From 77a69ec7a3685dbb3fda4c47af95549824821bd5 Mon Sep 17 00:00:00 2001 From: bestlee Date: Fri, 28 Aug 2026 16:26:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=A1=E6=89=B9=E6=A8=A1=E6=9D=BF=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=8E=A5=E5=8F=A3=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/service/api/system.ts | 31 ++++- src/views/systemManage/template/index.vue | 148 ++++++++++++++-------- 2 files changed, 120 insertions(+), 59 deletions(-) diff --git a/src/service/api/system.ts b/src/service/api/system.ts index 7022ef8..2c454e7 100644 --- a/src/service/api/system.ts +++ b/src/service/api/system.ts @@ -23,6 +23,14 @@ export function editSystemConfigApi(id:number, data:{group_key:string, label:str data, }); } +// 批量修改ai配置项和变更编号规则 +export function updateConfigApi(data:{items:any[]}) { + return request({ + url: '/api/system-config/batch', + method: 'put', + data, + }); +} // 删除配置项 export function deleteSystemConfigApi(id:number) { return request({ @@ -45,12 +53,27 @@ export function peopleListApi() { method: 'get', }); } - -// 批量修改ai配置项和变更编号规则 -export function updateConfigApi(data:{items:any[]}) { +// 新增审批模板 +export function addTemplateApi(data:any) { return request({ - url: '/api/system-config/batch', + url: '/api/approval-templates', + method: 'post', + data, + }); +} +// 编辑审批模板 +export function editTemplateApi(id:number,data:any) { + return request({ + url: `/api/approval-templates/${id}`, method: 'put', data, }); } +// 删除审批模板 +export function deleteTemplateApi(id:number) { + return request({ + url: `/api/approval-templates/${id}`, + method: 'delete', + }); +} + diff --git a/src/views/systemManage/template/index.vue b/src/views/systemManage/template/index.vue index 9b2a39c..c8f6aac 100644 --- a/src/views/systemManage/template/index.vue +++ b/src/views/systemManage/template/index.vue @@ -5,7 +5,8 @@ import { Icon } from '@iconify/vue' import { useThemeStore } from '@/store/modules/theme'; import { NButton, NPopconfirm, NTag } from 'naive-ui'; import { tagTextColor, tagBgColor, tagBorderColor } from '@/utils/common'; -import { templateListApi, systemConfigApi, peopleListApi } from '@/service/api/system'; +import { templateListApi, systemConfigApi, peopleListApi, addTemplateApi, editTemplateApi, deleteTemplateApi } from '@/service/api/system'; +import { json } from 'node:stream/consumers'; const appStore = useAppStore(); const themeStore = useThemeStore(); @@ -24,10 +25,9 @@ const currentTemplate = ref<{ id: number, category: string | null, level: string steps: [], }); const rules = ref({ - category: { required: true, message: '变更类别不能为空', trigger: ['blur'] }, - level: { required: true, message: '变更等级不能为空', trigger: ['blur'] }, - duration: { required: true, message: '变更时效不能为空', trigger: ['blur'] }, - step: { required: true, message: '审批步骤不能为空', trigger: ['blur'] } + category: { required: true, message: '变更类别不能为空', trigger: ['blur', 'change'] }, + level: { required: true, message: '变更等级不能为空', trigger: ['blur', 'change'] }, + duration: { type: 'number', required: true, message: '变更时效不能为空', trigger: ['blur', 'change'] }, }) const templateModal = ref(false); @@ -48,7 +48,7 @@ const SPECIALTIES = [ { label: '质量', value: '质量' } ]; // 审批用户列表 -const peopleList = ref<{label: string, value: number,children: any[]}[]>([]); +const peopleList = ref<{label: string, value: string,children: any[]}[]>([]); // 根据value匹配label和color const getLabel = (type: string, value: number) => { @@ -154,7 +154,7 @@ const columns = ref([ positiveText: '确定', negativeText: '取消', onPositiveClick: () => { - handleDelete(row) + handleDelete(row.id) }, // 可选:自定义确认/取消按钮的样式 positiveButtonProps: { size: 'tiny', type: 'primary' }, @@ -208,64 +208,81 @@ const handleView = (row: any) => { // 编辑模板 const handleEdit = (row: any) => { currentType.value = 'edit'; - currentTemplate.value = { + let obj = { id: row.id, category: row.category.toString(), level: row.level.toString(), duration: row.duration, steps: row.steps, }; + currentTemplate.value = JSON.parse(JSON.stringify(obj)); templateModal.value = true; } // 删除模板 -const handleDelete = (row: any) => { +const handleDelete = async (id: number) => { loading.value = true; - setTimeout(() => { - loading.value = false; - list.value = list.value.filter((item: any) => item.id !== row.id); + const {error} = await deleteTemplateApi(id); + if(!error){ + list.value = list.value.filter((item: any) => item.id !== id); window.$message?.success('删除成功') - }, 1000) + } + loading.value = false; } // 保存模板 const saveTemplate = async (e: MouseEvent) => { e.preventDefault() - formRef.value?.validate((errors: any) => { + formRef.value?.validate(async (errors: any) => { if (!errors) { + if(currentTemplate.value.steps.length===0){ + return window.$message?.warning('请添加审批步骤') + } + const hasEmptyName = currentTemplate.value.steps.some((item:any) => item.name === ''); + if(hasEmptyName){ + return window.$message?.warning('请填写审批步骤名称') + } + const hasEmptyMembers = currentTemplate.value.steps.some((item:any) => item.members.length=== 0); + if(hasEmptyMembers){ + return window.$message?.warning('请添加审批步骤人员') + } + const hasCountersignTrue = currentTemplate.value.steps.some((item:any) => item.countersign===true); + if(hasCountersignTrue){ + const hasEmptySpecialty = currentTemplate.value.steps + .filter((step:any) => step.countersign === true) + .some((step:any) => step.members.some((member:any) => member.specialty === "")); + if(hasEmptySpecialty){ + return window.$message?.warning('请选择审批步骤人员专业') + } + } btnLoading.value = true; - setTimeout(() => { - // 新增 - if(currentType.value === 'add'){ - list.value.push({ - id:list.value.length+1, - category:currentTemplate.value?.category as string, - level:currentTemplate.value?.level as string, - duration:currentTemplate.value?.duration as number, - steps:currentTemplate.value?.steps as any[] - }) + if(currentType.value === 'add'){ + const {error} = await addTemplateApi(currentTemplate.value); + if(!error){ + window.$message?.success('添加成功') + templateModal.value = false; + getList(); } - // 编辑 - if(currentType.value === 'edit'){ - const target = list.value.find((item:any) => item.id === currentTemplate.value.id); - if (target) { - target.category = currentTemplate.value?.category as string; - target.level = currentTemplate.value?.level as string; - target.duration = currentTemplate.value?.duration as number; - target.steps = currentTemplate.value?.steps as any[]; - } + } + if(currentType.value === 'edit'){ + let obj = JSON.parse(JSON.stringify(currentTemplate.value)); + obj.category = Number(obj.category); + obj.level = Number(obj.level); + const {error} = await editTemplateApi(currentTemplate.value.id,obj); + if(!error){ + window.$message?.success('编辑成功') + templateModal.value = false; + getList(); } - window.$message?.success('操作成功') - btnLoading.value = false; - templateModal.value = false; - }, 1000) + } + btnLoading.value = false; } }) } -// 会签步骤:一个模板最多一步;只有会签步骤能选专业。 -// 勾选/取消后,所有非会签步骤的人员专业与「必须会签」标记一并清空 + +// 专业会签步骤勾选 const setStepCountersign = (target: any, v: boolean) => { currentTemplate.value.steps.forEach((s:any) => { s.countersign = s === target ? v : false; - if (!s.countersign) s.members.forEach((m:any) => { m.specialty = ""; m.countersign = false; }); + if (!s.countersign) s.members.forEach((m:any) => { m.specialty = ""; m.is_sign = false; }); }); } // 当前打开人员选择器的步骤(步骤行「+」按钮切换) @@ -275,18 +292,39 @@ const togglePicker = (s: any) => { pickerStepId.value = pickerStepId.value === s.unique_id ? null : s.unique_id; pick.value = null; } +/** + * 在组织树中根据 user_id 查找用户信息 + * @param {Array} tree - 组织树数据 + * @param {string|number} targetUserId - 要查找的 user_id + * @returns {Object|null} - 返回 { userLabel, parentLabel, parentValue } 或 null + */ +function findUserInTree(tree: any[], targetUserId: string | number) { + for (const org of tree) { + const children = org.children || []; + for (const user of children) { + if (String(user.user_id) === String(targetUserId)) { + return { + user_name: user.label, + org_name: org.label, + org_id: org.value + }; + } + } + } + return null; // 未找到 +} // 添加审批步骤人员 const addMember = (s: any, v: string | null) => { - console.log(s,v) if (v && !s.members.some((m:any) => m.user_name === v)){ - s.members.push({ user_name: v, specialty: "", countersign: false }); + let info = findUserInTree(peopleList.value, v); + s.members.push({ user_id: Number(v), user_name: info?.user_name || '', org_id: info?.org_id || '', org_name: info?.org_name || '', specialty: "", is_sign: 0 }); pick.value = null; pickerStepId.value = null; } } // 删除审批步骤人员 -const delMember = (s: any, p: string) => { - s.members = s.members.filter((m:any) => m.person !== p); +const delMember = (s: any, p: number) => { + s.members = s.members.filter((m:any) => m.user_id !== p); } // 删除审批步骤 const removeStep = (idx: number) => { @@ -334,7 +372,6 @@ const getConfig = async () => { loading.value = false; } - // 人员数据转换 const groupUsersByOrg = (users:any) => { const orgMap = new Map(); // key: org.id, value: { id, label, children } @@ -357,13 +394,13 @@ const groupUsersByOrg = (users:any) => { // 避免同一个用户重复加入同一个组织(理论上不会发生,但做去重保护) if (!targetOrg.children.some((child:any) => child.id === userId)) { targetOrg.children.push({ - value: userId, - label: realname + value: userId.toString(), + label: realname, + user_id: userId.toString() }); } }); }); - return Array.from(orgMap.values()); } // 获取审批用户列表 @@ -371,12 +408,9 @@ const getPeopleList = async () => { const {data,error} = await peopleListApi(); if(!error){ peopleList.value = groupUsersByOrg(data); - console.log(groupUsersByOrg(data)) } } - - onMounted(() => { getPeopleList(); getConfig() @@ -385,7 +419,7 @@ onMounted(() => { - + @@ -495,7 +533,7 @@ onMounted(() => {

+ class="w-56" :on-update:value="(v) => addMember(s, v)" /> 未预设