Files
yunzerwebsiteallinone/backend/src/views/moduleshop/components/createModules.vue
T
2026-06-24 10:04:03 +08:00

313 lines
8.0 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-dialog
v-model="dialogVisible"
title="创建模块"
width="600px"
:close-on-click-modal="false"
@close="handleClose"
>
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
>
<el-form-item label="模块名称" prop="name">
<el-input
v-model="formData.name"
placeholder="请输入模块名称"
clearable
/>
</el-form-item>
<el-form-item label="模块代码" prop="code">
<el-input
v-model="formData.code"
placeholder="请输入模块代码"
clearable
/>
</el-form-item>
<el-form-item label="模块图标" prop="icon">
<el-input
v-model="formData.icon"
placeholder="请输入图标类名,如: fa-solid fa-home"
clearable
>
<template #prefix>
<el-icon v-if="formData.icon" :class="formData.icon" />
</template>
</el-input>
</el-form-item>
<el-form-item label="模块描述" prop="description">
<el-input
v-model="formData.description"
type="textarea"
:rows="3"
placeholder="请输入模块描述"
/>
</el-form-item>
<el-form-item label="模块类型" prop="type">
<el-select
v-model="formData.type"
placeholder="请选择模块类型"
>
<el-option label="前端模块" :value="1" />
<el-option label="后端模块" :value="2" />
<el-option label="全栈模块" :value="3" />
</el-select>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number
v-model="formData.sort"
:min="0"
:max="999"
controls-position="right"
placeholder="请输入排序"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio :value="1">启用</el-radio>
<el-radio :value="0">禁用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="模块包" prop="packageFile">
<el-upload
ref="uploadRef"
class="upload-demo"
drag
:auto-upload="false"
:limit="1"
:on-change="handleFileChange"
:before-upload="beforeUpload"
:on-exceed="handleExceed"
accept=".zip"
>
<el-icon class="el-icon--upload"><UploadFilled /></el-icon>
<div class="el-upload__text">
拖拽文件到此处或<em>点击上传</em>
</div>
<template #tip>
<div class="el-upload__tip">
只能上传 zip 格式的压缩包,且不超过 50MB
</div>
</template>
</el-upload>
<div v-if="formData.packageFile" class="file-info">
<el-icon><Document /></el-icon>
<span>{{ formData.packageFile.name }}</span>
<el-button
type="danger"
link
size="small"
@click="handleRemoveFile"
>
删除
</el-button>
</div>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">
确定
</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from "vue";
import { ElMessage } from "element-plus";
import { UploadFilled, Document } from "@element-plus/icons-vue";
import type { FormInstance, FormRules, UploadFile, UploadUserOptions } from "element-plus";
interface Props {
modelValue: boolean;
}
interface Emits {
(e: "update:modelValue", value: boolean): void;
(e: "success"): void;
}
const props = defineProps<Props>();
const emit = defineEmits<Emits>();
const dialogVisible = ref(false);
const formRef = ref<FormInstance>();
const uploadRef = ref();
const submitLoading = ref(false);
const formData = reactive({
name: "",
code: "",
icon: "",
description: "",
type: 3,
sort: 0,
status: 1,
packageFile: null as File | null
});
const formRules: FormRules = {
name: [
{ required: true, message: "请输入模块名称", trigger: "blur" }
],
code: [
{ required: true, message: "请输入模块代码", trigger: "blur" },
{ pattern: /^[a-zA-Z][a-zA-Z0-9]*$/, message: "代码必须以字母开头,只能包含字母和数字", trigger: "blur" }
],
type: [
{ required: true, message: "请选择模块类型", trigger: "change" }
],
status: [
{ required: true, message: "请选择状态", trigger: "change" }
]
};
watch(
() => props.modelValue,
(newVal) => {
dialogVisible.value = newVal;
},
{ immediate: true }
);
watch(dialogVisible, (newVal) => {
emit("update:modelValue", newVal);
});
const handleFileChange = (file: UploadFile) => {
formData.packageFile = file.raw;
};
const beforeUpload = (file: File) => {
const isZip = file.type === "application/zip" || file.name.endsWith(".zip");
const isLt50M = file.size / 1024 / 1024 < 50 * 1024;
if (!isZip) {
ElMessage.error("只能上传 zip 格式的文件!");
return false;
}
if (!isLt50M) {
ElMessage.error("文件大小不能超过 50MB!");
return false;
}
return true;
};
const handleExceed = () => {
ElMessage.warning("最多只能上传 1 个文件");
};
const handleRemoveFile = () => {
formData.packageFile = null;
if (uploadRef.value) {
uploadRef.value.clearFiles();
}
};
const handleSubmit = async () => {
if (!formRef.value) return;
await formRef.value.validate(async (valid) => {
if (valid) {
if (!formData.packageFile) {
ElMessage.warning("请上传模块包");
return;
}
submitLoading.value = true;
try {
// 创建 FormData 对象
const formDataObj = new FormData();
formDataObj.append("name", formData.name);
formDataObj.append("code", formData.code);
formDataObj.append("icon", formData.icon);
formDataObj.append("description", formData.description);
formDataObj.append("type", formData.type.toString());
formDataObj.append("sort", formData.sort.toString());
formDataObj.append("status", formData.status.toString());
formDataObj.append("package", formData.packageFile);
// TODO: 调用上传接口
// const res = await createModule(formDataObj);
ElMessage.success("创建成功");
handleClose();
emit("success");
} catch (error) {
console.error("创建失败:", error);
ElMessage.error("创建失败");
} finally {
submitLoading.value = false;
}
}
});
};
const handleClose = () => {
formRef.value?.resetFields();
formData.packageFile = null;
dialogVisible.value = false;
};
// 暴露重置方法
defineExpose({
reset: handleClose
});
</script>
<style scoped lang="less">
.upload-demo {
width: 100%;
:deep(.el-upload) {
width: 100%;
}
:deep(.el-upload-dragger) {
width: 100%;
height: 180px;
}
}
.file-info {
margin-top: 12px;
padding: 8px 12px;
background: var(--el-fill-color-light);
border-radius: 4px;
display: flex;
align-items: center;
gap: 8px;
.el-icon {
font-size: 20px;
color: var(--el-color-primary);
}
span {
flex: 1;
font-size: 14px;
color: var(--el-text-color-regular);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.el-upload__tip {
font-size: 12px;
color: var(--el-text-color-placeholder);
margin-top: 8px;
}
</style>