diff --git a/src/service/api/system.ts b/src/service/api/system.ts index e700e2a..7022ef8 100644 --- a/src/service/api/system.ts +++ b/src/service/api/system.ts @@ -30,3 +30,27 @@ export function deleteSystemConfigApi(id:number) { method: 'delete', }); } + +// 审批模板列表 +export function templateListApi() { + return request({ + url: '/api/approval-templates', + method: 'get', + }); +} +// 审批用户列表 +export function peopleListApi() { + return request({ + url: '/api/approval-flow/users', + method: 'get', + }); +} + +// 批量修改ai配置项和变更编号规则 +export function updateConfigApi(data:{items:any[]}) { + return request({ + url: '/api/system-config/batch', + method: 'put', + data, + }); +} diff --git a/src/views/systemManage/role/index.vue b/src/views/systemManage/role/index.vue index 7947910..7724c93 100644 --- a/src/views/systemManage/role/index.vue +++ b/src/views/systemManage/role/index.vue @@ -29,11 +29,6 @@ const rules = ref({ }) const roleModal = ref(false); const permissionModal = ref(false); -const pagination = ref<{ page: number, pageSize: number, pageCount: number }>({ - page: 1, - pageSize: 20, - pageCount: 0, -}) const columns = ref([ { title: '序号', @@ -41,7 +36,7 @@ const columns = ref([ width: 5, align: 'center', render: (_row: any, index: number) => { - return h('span', {}, { default: () => (pagination.value.page - 1) * pagination.value.pageSize + index + 1 }) + return h('span', {}, { default: () => index + 1 }) } }, { @@ -230,7 +225,7 @@ onMounted(() => { :single-line="false" :columns="columns" :data="list" - :pagination="pagination" + :pagination="false" max-height="calc(100vh - 290px)" /> diff --git a/src/views/systemManage/setting/index.vue b/src/views/systemManage/setting/index.vue index a434366..98e73ac 100644 --- a/src/views/systemManage/setting/index.vue +++ b/src/views/systemManage/setting/index.vue @@ -4,26 +4,21 @@ import { useAppStore } from '@/store/modules/app'; import { Icon } from '@iconify/vue' import { useThemeStore } from '@/store/modules/theme'; import { getColorWithOpacity, tagTextColor, tagBgColor, tagBorderColor } from '@/utils/common'; -import { systemConfigApi, addSystemConfigApi, editSystemConfigApi, deleteSystemConfigApi } from '@/service/api/system'; +import { systemConfigApi, addSystemConfigApi, editSystemConfigApi, deleteSystemConfigApi, updateConfigApi } from '@/service/api/system'; const appStore = useAppStore(); const themeStore = useThemeStore(); const gap = computed(() => (appStore.isMobile ? 0 : 16)); -// AI 辅助功能配置 -const aiEnabled = ref(true); -const aiConfig = ref<{address:string, mode:number|null, key:string,timeout:null|number}>({ - address:'', - mode:null, - key:'', - timeout:null, -}) -const aiTested = ref("none"); +// *********************AI 辅助功能配置*********************// +const aiConfig = ref([]) +const switchLoading = ref(false); const modeOptions = ref<{label:string, value:number}[]>([ {label:'kimi-k2(企业私有化部署)',value:1} ]) const testing = ref(false); const showLog = ref(false); + const AI_LOGS = [ { scene: "AI-01 变更识别", user: "张工艺", change: "MOC-2026-R01-0041", time: "08-24 09:12", cost: "1.8s", adopted: "修改后采纳" }, { scene: "AI-03 风险预分析", user: "张工艺", change: "MOC-2026-R01-0041", time: "08-24 09:15", cost: "2.4s", adopted: "采纳" }, @@ -32,6 +27,34 @@ const AI_LOGS = [ { scene: "AI-09 关闭辅助判定", user: "系统管理员", change: "MOC-2026-R01-0035", time: "08-23 15:02", cost: "1.5s", adopted: "采纳" }, ]; +// AI 辅助功能切换 +const toggle = async (v: boolean, item:any) => { + switchLoading.value = true; + const {error} = await updateConfigApi({items:[{ + id:item.id, + label:item.label, + remark:item.remark, + value:v ? '1' : '0' + }]}); + if(!error){ + item.value = v ? '1' : '0'; + window.$message?.success(v ? "AI 辅助功能已启用" : "AI 辅助功能已关闭"); + } + switchLoading.value = false; +} +// 测试连接 +const testConn = () => { + testing.value = true; + setTimeout(() => { + testing.value = false; + window.$message?.success(`连接测试通过:${aiConfig.value.mode} 响应正常(耗时 0.8s)`); + }, 900); +} +// 保存ai配置 +const saveAiCfg = () => { + window.$message?.success("AI 接口配置已保存(配置变更留痕,立即生效)"); +} + // *********************变更类型*********************// const typeRef = ref(null); @@ -212,27 +235,24 @@ const levelSave = async (e:MouseEvent) => { // *********************变更编号规则*********************// +const ruleLoading = ref(false); const previewNumber = computed(() => { + let prefix = ruleConfig.value.find((item:any) => item.item_key === 'prefix')?.value || ''; let year = ''; + let code = ruleConfig.value.find((item:any) => item.item_key === 'unit_code')?.value || ''; let digit = ''; const currentYear = new Date().getFullYear(); - if (ruleInfo.value.year === 'yyyy') { + if (ruleConfig.value.find((item:any) => item.item_key === 'year_format')?.value === 'yyyy') { year = currentYear.toString(); - } else if (ruleInfo.value.year === 'yy') { + } else if (ruleConfig.value.find((item:any) => item.item_key === 'year_format')?.value === 'yy') { year = currentYear.toString().substring(2); } - if (ruleInfo.value.digit) { - digit = '0'.repeat(ruleInfo.value.digit - 1) + '1'; + if (ruleConfig.value.find((item:any) => item.item_key === 'seq_length')?.value) { + digit = '0'.repeat(ruleConfig.value.find((item:any) => item.item_key === 'seq_length')?.value - 1) + '1'; } - return ruleInfo.value.prefix+'-' + year + '-' + ruleInfo.value.code + '-' + digit; + return prefix+'-' + year + '-' + code + '-' + digit; }); -const ruleInfo = ref<{prefix:string, year:null|string, code:string|null, digit:number|null, rule:string|null}>({ - prefix:'', - year:null, - code: null, - digit: null, - rule: null, -}) +const ruleConfig = ref([]) const yearOptions = ref<{label:string, value:string}[]>([ {label:'四位年份(yyyy)',value:'yyyy'}, {label:'两位年份(yy)',value:'yy'}, @@ -247,7 +267,21 @@ const ruleOptions = ref<{label:string, value:string}[]>([ {label:'连续不重置',value:'CONTINUE'}, ]) -// ---------- 风险矩阵设置(按分析方法) ---------- +// 保存编号规则 +const saveRule = async () => { + if(ruleConfig.value.find((item:any) => item.item_key === 'prefix')?.value===''){ + return window.$message?.warning(`请输入${ruleConfig.value.find((item:any) => item.item_key === 'prefix')?.label}`); + } + ruleLoading.value = true; + const {error} = await updateConfigApi({items:ruleConfig.value}); + if(!error){ + window.$message?.success("保存成功"); + } + ruleLoading.value = false; +} + +// *************** 风险矩阵设置(按分析方法) ***************// + const dimensionModal = ref(false); const dimensionLoading = ref(false); const dimForm = ref({ s: [], l: [] }); @@ -299,22 +333,6 @@ const cellLevel = (s:number, l:number) => { const sc = cellScore(s, l); return curMatrix.value.levels.find((lv:{min:number,max:number}) => sc >= lv.min && sc <= lv.max); } -// AI 辅助功能切换 -const toggle = (v: boolean) => { - window.$message?.success(v ? "AI 辅助功能已启用" : "AI 辅助功能已关闭"); - aiEnabled.value = v; -} -const testConn = () => { - testing.value = true; - setTimeout(() => { - testing.value = false; - aiTested.value = "ok"; - window.$message?.success(`连接测试通过:${aiConfig.value.mode} 响应正常(耗时 0.8s)`); - }, 900); -} -const saveAiCfg = () => { - window.$message?.success("AI 接口配置已保存(配置变更留痕,立即生效)"); -} const dimensionSave = () => { dimensionLoading.value = true; setTimeout(() => { @@ -340,17 +358,11 @@ const getConfig = async () => { // 解析 AI 辅助功能配置 const aiAssistGroup = data.find((group:{group_key:string}) => group.group_key === 'ai_assist'); if (aiAssistGroup) { - const items = aiAssistGroup.items; - items.forEach((item:any) => { - switch (item.item_key) { - case 'enabled': aiEnabled.value = item.value === '1'; break; - case 'api_url': aiConfig.value.address = item.value; break; - case 'model': aiConfig.value.mode = item.value; break; - case 'api_key': aiConfig.value.key = item.value; break; - case 'timeout_seconds': aiConfig.value.timeout = Number(item.value); break; - default: break; - } - }); + aiConfig.value = aiAssistGroup.items; + const target = aiConfig.value.find((item:any) => item.item_key === 'timeout_seconds'); + if (target) { + target.value = Number(target.value); + } } // 解析 变更类型设置 const changeTypeGroup = data.find((group:{group_key:string}) => group.group_key === 'change_type'); @@ -365,17 +377,11 @@ const getConfig = async () => { // 解析 变更编号规则 const changeCodeGroup = data.find((group:{group_key:string}) => group.group_key === 'change_no_rule'); if (changeCodeGroup) { - const items = changeCodeGroup.items; - items.forEach((item:any) => { - switch (item.item_key) { - case 'prefix': ruleInfo.value.prefix = item.value; break; - case 'year_format': ruleInfo.value.year = item.value; break; - case 'unit_code': ruleInfo.value.code = item.value; break; - case 'seq_length': ruleInfo.value.digit = Number(item.value); break; - case 'seq_reset': ruleInfo.value.rule = item.value; break; - default: break; - } - }); + ruleConfig.value = changeCodeGroup.items; + const target = ruleConfig.value.find((item:any) => item.item_key === 'seq_length'); + if (target) { + target.value = Number(target.value); + } } } } @@ -405,59 +411,62 @@ onMounted(() => { AI 辅助功能

-
-
-
启用 AI 辅助
- +
AI 接口配置 - 连接正常
-
-

接口地址

-
- + +
@@ -610,40 +619,42 @@ onMounted(() => {
-
-

编号前缀

-
- +
编号示例预览: {{previewNumber}} - 保存规则 + 保存规则

保存草稿即预占编号,提交后正式生效;规则修改不影响历史单据编号。

diff --git a/src/views/systemManage/template/index.vue b/src/views/systemManage/template/index.vue index 30bf47d..9b2a39c 100644 --- a/src/views/systemManage/template/index.vue +++ b/src/views/systemManage/template/index.vue @@ -3,10 +3,10 @@ import { ref, computed, h, onMounted } from 'vue'; import { useAppStore } from '@/store/modules/app'; import { Icon } from '@iconify/vue' import { useThemeStore } from '@/store/modules/theme'; -import { useRouter } from 'vue-router'; import { NButton, NPopconfirm, NTag } from 'naive-ui'; +import { tagTextColor, tagBgColor, tagBorderColor } from '@/utils/common'; +import { templateListApi, systemConfigApi, peopleListApi } from '@/service/api/system'; -const router = useRouter(); const appStore = useAppStore(); const themeStore = useThemeStore(); const gap = computed(() => (appStore.isMobile ? 0 : 16)); @@ -16,71 +16,47 @@ const btnLoading = ref(false); const currentType = ref('add'); const readonly = computed(() => currentType.value === "view"); const formRef = ref(null); -const currentTemplate = ref<{ id: number, category: string | null, level: string | null, timeLimit: string | null, steps: any[] }>({ +const currentTemplate = ref<{ id: number, category: string | null, level: string | null, duration: number | null, steps: any[] }>({ id: 0, category: null, level: null, - timeLimit: null, + duration: null, steps: [], }); const rules = ref({ category: { required: true, message: '变更类别不能为空', trigger: ['blur'] }, level: { required: true, message: '变更等级不能为空', trigger: ['blur'] }, - timeLimit: { required: true, message: '变更时效不能为空', trigger: ['blur'] }, + duration: { required: true, message: '变更时效不能为空', trigger: ['blur'] }, step: { required: true, message: '审批步骤不能为空', trigger: ['blur'] } }) const templateModal = ref(false); -const categoryOptions = ref([ - { - label: '工艺', - value: '工艺' - }, - { - label: '设备', - value: '设备' - }, - { - label: '管理', - value: '管理' +const categoryOptions = ref<{ label: string, value: string, color: string }[]>([]) +const levelOptions = ref<{ label: string, value: string, color: string }[]>([]) +const durationOptions = ref<{ label: string, value: number }[]>([ + { label: '永久', value: 1 }, + { label: '临时', value: 2 }, +]) +// 专业 +const SPECIALTIES = [ + { label: '生产', value: '生产' }, + { label: '技术', value: '技术' }, + { label: '仪表', value: '仪表' }, + { label: '电气', value: '电气' }, + { label: '设备', value: '设备' }, + { label: '安全', value: '安全' }, + { label: '质量', value: '质量' } +]; +// 审批用户列表 +const peopleList = ref<{label: string, value: number,children: any[]}[]>([]); + +// 根据value匹配label和color +const getLabel = (type: string, value: number) => { + if(type=='level'){ + return levelOptions.value.find((item: { label: string, value: string, color: string }) => item.value === value.toString()) || null; } -]) - -const levelOptions = ref([ - { - label: '一般', - value: '一般' - }, - { - label: '重要', - value: '重要' - }, -]) - -const timeLimitOptions = ref([ - { - label: '永久', - value: '永久' - }, - { - label: '临时', - value: '临时' - }, -]) -const SPECIALTIES = ref<{ label: string, value: string }[]>([ - { label: '工艺', value: 'process' }, - { label: '设备', value: 'equipment' }, - { label: '仪表', value: 'instrument' }, - { label: '电气', value: 'electrical' }, - { label: '安全', value: 'safety' }, - { label: '质量', value: 'quality' } -]); - -const pagination = ref<{ page: number, pageSize: number, pageCount: number }>({ - page: 1, - pageSize: 20, - pageCount: 0, -}) + return categoryOptions.value.find((item: { label: string, value: string, color: string }) => item.value === value.toString()) || null; +} const columns = ref([ { title: '序号', @@ -88,7 +64,7 @@ const columns = ref([ width: 6, align: 'center', render: (row: any, index: number) => { - return h('span', {}, { default: () => (pagination.value.page - 1) * pagination.value.pageSize + index + 1 }) + return h('span', {}, { default: () => index + 1 }) } }, { @@ -96,11 +72,15 @@ const columns = ref([ key: 'category', width: 8, align: 'center', - render: (row: any, index: number) => { + render: (row: any) => { return h(NTag, { size: 'small', - type: 'default' - }, { default: () => `${row.category}` }) + color: { + 'color': tagBgColor(getLabel('category', row.category)?.color || ''), + 'textColor': tagTextColor(getLabel('category', row.category)?.color || ''), + 'borderColor': tagBorderColor(getLabel('category', row.category)?.color || ''), + }, + }, { default: () => `${getLabel('category', row.category)?.label || ''}` }) } }, { @@ -108,23 +88,27 @@ const columns = ref([ key: 'level', width: 8, align: 'center', - render: (row: any, index: number) => { + render: (row: any) => { return h(NTag, { size: 'small', - type: `${row.level==='重要'?'error':'default'}` - }, { default: () => `${row.level}` }) + color: { + 'color': tagBgColor(getLabel('level', row.level)?.color || ''), + 'textColor': tagTextColor(getLabel('level', row.level)?.color || ''), + 'borderColor': tagBorderColor(getLabel('level', row.level)?.color || ''), + }, + }, { default: () => `${getLabel('level', row.level)?.label || ''}` }) } }, { title: '变更时效', - key: 'timeLimit', + key: 'duration', width: 8, align: 'center', - render: (row: any, index: number) => { + render: (row: any) => { return h(NTag, { size: 'small', - type: `${row.timeLimit==='临时'?'warning':'info'}` - }, { default: () => `${row.timeLimit}` }) + type: `${row.duration===2?'warning':'info'}` + }, { default: () => `${row.duration===2?'临时':'永久'}` }) } }, { @@ -194,46 +178,8 @@ const columns = ref([ } }, ]) -const list = ref<{ id: number, category: string, level: string, timeLimit: string, steps: any[] }[]>([]) +const list = ref<{ id: number, category: string, level: string, duration: number | null, steps: any[] }[]>([]) -// 获取列表 -const getList = async () => { - loading.value = true; - setTimeout(() => { - loading.value = false; - list.value = [ - {id:1,category:'工艺',level:'重要',timeLimit:'临时',steps: [ - { - id:101, - name:'部门审核', - countersign: false, - members: [{person:'测试人员01',specialty:'',countersign:false}] - }, - { - id:102, - name:'专业审批', - countersign: false, - members: [{person:'测试人员02',specialty:'',countersign:false}] - }, - {id: 103, - name: "部门负责人批准", - countersign: false, - members: [ {person:'测试人员03',specialty:'',countersign:false}] - } - ]}, - {id:2,category:'设备',level:'一般',timeLimit:'临时',steps:[ - - ]}, - {id:3,category:'管理',level:'重要',timeLimit:'永久',steps:[ - - ]}, - {id:4,category:'工艺',level:'重要',timeLimit:'临时',steps:[ - - ]}, - - ] - }, 1000) -} // 打开添加模板弹框 const addTemplate = () => { @@ -242,7 +188,7 @@ const addTemplate = () => { id: 0, category: null, level: null, - timeLimit: null, + duration: null, steps: [], }; templateModal.value = true; @@ -252,26 +198,26 @@ const handleView = (row: any) => { currentType.value = 'view'; currentTemplate.value = { id: row.id, - category: row.category, - level: row.level, - timeLimit: row.timeLimit, + category: row.category.toString(), + level: row.level.toString(), + duration: row.duration, steps: row.steps, }; templateModal.value = true; } -// 编辑角色 +// 编辑模板 const handleEdit = (row: any) => { currentType.value = 'edit'; currentTemplate.value = { id: row.id, - category: row.category, - level: row.level, - timeLimit: row.timeLimit, + category: row.category.toString(), + level: row.level.toString(), + duration: row.duration, steps: row.steps, }; templateModal.value = true; } -// 删除角色 +// 删除模板 const handleDelete = (row: any) => { loading.value = true; setTimeout(() => { @@ -280,8 +226,8 @@ const handleDelete = (row: any) => { window.$message?.success('删除成功') }, 1000) } -// 保存角色 -const saveRole = async (e: MouseEvent) => { +// 保存模板 +const saveTemplate = async (e: MouseEvent) => { e.preventDefault() formRef.value?.validate((errors: any) => { if (!errors) { @@ -293,7 +239,7 @@ const saveRole = async (e: MouseEvent) => { id:list.value.length+1, category:currentTemplate.value?.category as string, level:currentTemplate.value?.level as string, - timeLimit:currentTemplate.value?.timeLimit as string, + duration:currentTemplate.value?.duration as number, steps:currentTemplate.value?.steps as any[] }) } @@ -303,7 +249,7 @@ const saveRole = async (e: MouseEvent) => { if (target) { target.category = currentTemplate.value?.category as string; target.level = currentTemplate.value?.level as string; - target.timeLimit = currentTemplate.value?.timeLimit as string; + target.duration = currentTemplate.value?.duration as number; target.steps = currentTemplate.value?.steps as any[]; } } @@ -326,84 +272,114 @@ const setStepCountersign = (target: any, v: boolean) => { const pickerStepId = ref(null); const pick = ref(null); const togglePicker = (s: any) => { - pickerStepId.value = pickerStepId.value === s.id ? null : s.id; + pickerStepId.value = pickerStepId.value === s.unique_id ? null : s.unique_id; pick.value = null; } +// 添加审批步骤人员 const addMember = (s: any, v: string | null) => { - if (v && !s.members.some((m:any) => m.person === v)) s.members.push({ person: v, specialty: "", countersign: false }); - pick.value = null; - pickerStepId.value = 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 }); + pick.value = null; + pickerStepId.value = null; + } } +// 删除审批步骤人员 const delMember = (s: any, p: string) => { s.members = s.members.filter((m:any) => m.person !== p); } +// 删除审批步骤 const removeStep = (idx: number) => { currentTemplate.value.steps.splice(idx, 1); } -let sid = 100; -const mkStep = (name: string, extra: Partial = {}): any => ({ id: ++sid, name, countersign: false, members: [], ...extra }); -const addStepAfter = (idx: number) => { - currentTemplate.value.steps.splice(idx + 1, 0, mkStep("")); +// 添加审批步骤 +const addStep = (idx: number) => { + let step = { + unique_id: Date.now(), + step_order: currentTemplate.value.steps.length + 1, + name: "", + countersign: false, + members: [], + } + currentTemplate.value.steps.splice(idx + 1, 0, step); } -const ORG_TREE = [ - { - id: "factory", name: "演示工厂", short: "YS", leaf: false, sort: 0, - children: [ - { - id: "scb", name: "生产部", short: "SCB", leaf: false, sort: 0, - children: [ - { id: "cj1", name: "测试车间一", short: "CJ1", leaf: true, sort: 0 }, - { id: "cj2", name: "测试车间二", short: "CJ2", leaf: true, sort: 1 }, - { id: "cj3", name: "测试车间三", short: "CJ3", leaf: true, sort: 2 }, - ], - }, - { - id: "ahb", name: "安环部", short: "AHB", leaf: false, sort: 1, - children: [ - { id: "aqk", name: "安全科", short: "AQK", leaf: true, sort: 0 }, - { id: "hbk", name: "环保科", short: "HBK", leaf: true, sort: 1 }, - ], - }, - { - id: "sbb", name: "设备部", short: "SBB", leaf: false, sort: 2, - children: [ - { id: "sbk", name: "设备科", short: "SBK", leaf: true, sort: 0 }, - ], - }, - { - id: "zlb", name: "质量部", short: "ZLB", leaf: false, sort: 3, - children: [ - { id: "zjk", name: "质检科", short: "ZJK", leaf: true, sort: 0 }, - ], - }, - ], - }, -]; -const LEVEL2_ORGS = ORG_TREE[0]?.children ?? []; -const ORG_MEMBERS = [ - { id: 1, name: "测试人员01", dept: "测试车间一", gender: "男", phone: "13800000001", email: "test01@demo.com", account: "TEST001", role: "操作人员", scope: ["factory"], enabled: true }, - { id: 2, name: "测试人员02", dept: "测试车间二", gender: "女", phone: "13800000002", email: "test02@demo.com", account: "TEST002", role: "班长", scope: ["factory"], enabled: true }, - { id: 3, name: "测试人员03", dept: "测试车间三", gender: "男", phone: "13800000003", email: "test03@demo.com", account: "TEST003", role: "车间主任", scope: ["factory"], enabled: true }, - { id: 4, name: "测试人员04", dept: "安全科", gender: "女", phone: "13800000004", email: "test04@demo.com", account: "TEST004", role: "安全工程师", scope: ["factory"], enabled: true }, - { id: 5, name: "测试人员05", dept: "环保科", gender: "男", phone: "13800000005", email: "test05@demo.com", account: "TEST005", role: "环保专员", scope: ["factory"], enabled: true }, - { id: 6, name: "测试人员06", dept: "设备科", gender: "男", phone: "13800000006", email: "test06@demo.com", account: "TEST006", role: "设备工程师", scope: ["factory"], enabled: true }, - { id: 7, name: "测试人员07", dept: "质检科", gender: "女", phone: "13800000007", email: "test07@demo.com", account: "TEST007", role: "质量工程师", scope: ["factory"], enabled: true }, -]; -function orgSubtreeNames(n: any): string[] { - return [n.name, ...(n.children ?? []).flatMap(orgSubtreeNames)]; + +// 获取列表 +const getList = async () => { + loading.value = true; + const {data,error} = await templateListApi(); + if(!error){ + list.value = data || []; + } + loading.value = false; } -// 预设人员:级联选项(第二层组织 → 组织下可选成员,已选成员不再出现,空组织不展示) -const peopleOpts = (s: any) => - LEVEL2_ORGS.map((o) => ({ - label: o.name, - value: o.id, - children: ORG_MEMBERS - .filter((m) => m.enabled && orgSubtreeNames(o).includes(m.dept) && !s.members.some((x) => x.person === m.name)) - .map((m) => ({ label: m.name, value: m.name })), - })).filter((o) => o.children.length > 0); + +// 获取配置 +const getConfig = async () => { + loading.value = true; + const {data,error} = await systemConfigApi(); + if(!error){ + // 变更类型 + const changeTypeGroup = data.find((group:{group_key:string}) => group.group_key === 'change_type'); + if (changeTypeGroup) { + categoryOptions.value = changeTypeGroup.items; + } + // 变更等级 + const changeLevelGroup = data.find((group:{group_key:string}) => group.group_key === 'change_level'); + if (changeLevelGroup) { + levelOptions.value = changeLevelGroup.items; + } + getList(); + } + loading.value = false; +} + + +// 人员数据转换 +const groupUsersByOrg = (users:any) => { + const orgMap = new Map(); // key: org.id, value: { id, label, children } + users.forEach((user:any) => { + const { id: userId, realname, user_departments } = user; + if (!user_departments || user_departments.length === 0) return; + + user_departments.forEach((dept:any) => { + const org = dept.org; + if (!org || !org.id) return; + + if (!orgMap.has(org.id)) { + orgMap.set(org.id, { + value: org.id, + label: org.label, + children: [] + }); + } + const targetOrg = orgMap.get(org.id); + // 避免同一个用户重复加入同一个组织(理论上不会发生,但做去重保护) + if (!targetOrg.children.some((child:any) => child.id === userId)) { + targetOrg.children.push({ + value: userId, + label: realname + }); + } + }); + }); + + return Array.from(orgMap.values()); +} +// 获取审批用户列表 +const getPeopleList = async () => { + const {data,error} = await peopleListApi(); + if(!error){ + peopleList.value = groupUsersByOrg(data); + console.log(groupUsersByOrg(data)) + } +} + + onMounted(() => { - getList() + getPeopleList(); + getConfig() }) @@ -434,7 +410,7 @@ onMounted(() => { :single-line="false" :columns="columns" :data="list" - :pagination="pagination" + :pagination="false" max-height="calc(100vh - 290px)" :scroll-x="820" /> @@ -469,15 +445,15 @@ onMounted(() => { -
+
{{ idx + 1 }} @@ -496,42 +472,43 @@ onMounted(() => {
预设人员:
-
- {{ m.person }} +
+ {{ m.user_name }} - +

必须参与会签:勾选的人员必须参与专业会签,未勾选的人员为可选会签(按需参加)

- + class="w-56" :on-update:value="(v) => addMember(s, v ? null : String(v))" /> + 未预设
- 添加审批步骤 + 添加审批步骤