|
|
@@ -1,6 +1,6 @@
|
|
|
<script lang="ts" setup>
|
|
|
import { saveTrainingInformation, updateTrainingInformation, queryEducationTrainingPlanCourseDetail } from '@/api/production-education-training-plan-dept';
|
|
|
- import { ref, reactive, onMounted, watch, shallowRef, computed } from 'vue';
|
|
|
+ import { ref, reactive, onMounted, watch, shallowRef, computed, nextTick } from 'vue';
|
|
|
import { UploadFilled, Plus, Delete, Download, ZoomIn } from '@element-plus/icons-vue';
|
|
|
import { TRAINING_FORM_RULES } from '../configs/form';
|
|
|
import { queryUserGroupPage } from '@/api/system/person-group';
|
|
|
@@ -10,9 +10,10 @@
|
|
|
// @ts-ignore: missing type declarations for CSS side-effect import
|
|
|
import '@wangeditor/editor/dist/css/style.css';
|
|
|
import { ElMessage, UploadRawFile } from 'element-plus';
|
|
|
+ import { unformatAttachment, formatAttachmentList } from '@/components/UploadFiles/utils';
|
|
|
+ import { uploadFileApi, UPLOAD_BIZ_TYPE } from '@/api/minio';
|
|
|
|
|
|
import { debounce } from 'lodash-es';
|
|
|
-
|
|
|
const props = defineProps({
|
|
|
state: {
|
|
|
type: String,
|
|
|
@@ -27,14 +28,15 @@
|
|
|
default: null,
|
|
|
},
|
|
|
});
|
|
|
- const isViewMode = ref(props.state === 'view');
|
|
|
- const isEditMode = ref(props.state === 'edit');
|
|
|
- const isCreateMode = ref(props.state === 'add');
|
|
|
+
|
|
|
+ const isViewMode = computed(() => props.state === 'view');
|
|
|
+ const isEditMode = computed(() => props.state === 'edit');
|
|
|
+ const isCreateMode = computed(() => props.state === 'add');
|
|
|
|
|
|
const emit = defineEmits(['update:visible', 'refreshList', 'saveSuccess']);
|
|
|
const formRef = ref();
|
|
|
const rules = ref(TRAINING_FORM_RULES);
|
|
|
-
|
|
|
+
|
|
|
const form = reactive({
|
|
|
courseType: '',
|
|
|
courseName: '',
|
|
|
@@ -58,8 +60,35 @@
|
|
|
{ label: '特种作业培训考核', value: 3 },
|
|
|
{ label: '特种作业复训考核', value: 4 },
|
|
|
]);
|
|
|
+
|
|
|
+ // 上传文件
|
|
|
+ const formatAttachment = async (data: any) => {
|
|
|
+ if (!data) return data;
|
|
|
+ const uuid = Math.random().toString(36).substring(2, 9);
|
|
|
+ const timestamp = Date.now().toString();
|
|
|
+ const random = Math.random().toString(36).substring(2, 4);
|
|
|
+ const fileName = data.name;
|
|
|
+ const res = await uploadFileApi({
|
|
|
+ bizType: UPLOAD_BIZ_TYPE.ATTACHMENT,
|
|
|
+ fileName: `${uuid}-${timestamp}-${random}`,
|
|
|
+ file: data,
|
|
|
+ });
|
|
|
+ const fileType = data.fileType;
|
|
|
+ const fileSize = data.fileSize;
|
|
|
+ const fileId = data.fileId;
|
|
|
+ const fileUrl = res.url;
|
|
|
+ return {
|
|
|
+ fileName,
|
|
|
+ fileType,
|
|
|
+ fileSize,
|
|
|
+ fileUrl,
|
|
|
+ fileId,
|
|
|
+ };
|
|
|
+};
|
|
|
+const openState = ref(false)
|
|
|
// 打开抽屉时的事件
|
|
|
const openDrawerFn = async () => {
|
|
|
+ await nextTick();
|
|
|
if ((props.state === 'edit' || props.state === 'view') && props.currentId) {
|
|
|
// 编辑/查看模式,加载现有详情数据
|
|
|
// 这里可以调用接口获取当前培训课程的信息,并填充到 form 中
|
|
|
@@ -76,10 +105,16 @@
|
|
|
courseIntroduction: res.courseIntroduction,
|
|
|
isSign: res.isSign,
|
|
|
});
|
|
|
- //
|
|
|
form.groupOfParticipants = res.groupOfParticipants ? res.groupOfParticipants.split(',').map(Number) : [];
|
|
|
- // form.courseImg = res.courseImg ? [JSON.parse(res.courseImg)] : [];
|
|
|
- // fileList.value = JSON.parse(res.courseContent) || [];
|
|
|
+ // 编辑和查看时 没有回显
|
|
|
+ if(res.courseImg){
|
|
|
+ form.courseImg = [JSON.parse(res.courseImg)]
|
|
|
+ }
|
|
|
+ if(res.courseContent){
|
|
|
+ // handleFileExceed(JSON.parse(res.courseContent))
|
|
|
+ // fileList.value = JSON.parse(res.courseContent) || [];
|
|
|
+ form.courseContent = res.courseContent
|
|
|
+ }
|
|
|
});
|
|
|
} else if (props.state === 'add') {
|
|
|
// 新增模式,重置表单
|
|
|
@@ -98,58 +133,13 @@
|
|
|
isSign: 0,
|
|
|
courseImg: [] as FileItem[],
|
|
|
});
|
|
|
+ courseContentUpload.value?.clearFiles();
|
|
|
+ courseImgRef.value?.clearFiles();
|
|
|
}
|
|
|
};
|
|
|
- const handleValidate = async () => {
|
|
|
- if (!formRef.value) return;
|
|
|
- try {
|
|
|
- await formRef.value.validate();
|
|
|
- return true;
|
|
|
- } catch {
|
|
|
- return false;
|
|
|
- }
|
|
|
- };
|
|
|
- const handleSave = debounce(async () => {
|
|
|
- const res = await handleValidate();
|
|
|
- if (!res) return;
|
|
|
- try {
|
|
|
- const basePayload = {
|
|
|
- ...form,
|
|
|
- petpiId: props.currentId,
|
|
|
- courseImg: form.courseImg[0],
|
|
|
- };
|
|
|
- console.log('提交的表单数据:', basePayload);
|
|
|
+
|
|
|
|
|
|
- if (isCreateMode.value) {
|
|
|
- // 新增,创建接口
|
|
|
- await saveTrainingInformation(basePayload);
|
|
|
- ElMessage.success('创建成功');
|
|
|
|
|
|
- } else if (isEditMode.value && props.currentId) {
|
|
|
- // 编辑,更新接口
|
|
|
- await updateTrainingInformation({
|
|
|
- id: props.currentId,
|
|
|
- ...basePayload,
|
|
|
- });
|
|
|
- ElMessage.success('保存成功');
|
|
|
-
|
|
|
- }
|
|
|
- emit('saveSuccess');
|
|
|
- } catch (e) {
|
|
|
- ElMessage.error('保存失败,请重试');
|
|
|
- }
|
|
|
- emit('update:visible', false);
|
|
|
- }, 1000);
|
|
|
- // const handleSave = () => {
|
|
|
-
|
|
|
- // // 简单验证,可以根据需要添加更多验证逻辑
|
|
|
- // if (!form.courseName || !form.courseType) {
|
|
|
- // ElMessage.error('请填写完整信息');
|
|
|
- // return;
|
|
|
- // }
|
|
|
- // emit('refreshList', { ...form }); // 传递表单数据,可以根据实际需求调整
|
|
|
- // emit('update:visible', false);
|
|
|
- // };
|
|
|
// 富文本编辑器
|
|
|
const editorRef = shallowRef();
|
|
|
const editorConfig = computed(() => ({
|
|
|
@@ -157,46 +147,36 @@
|
|
|
MENU_CONF: {},
|
|
|
}));
|
|
|
|
|
|
- const beforeUpload = (file) => {
|
|
|
- const isAllowedType = [
|
|
|
- 'application/rar',
|
|
|
- 'application/zip',
|
|
|
- 'application/msword',
|
|
|
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
|
- 'application/pdf',
|
|
|
- 'video/mp4',
|
|
|
- ].includes(file.type);
|
|
|
- const isLt20M = file.size / 1024 / 1024 < 20;
|
|
|
-
|
|
|
- if (!isAllowedType) {
|
|
|
- ElMessage.error('上传文件格式不正确!');
|
|
|
- }
|
|
|
- if (!isLt20M) {
|
|
|
- ElMessage.error('上传文件大小不能超过20MB!');
|
|
|
- }
|
|
|
- return isAllowedType && isLt20M;
|
|
|
+ const handleEditorChange = () => {
|
|
|
+ // 编辑器内容变化时的处理
|
|
|
};
|
|
|
-
|
|
|
const handleEditorCreated = (editor: any) => {
|
|
|
editorRef.value = editor;
|
|
|
};
|
|
|
|
|
|
- const handleEditorChange = () => {
|
|
|
- // 编辑器内容变化时的处理
|
|
|
- };
|
|
|
- const handleImageUploadChange = (response: any, file: any) => {
|
|
|
- form.courseImg = [response];
|
|
|
+ // 上传图片
|
|
|
+ const handleImageUploadChange = async (uploadFile: any, uploadFiles: any) => {
|
|
|
+ form.courseImg = uploadFiles;
|
|
|
+ if(uploadFile.raw){
|
|
|
+ let res = await formatAttachment(uploadFile.raw)
|
|
|
+ console.log(res, '图片上传')
|
|
|
+ if(res){
|
|
|
+ ElMessage.success('上传成功')
|
|
|
+ }
|
|
|
+ }
|
|
|
};
|
|
|
-
|
|
|
+ // 替换图片
|
|
|
const courseImgRef = ref();
|
|
|
- const handleImageExceed = (files: any[]) => {
|
|
|
- console.log(files);
|
|
|
- courseImgRef.value!.clearFiles(); // 清空文件列表
|
|
|
+ const handleImageExceed = (files) => {
|
|
|
+ courseImgRef.value!.clearFiles();
|
|
|
const file = files[0] as UploadRawFile;
|
|
|
- courseImgRef.value!.handleStart(file); // 手动触发上传
|
|
|
- form.courseImg = files[0];
|
|
|
+ console.log(file)
|
|
|
+ if (!validateImage(file)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ courseImgRef.value!.handleStart(file);
|
|
|
};
|
|
|
-
|
|
|
+// 图片预览
|
|
|
const dialogVisible = ref(false);
|
|
|
const dialogImageUrl = ref('');
|
|
|
const handlePictureCardPreview = (file: any) => {
|
|
|
@@ -204,11 +184,7 @@
|
|
|
dialogVisible.value = true;
|
|
|
};
|
|
|
|
|
|
- const handleImageRemove = (file: any) => {
|
|
|
- console.log('图片被移除:', file, fileList.value);
|
|
|
- // console.log('图片被移除:', file, fileList.value);
|
|
|
- // form.courseImg = fileList.value.filter((item) => item.uid !== file.uid);
|
|
|
- };
|
|
|
+// 图片格式校验
|
|
|
const validateImage = (file) => {
|
|
|
const validMIME = [
|
|
|
'image/jpeg',
|
|
|
@@ -243,6 +219,29 @@
|
|
|
return true; // 验证通过
|
|
|
};
|
|
|
|
|
|
+ // 验证文件类型
|
|
|
+ const allowedTypes = [
|
|
|
+ 'application/rar',
|
|
|
+ 'application/zip',
|
|
|
+ 'application/msword',
|
|
|
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
|
+ 'application/pdf',
|
|
|
+ 'video/mp4',
|
|
|
+ ];
|
|
|
+
|
|
|
+ const beforeUpload = (file) => {
|
|
|
+ const isAllowedType = allowedTypes.includes(file.type);
|
|
|
+ const isLt20M = file.size / 1024 / 1024 < 20;
|
|
|
+
|
|
|
+ if (!isAllowedType) {
|
|
|
+ ElMessage.error('上传文件格式不正确!');
|
|
|
+ }
|
|
|
+ if (!isLt20M) {
|
|
|
+ ElMessage.error('上传文件大小不能超过20MB!');
|
|
|
+ }
|
|
|
+
|
|
|
+ return isAllowedType && isLt20M;
|
|
|
+ };
|
|
|
// 文件选择更新
|
|
|
const courseContentUpload = ref();
|
|
|
const handleFileExceed = (files) => {
|
|
|
@@ -253,17 +252,11 @@
|
|
|
}
|
|
|
courseContentUpload.value!.handleStart(file); // 手动触发上传
|
|
|
};
|
|
|
+
|
|
|
+
|
|
|
// 课程内容文件上传
|
|
|
- const handleFileChange = (file, fileList) => {
|
|
|
- // 1. 验证文件类型和大小
|
|
|
- const allowedTypes = [
|
|
|
- 'application/rar',
|
|
|
- 'application/zip',
|
|
|
- 'application/msword',
|
|
|
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
|
- 'application/pdf',
|
|
|
- 'video/mp4',
|
|
|
- ];
|
|
|
+ const handleFileChange = async (file, fileList) => {
|
|
|
+
|
|
|
|
|
|
if (!allowedTypes.includes(file.raw.type)) {
|
|
|
ElMessage.error('不支持的文件格式');
|
|
|
@@ -274,24 +267,60 @@
|
|
|
ElMessage.error('文件大小不能超过20MB');
|
|
|
return;
|
|
|
}
|
|
|
- console.log(file, fileList);
|
|
|
- // 2. 关键修改:强制覆盖旧文件
|
|
|
- fileList.value = [file.raw]; // 直接替换为新文件
|
|
|
+
|
|
|
+ if(file.raw){
|
|
|
+ let res = await formatAttachment(file.raw)
|
|
|
+ console.log(res, '文件上传')
|
|
|
+ if(res){
|
|
|
+ ElMessage.success('上传成功')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 直接替换为新文件
|
|
|
+ fileList.value = [file.raw];
|
|
|
form.courseContent = file; // 更新表单数据
|
|
|
};
|
|
|
|
|
|
- const handleUploadSignsUploadSuccess = async (item: any, fileList) => {
|
|
|
- // const attachment = await formatAttachmentList(fileList);
|
|
|
- // item.attachment = attachment;
|
|
|
- // form.courseImg = [...signRecords.value.level1, ...signRecords.value.level2, ...signRecords.value.level3];
|
|
|
+ // 提交保存/编辑
|
|
|
+ const handleValidate = async () => {
|
|
|
+ if (!formRef.value) return;
|
|
|
+ try {
|
|
|
+ await formRef.value.validate();
|
|
|
+ return true;
|
|
|
+ } catch {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
};
|
|
|
+ const handleSave = debounce(async () => {
|
|
|
+ const res = await handleValidate();
|
|
|
+ if (!res) return;
|
|
|
+ try {
|
|
|
+ const basePayload = {
|
|
|
+ ...form,
|
|
|
+ petpiId: props.currentId,
|
|
|
+ courseImg: form.courseImg[0],
|
|
|
+ };
|
|
|
+ console.log('提交的表单数据:', basePayload);
|
|
|
+
|
|
|
+ if (isCreateMode.value) {
|
|
|
+ // 新增,创建接口
|
|
|
+ await saveTrainingInformation(basePayload);
|
|
|
+ ElMessage.success('创建成功');
|
|
|
|
|
|
- // 文件上传
|
|
|
- const handleUploadSuccess = (files: FileItem[]) => {
|
|
|
- console.log('上传成功的文件列表:', files);
|
|
|
- form.courseImg = files;
|
|
|
- };
|
|
|
-
|
|
|
+ } else if (isEditMode.value && props.currentId) {
|
|
|
+ // 编辑,更新接口
|
|
|
+ await updateTrainingInformation({
|
|
|
+ id: props.currentId,
|
|
|
+ ...basePayload,
|
|
|
+ });
|
|
|
+ ElMessage.success('保存成功');
|
|
|
+
|
|
|
+ }
|
|
|
+ emit('saveSuccess');
|
|
|
+ } catch (e) {
|
|
|
+ ElMessage.error('保存失败,请重试');
|
|
|
+ emit('update:visible', false);
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
|
|
|
const groupList = ref<any>([]);
|
|
|
// 获取级联部门分组数据
|
|
|
@@ -381,7 +410,8 @@
|
|
|
<Editor
|
|
|
style="height: 400px; overflow-y: auto"
|
|
|
v-model="form.courseIntroduction"
|
|
|
- mode="default"
|
|
|
+ mode="disabled"
|
|
|
+ :disabled="isViewMode"
|
|
|
:defaultConfig="editorConfig"
|
|
|
@on-created="handleEditorCreated"
|
|
|
@on-change="handleEditorChange"
|
|
|
@@ -394,6 +424,7 @@
|
|
|
action=""
|
|
|
ref="courseContentUpload"
|
|
|
:auto-upload="false"
|
|
|
+ :disabled="isViewMode"
|
|
|
:on-change="handleFileChange"
|
|
|
accept=".rar, .zip, .doc, .docx, .pdf, .mp4"
|
|
|
:file-list="fileList"
|
|
|
@@ -439,7 +470,7 @@
|
|
|
</el-icon>
|
|
|
|
|
|
<template #tip>
|
|
|
- <div class="el-upload__tip"> 支持格式:.jpg .png .jpeg,单个文件不能超过300k,设置一个默认图片。 </div>
|
|
|
+ <div class="el-upload__tip"> 支持格式:.jpg .png .jpeg,单个文件不能超过300k,设置一个默认图片。</div>
|
|
|
</template>
|
|
|
<template #file="{ file }">
|
|
|
<div>
|
|
|
@@ -453,7 +484,7 @@
|
|
|
</template>
|
|
|
</el-upload>
|
|
|
<el-dialog v-model="dialogVisible">
|
|
|
- <img w-full :src="dialogImageUrl" alt="Preview Image" />
|
|
|
+ <img w-full :src="dialogImageUrl" alt="Preview Image" style="width: 100%;" />
|
|
|
</el-dialog>
|
|
|
</el-form-item>
|
|
|
</el-form>
|