Files
yunzerwebsiteallinone/backend/src/views/apps/cms/solution/index/components/edit.vue
T

349 lines
7.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<el-drawer
v-model="visible"
:title="title"
size="65%"
class="cms-solution-drawer"
destroy-on-close
@close="handleClose"
>
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
class="solution-form"
>
<el-form-item label="方案名称" prop="title">
<el-input v-model="formData.title" placeholder="请输入解决方案名称" />
</el-form-item>
<el-form-item label="方案描述" prop="desc">
<el-input
v-model="formData.desc"
type="textarea"
:rows="4"
placeholder="请输入解决方案描述"
/>
</el-form-item>
<el-form-item label="方案内容" prop="content" class="content-form-item">
<div class="editor-container">
<UmoEditor v-model="formData.content" style="height: 450px;" />
</div>
</el-form-item>
<el-form-item label="方案图片" prop="thumb">
<div class="flex-direction">
<el-upload
class="image-uploader"
:action="uploadUrl"
:headers="uploadHeaders"
:show-file-list="false"
:on-success="handleImageSuccess"
:on-error="handleImageError"
:before-upload="beforeImageUpload"
accept="image/*"
>
<img
v-if="formData.thumb"
:src="getImageUrl(formData.thumb)"
class="image-preview"
/>
<div v-else class="upload-placeholder">
<el-icon class="image-uploader-icon"><Plus /></el-icon>
<div class="el-upload__text">点击上传方案图片</div>
</div>
</el-upload>
<div
style="
margin-top: 8px;
font-size: 12px;
color: var(--el-text-color-secondary);
"
>
建议尺寸:200x200,支持 jpg、png、gif 格式,大小不超过 2MB
</div>
</div>
<el-button
v-if="formData.thumb"
size="small"
type="danger"
text
@click="handleRemoveImage"
style="margin-top: 8px"
>
删除图片
</el-button>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="formData.sort" :min="0" :max="999" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button
type="primary"
@click="handleSubmit"
:loading="submitLoading"
>
确定
</el-button>
</span>
</template>
</el-drawer>
</template>
<script setup>
import { ref, reactive, watch } from "vue";
import { ElMessage } from "element-plus";
import { Plus } from "@element-plus/icons-vue";
import { addService, updateService } from "@/api/services";
// @ts-ignore
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
const props = defineProps({
modelValue: {
type: Boolean,
default: false,
},
title: {
type: String,
default: "添加解决方案",
},
isEdit: {
type: Boolean,
default: false,
},
rowData: {
type: Object,
default: () => ({}),
},
});
const emit = defineEmits(["update:modelValue", "success"]);
const visible = ref(false);
const submitLoading = ref(false);
const formRef = ref(null);
// 上传配置
const uploadUrl = ref(API_BASE_URL + "/admin/uploadfiles");
const uploadHeaders = ref({
Authorization: "Bearer " + (localStorage.getItem("token") || ""),
});
// 图片上传前校验
const beforeImageUpload = (file) => {
const isImage = file.type.startsWith("image/");
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isImage) {
ElMessage.error("请上传图片文件!");
return false;
}
if (!isLt2M) {
ElMessage.error("图片大小不能超过 2MB!");
return false;
}
return true;
};
// 图片上传成功
const handleImageSuccess = (response) => {
if (response.code === 200 || response.code === 201) {
formData.thumb = response.data.url || response.data.path;
ElMessage.success(
response.code === 201 ? "文件已存在,直接使用" : "图片上传成功",
);
} else {
ElMessage.error(response.msg || "图片上传失败");
}
};
// 图片上传失败
const handleImageError = () => {
ElMessage.error("图片上传失败,请重试");
};
// 删除图片
const handleRemoveImage = () => {
formData.thumb = "";
ElMessage.success("图片已删除");
};
// 获取图片完整URL(用于预览)
const getImageUrl = (imagePath) => {
if (!imagePath) return "";
if (imagePath.startsWith("http")) return imagePath;
return API_BASE_URL + imagePath;
};
const formData = reactive({
title: "",
desc: "",
content: "",
thumb: "",
url: "",
sort: 0,
status: 1,
});
const formRules = {
title: [
{ required: true, message: "请输入解决方案名称", trigger: "blur" },
{ max: 100, message: "长度不超过100个字符", trigger: "blur" },
],
desc: [
{ required: true, message: "请输入解决方案描述", trigger: "blur" },
{ max: 200, message: "描述长度不超过200个字符", trigger: "blur" },
],
};
// 监听 modelValue 变化
watch(
() => props.modelValue,
(val) => {
visible.value = val;
if (val) {
resetForm();
if (props.isEdit && props.rowData) {
Object.assign(formData, props.rowData);
}
}
},
);
// 监听 visible 变化
watch(visible, (val) => {
emit("update:modelValue", val);
});
// 重置表单
const resetForm = () => {
formData.title = "";
formData.desc = "";
formData.content = "";
formData.thumb = "";
formData.url = "";
formData.sort = 0;
formData.status = 1;
};
// 关闭
const handleClose = () => {
visible.value = false;
};
// 提交
const handleSubmit = async () => {
if (!formRef.value) return;
await formRef.value.validate(async (valid) => {
if (valid) {
submitLoading.value = true;
try {
let res;
if (props.isEdit) {
res = await updateService(props.rowData.id, formData);
} else {
res = await addService(formData);
}
if (res.code === 200) {
ElMessage.success(props.isEdit ? "更新成功" : "添加成功");
handleClose();
emit("success");
} else {
ElMessage.error(res.msg || "操作失败");
}
} catch (error) {
console.error("提交失败:", error);
ElMessage.error("操作失败");
} finally {
submitLoading.value = false;
}
}
});
};
</script>
<style scoped>
:deep(.el-drawer__body) {
overflow-x: hidden;
padding: 20px;
}
.solution-form {
width: 100%;
}
:deep(.el-form-item__content) {
min-width: 0;
max-width: 100%;
}
.editor-container {
width: 100%;
min-width: 0;
max-width: 100%;
border: 1px solid var(--el-border-color, #dcdfe6);
border-radius: 4px;
overflow: hidden;
box-sizing: border-box;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
/* 图片上传样式 */
.image-uploader {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
width: 120px;
height: 120px;
}
.image-uploader:hover {
border-color: var(--el-color-primary);
}
.upload-placeholder {
width: 120px;
height: 120px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: var(--el-text-color-secondary);
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
margin-bottom: 8px;
}
.el-upload__text {
font-size: 12px;
}
.image-preview {
width: 120px;
height: 120px;
object-fit: contain;
display: block;
}
.flex-direction {
display: flex;
flex-direction: column;
align-items: flex-start;
}
</style>