| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- <template>
- <main class="safety-platform-container__main">
- <BasicForm
- ref="basicFormRef"
- :formData="ruleFormData"
- :formRules="isViewMode ? undefined : formRules"
- :formConfig="computedFormConfig"
- >
- <template #categoryName>
- <el-select v-model="ruleFormData.categoryName" placeholder="请选择分类名称" :disabled="isViewMode || isFeedbackMode">
- <el-option v-for="item in classifyNameOptions" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </template>
- <template #responsibleDeptId>
- <el-cascader
- v-model="ruleFormData.responsibleDeptId"
- :options="deptTree"
- :props="responsibleDeptCascaderProp"
- clearable
- :show-all-levels="false"
- placeholder="请选择责任部门"
- style="width: 100%"
- :disabled="isViewMode || isFeedbackMode"
- />
- </template>
- <template #cooperateDeptIds>
- <el-cascader
- v-model="ruleFormData.cooperateDeptIds"
- :options="deptTree"
- :props="cooperateDeptCascaderProp"
- clearable
- collapse-tags
- :show-all-levels="false"
- :max-collapse-tags="3"
- popper-class="cascader-popper--custom"
- placeholder="请选择配合部门"
- style="width: 100%"
- :disabled="isViewMode || isFeedbackMode"
- />
- </template>
- <template #responsiblePersonId>
- <el-select
- v-model="ruleFormData.responsiblePersonId"
- placeholder="请选择责任人"
- :disabled="isViewMode || isFeedbackMode"
- filterable
- >
- <el-option
- v-for="user in responsiblePersonOptions"
- :key="user.value"
- :label="user.label"
- :value="user.value"
- />
- </el-select>
- </template>
- <template #fileUrl>
- <UploadFiles
- v-if="isFeedbackMode"
- label="上传文件"
- :maxCount="10"
- :file-list="ruleFormData.fileUrlList"
- :allow-all-file-types="true"
- @uploadSuccess="(list: FileItem[]) => handleUploadSuccess(list)"
- @preview="handlePreview"
- />
- <div class="file-list" v-else>
- <div class="file-item" v-for="file in ruleFormData.fileUrlList" :key="file.fileId">
- <span class="file-item--name">{{ file.fileName }}</span>
- <div class="file-item--footer">
- <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
- >预览</el-button
- >
- <!-- <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
- >下载</el-button
- > -->
- </div>
- </div>
- </div>
- </template>
- </BasicForm>
- <PreviewOnline ref="previewOnlineRef" />
- </main>
- <footer class="safety-platform-container__footer">
- <el-button @click="router.back()">返回</el-button>
- <el-button v-if="!isViewMode && !isFeedbackMode" type="primary" @click="handleSubmit">
- {{ isCreateMode ? '提交' : '保存' }}
- </el-button>
- <el-button v-if="!isViewMode && isFeedbackMode" type="primary" @click="handleFeedbackSubmit">
- 反馈
- </el-button>
- </footer>
- </template>
- <script setup lang="ts">
- import { computed, onMounted, ref } from 'vue';
- import { useRoute, useRouter } from 'vue-router';
- import { ElMessage } from 'element-plus';
- import BasicForm from '@/components/BasicForm.vue';
- // import UploadFiles from '@/components/UploadFiles/UploadFiles.vue';
- // import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
- import '@wangeditor/editor/dist/css/style.css';
- import { useFormConfigHook } from '@/hooks/useFormConfigHook';
- import { ACADEMY_FILE_FORM_CONFIG, ACADEMY_FILE_FORM_DATA, ACADEMY_FILE_FORM_RULES } from '../configs/form';
- import {
- querySafetyCultureActivityDetail,
- addSafetyCultureActivityManagement,
- updateSafetyCultureActivity,
- getAllDepartments,
- feedbackSafetyCultureActivityManagement
- } from '@/api/safety-culture';
- import { queryAvailableUserList } from '@/api/system/person-group';
- import type { addSafetyCultureFilePageQuery } from '@/api/safety-culture';
- import type { DeptTree } from '@/types/dept/type';
- import type { FileItem } from '@/components/UploadFiles/types';
- import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
- import UploadFiles from '@/components/UploadFiles/UploadFiles.vue';
- import { formatAttachmentList } from '@/components/UploadFiles/utils';
- const router = useRouter();
- const route = useRoute();
- const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
- const operate = computed(() => (route.query.operate as string) || 'safety-culture-material-create');
- const currentId = computed(() => Number(route.query.id));
- const isCreateMode = computed(() => operate.value === 'safety-culture-material-create');
- const isEditMode = computed(() => operate.value === 'safety-culture-material-edit');
- const isViewMode = computed(() => operate.value === 'safety-culture-material-view');
- const isFeedbackMode = computed(() => operate.value === 'safety-culture-material-feedback');
- const { ruleFormData, formRules, ruleFormConfig, cloneRuleFormData } = useFormConfigHook(
- ACADEMY_FILE_FORM_CONFIG,
- ACADEMY_FILE_FORM_DATA,
- ACADEMY_FILE_FORM_RULES,
- );
- const viewFormConfig = ref(
- ACADEMY_FILE_FORM_CONFIG.map((item) => ({
- ...item,
- componentProps: {
- ...item.componentProps,
- disabled: true,
- },
- })),
- );
- const computedFormConfig = computed(() => {
- if (isViewMode.value || isFeedbackMode.value) {
- return viewFormConfig.value;
- }
- return ruleFormConfig.value;
- });
- const basicFormRef = ref<InstanceType<typeof BasicForm>>();
- const responsibleDeptCascaderProp = {
- expandTrigger: 'hover' as const,
- checkStrictly: true,
- emitPath: false,
- value: 'id',
- label: 'deptName',
- };
- const cooperateDeptCascaderProp = {
- multiple: true,
- expandTrigger: 'hover' as const,
- checkStrictly: true,
- emitPath: false,
- value: 'id',
- label: 'deptName',
- };
- const deptTree = ref<DeptTree[]>([]);
- const loadDeptTreeData = async () => {
- const result = await getAllDepartments();
- deptTree.value = result?.[0]?.children || [];
- };
- const classifyNameOptions = ref<Array<{ label: string; value: string }>>([
- { label: '安全综合工作', value: '安全综合工作' },
- { label: '生产安全工作', value: '生产安全工作' },
- ]);
- const responsiblePersonOptions = ref<Array<{ label: string; value: number }>>([]);
- const loadResponsiblePersonOptions = async () => {
- const result = await queryAvailableUserList({
- pageNumber: 1,
- pageSize: 1000,
- queryParam: {},
- });
- responsiblePersonOptions.value = (result.records || []).map((item) => ({
- label: item.realname || item.staffNo,
- value: item.id,
- }));
- };
- const normalizeToNumberArray = (value: unknown): number[] => {
- if (Array.isArray(value)) {
- return value.map((item) => Number(item)).filter((item) => Number.isFinite(item));
- }
- if (value == null || value === '') {
- return [];
- }
- if (typeof value === 'string' && value.includes(',')) {
- return value
- .split(',')
- .map((item) => Number(item.trim()))
- .filter((item) => Number.isFinite(item));
- }
- const numericValue = Number(value);
- return Number.isFinite(numericValue) ? [numericValue] : [];
- };
- const normalizeCooperateDeptIds = (value: unknown): string => {
- return normalizeToNumberArray(value)
- .map((item) => String(item))
- .join(',');
- };
- const buildPayload = (): addSafetyCultureFilePageQuery => {
- const responsibleDeptId = Number(ruleFormData.responsibleDeptId);
- const responsiblePersonId = Number(ruleFormData.responsiblePersonId);
- return {
- id: currentId.value,
- planName: String(ruleFormData.planName || ''),
- actionContent: String(ruleFormData.actionContent || ''),
- categoryName: String(ruleFormData.categoryName || ''),
- responsibleDeptId,
- responsiblePersonId,
- cooperateDeptIds: normalizeCooperateDeptIds(ruleFormData.cooperateDeptIds),
- attachmentUrl: JSON.stringify(ruleFormData.fileUrlList || []),
- };
- };
- const handleValidate = async () => {
- if (!basicFormRef.value) return;
- const res = await basicFormRef.value.validateForm();
- return res;
- };
- const getDetail = async () => {
- if (!currentId.value) return;
- try {
- const res = await querySafetyCultureActivityDetail(currentId.value);
- if (res) {
- ruleFormData.planName = res.planName || '';
- ruleFormData.actionContent = res.actionContent || '';
- ruleFormData.categoryName = res.categoryName != null ? String(res.categoryName) : '';
- ruleFormData.responsibleDeptId = res.responsibleDeptId != null ? Number(res.responsibleDeptId) : undefined;
- ruleFormData.responsiblePersonId =
- res.responsiblePersonId != null ? Number(res.responsiblePersonId) : undefined;
- ruleFormData.cooperateDeptIds = normalizeToNumberArray(res.cooperateDeptIds);
- ruleFormData.responsibleDeptName = res.responsibleDeptName || '';
- ruleFormData.responsiblePersonName = res.responsiblePersonName || '';
- ruleFormData.fileUrlList = JSON.parse(res.attachmentUrl || '[]') || [];
- }
- cloneRuleFormData();
- } catch (e) {
- console.error('获取安全文化活动详情失败:', e);
- ElMessage.error('获取详情失败');
- }
- };
- const handleSubmit = async () => {
- const res = await handleValidate();
- if (!res) return;
- console.log('ruleFormData', ruleFormData);
- try {
- const payload = buildPayload();
- if (isCreateMode.value) {
- await addSafetyCultureActivityManagement(payload);
- ElMessage.success('创建成功');
- } else if (isEditMode.value && currentId.value) {
- await updateSafetyCultureActivity({
- id: currentId.value,
- ...payload,
- });
- ElMessage.success('保存成功');
- }
- router.back();
- } catch (e) {
- console.error('保存安全文化活动失败:', e);
- ElMessage.error('保存失败,请重试');
- }
- };
- const handlePreview = (url: string) => {
- if (url) {
- // 根据文件扩展名判断文件类型
- const extension = url.split('.').pop()?.toLowerCase() || '';
- let fileType: 'pdf' | 'word' | 'excel' | 'ppt' = 'pdf';
- if (extension === 'doc' || extension === 'docx') {
- fileType = 'word';
- } else if (extension === 'xls' || extension === 'xlsx') {
- fileType = 'excel';
- } else if (extension === 'ppt' || extension === 'pptx') {
- fileType = 'ppt';
- }
- previewOnlineRef.value?.open(url, fileType);
- }
- };
- // 文件上传
- const handleUploadSuccess = async (files: FileItem[]) => {
- ruleFormData.fileUrlList = await formatAttachmentList(files);
- // 更新fileUrl字段以触发表单验证
- ruleFormData.fileUrl = JSON.stringify(ruleFormData.fileUrlList) || '';
- };
- const previewOnline = (url: string | undefined, type) => {
- if (url) {
- previewOnlineRef.value?.open(url, type);
- }
- };
- // 反馈
- const handleFeedbackSubmit = async () => {
- // 验证文件上传(必填)
- if (!ruleFormData.fileUrlList || ruleFormData.fileUrlList.length === 0) {
- ElMessage.warning('请上传文件');
- return;
- }
- try {
- const payload = buildPayload();
- await feedbackSafetyCultureActivityManagement(payload);
- ElMessage.success('反馈成功');
- cloneRuleFormData();
- router.back();
- } catch (e) {
- console.error('反馈安全文化活动失败:', e);
- ElMessage.error('反馈失败,请重试');
- }
- };
- onMounted(() => {
- cloneRuleFormData();
- loadDeptTreeData();
- loadResponsiblePersonOptions();
- // beforeRouteLeave();
- if (isEditMode.value || isViewMode.value || isFeedbackMode.value) {
- getDetail();
- }
- });
- </script>
- <style scoped lang="scss">
- @use '@/styles/page-details-layout.scss' as *;
- .editor-container {
- width: 100%;
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- overflow: hidden;
- }
- .content-display {
- min-height: 200px;
- padding: 12px;
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- background-color: #f5f7fa;
- }
- .file-display {
- .file-link {
- color: #409eff;
- text-decoration: none;
- &:hover {
- text-decoration: underline;
- }
- }
- }
- .no-file {
- color: rgba(0, 0, 0, 0.65);
- }
- .image-uploader {
- :deep(.el-upload--picture-card) {
- width: 80px !important;
- height: 80px !important;
- line-height: 80px;
- }
- :deep(.el-upload-list--picture-card .el-upload-list__item) {
- width: 80px !important;
- height: 80px !important;
- }
- }
- </style>
|