diff --git a/src/api/common/api.ts b/src/api/common/api.ts index aabce4b..afa63e9 100644 --- a/src/api/common/api.ts +++ b/src/api/common/api.ts @@ -21,7 +21,7 @@ enum Api { deletePendingTask = '/tasktask/taskTask/deletePendingTask', updateTitleAndDeadline = '/tasktask/taskTask/updateTitleAndDeadline', currentNodeInfo = '/act/task/currentNodeInfo', - getBusinessStatus = '/tasktask/taskTask/getBusinessStatus', + } /** @@ -210,11 +210,6 @@ export const updateTitleAndDeadline = (params) => { */ export const queryCurrentNodeInfo = (params) => defHttp.get({ url: Api.currentNodeInfo, params }); -/** - * 查询业务状态(单条) - * @param params { businessId: string } - */ -export const getBusinessStatus = (params) => defHttp.get({ url: Api.getBusinessStatus, params }); /** * 【用于评论功能】自定义文件上传-方法 diff --git a/src/composables/useSubApproveUserResolver.ts b/src/composables/useSubApproveUserResolver.ts new file mode 100644 index 0000000..4f6fe9d --- /dev/null +++ b/src/composables/useSubApproveUserResolver.ts @@ -0,0 +1,72 @@ +import { ref } from 'vue'; +import { getUserList } from '/@/api/common/api'; + +function normalizeCommaList(value: string): string { + return String(value || '') + .split(',') + .map((s) => s.trim()) + .filter(Boolean) + .join(','); +} + +function normalizeDisplayNames(value: string): string { + return String(value || '') + .split(/[,,;;、]/) + .map((s) => s.trim()) + .filter(Boolean) + .join('、'); +} + +/** + * 部门经办人选人 + 名称解析,统一 BgXiSpeak / DqInspectTask 等 BPM 表单的 + * username → realname 转换逻辑。 + * + * - `usernames`: 原始 username(逗号分隔),绑定 sz-dept-user-modal 的 v-model + * - `displayNames`: 真实姓名(顿号分隔),用于审批意见模板和 formScope + * - `setDisplayNames`: modal @confirm 已携带 realname 时直接设置(同步,无 API) + * - `initFromData`: 从已保存数据初始化时,通过 API 一次性解析 username → realname + */ +export function useSubApproveUserResolver() { + const usernames = ref(''); + const displayNames = ref(''); + + /** modal @confirm 回调直接设置已携带的 realname */ + function setDisplayNames(userIds: string, realnames: string) { + usernames.value = normalizeCommaList(userIds); + displayNames.value = normalizeDisplayNames(realnames); + } + + /** 从已保存数据初始化(需 API 解析 username → realname) */ + async function initFromData(rawUsernames: string) { + usernames.value = normalizeCommaList(rawUsernames); + if (!usernames.value) { + displayNames.value = ''; + return; + } + + try { + const res = await getUserList({ + username: usernames.value, + isMultiTranslate: 'true', + pageNo: 1, + pageSize: 999, + }); + const records = res?.records || res?.result?.records || res || []; + const nameMap: Record = {}; + for (const item of records) { + const u = String(item?.username || '').trim(); + const r = String(item?.realname || item?.name || '').trim(); + if (u && r) nameMap[u] = r; + } + const resolved = usernames.value + .split(',') + .map((u) => nameMap[u.trim()] || u.trim()) + .filter(Boolean); + displayNames.value = normalizeDisplayNames(resolved.join(',')); + } catch { + // 解析失败,保持空 + } + } + + return { usernames, displayNames, setDisplayNames, initFromData }; +} diff --git a/src/views/bg/xispeak/BgXiSpeakList.vue b/src/views/bg/xispeak/BgXiSpeakList.vue index ed86884..aad54e9 100644 --- a/src/views/bg/xispeak/BgXiSpeakList.vue +++ b/src/views/bg/xispeak/BgXiSpeakList.vue @@ -118,7 +118,7 @@ import { defHttp } from '/@/utils/http/axios'; import { useMessage } from '/@/hooks/web/useMessage'; import { showImportValidationErrors } from '/@/utils/helper/importError'; - import { startProcessSchedules, getBusinessStatus } from '/@/api/common/api'; + import { startProcessSchedules } from '/@/api/common/api'; import { dateUtil } from '/@/utils/dateUtil'; import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue'; @@ -360,7 +360,6 @@ import { defHttp } from '/@/utils/http/axios'; if (result && result.length > 0) { record.children = getDataByResult(result); await refreshFeedbackCounts(record.children); - await refreshBusinessStatus(record.children); // 触发表格重新渲染 updateTableDataRecord(record.id, { ...record }); } else { @@ -443,40 +442,6 @@ import { defHttp } from '/@/utils/http/axios'; } } - /** - * 批量查询业务状态并更新到 records 中 - */ - async function refreshBusinessStatus(records) { - const ids = collectAllIds(records); - if (ids.length === 0) return; - try { - const results = await Promise.all( - ids.map((id) => - getBusinessStatus({ businessId: id }).catch(() => null) - ) - ); - const statusMap: Record = {}; - for (const item of results) { - if (item?.businessId) { - statusMap[item.businessId] = item.status_dictText || ''; - } - } - const updateFn = (list) => { - if (!list) return; - for (const item of list) { - const status = statusMap[item.id]; - if (status !== undefined) { - item.status_dictText = status; - } - if (item.children) updateFn(item.children); - } - }; - updateFn(records); - } catch (e) { - // 静默处理查询异常 - } - } - /** * 接口请求成功后回调 */ @@ -484,8 +449,7 @@ import { defHttp } from '/@/utils/http/axios'; getDataByResult(result.items) && loadDataByExpandedRows(); if (result.items && result.items.length > 0) { await refreshFeedbackCounts(result.items); - await refreshBusinessStatus(result.items); - // 触发表格重新渲染以显示更新后的 implCount / closedCount / businessStatus + // 触发表格重新渲染以显示更新后的 implCount / closedCount setTableData([...getDataSource()]); } } diff --git a/src/views/bg/xispeak/components/BgXiSpeakBPMForm.vue b/src/views/bg/xispeak/components/BgXiSpeakBPMForm.vue index 30dbf50..ec9d744 100644 --- a/src/views/bg/xispeak/components/BgXiSpeakBPMForm.vue +++ b/src/views/bg/xispeak/components/BgXiSpeakBPMForm.vue @@ -246,7 +246,7 @@ - + @@ -257,6 +257,7 @@ :showSelnextUser="showSelnextUser" :beforeHandle="saveMainFormBeforeProcessHandle" :defaultReason="defaultHandleReason" + :defaultCc="defaultCcUsers" @success="handleProcessSuccess" @claimSuccess="handleClaimSuccess" /> @@ -278,7 +279,7 @@ import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue'; import Icon from '/@/components/Icon/index'; import { bgXiSpeakFeedbackList, bgXiSpeakFeedbackDelete, saveBpmForm, saveSubApprove, getProcessVariable } from '../BgXiSpeak.api'; - import { getUserList } from '/@/api/common/api'; + import { useSubApproveUserResolver } from '/@/composables/useSubApproveUserResolver'; import { usePermission } from '/@/hooks/web/usePermission'; import TaskHandleInnerContent from '/@/views/super/bpm/process/personalOffice/myHandleTask/content/TaskHandleInnerContent.vue'; import BgXiSpeakBPMFeedbackModal from './BgXiSpeakBPMFeedbackModal.vue'; @@ -328,10 +329,9 @@ import { const showBaseInfoDetail = ref(false); const showFeedbackDetail = ref(true); const feedbackList = ref([]); - const subApproveUser = ref(''); - const subApproveUserNameText = ref(''); - const userResolveVersion = ref(0); + const { usernames: subApproveUser, displayNames: subApproveUserNameText, setDisplayNames, initFromData } = useSubApproveUserResolver(); const isEnd = ref(0); + const defaultCcUsers = ref>([]); const mainForm = reactive>({ id: '', @@ -429,6 +429,7 @@ import { () => String(props.formData?.extendUrlParams?.showSubApproveUser ?? props.formData?.extendUrlParams?.selectuser ?? '') === '1' ); const showSubApproveUserSelector = computed(() => showSubApproveUser.value && String(isEnd.value) !== '1'); + const showDefaultCc = computed(() => String(props.formData?.extendUrlParams?.defaultCc ?? '') === '1'); const processInfo = computed(() => ({ taskId: props.formData?.taskId, @@ -469,9 +470,10 @@ import { Task_0jrgrzs: buildDeptHandlerFeedbackReason, Task_12vdqzv: buildDeptHandlerFeedbackReason, // 部门负责人接受任务并分配 - Task_1v9ce78: () => buildDeptLeaderAssignReason( - normalizeDeptNames(subApproveUserNameText.value || subApproveUser.value), - ), + Task_1v9ce78: () => { + if (isEnd.value === 1) return ''; + return buildDeptLeaderAssignReason(normalizeDeptNames(subApproveUserNameText.value)); + }, // 部门负责人直接反馈 Task_0sialna: buildDeptLeaderDirectFeedbackReason, // 督办部门经办人确认全部反馈事项 @@ -525,11 +527,35 @@ import { }, { immediate: true } ); + watch(isEnd, (val) => { + const vars = props.formData?.vars; + if (vars) { + vars.is_end = String(val); + vars.isEnd = String(val); + } + }); + + async function fetchDefaultCcUsers() { + try { + const res = await defHttp.get({ + url: '/sys/user/queryUserRoleComponentData', + params: { departId: PARTY_COMMITTEE_DEPT_ID, roleId: SDW_LEADER_ROLE_ID, searchSecurityLevel: 5, pageNo: 1, pageSize: 999 }, + }); + const records = res?.records || res?.result?.records || []; + defaultCcUsers.value = records.sort((a, b) => (a.sortno ?? Infinity) - (b.sortno ?? Infinity)); + } catch { + defaultCcUsers.value = []; + } + } watch( - subApproveUser, - (value) => { - resolveSubApproveUserName(value); + () => showDefaultCc.value, + () => { + if (showDefaultCc.value) { + fetchDefaultCcUsers(); + } else { + defaultCcUsers.value = []; + } }, { immediate: true } ); @@ -560,7 +586,7 @@ import { if (approveInfo && deptId && approveInfo[deptId]) { const detail = approveInfo[deptId]; isEnd.value = detail.isEnd ?? 0; - subApproveUser.value = detail.implWorker ?? ''; + initFromData(detail.implWorker ?? ''); } } @@ -771,42 +797,6 @@ import { .join(','); } - async function resolveSubApproveUserName(value: any) { - const resolveVersion = ++userResolveVersion.value; - const usernames = normalizeUsernameList(value); - if (!usernames) { - subApproveUserNameText.value = ''; - return; - } - - subApproveUserNameText.value = normalizeDeptNames(usernames); - try { - const res = await getUserList({ username: usernames, isMultiTranslate: 'true', pageNo: 1, pageSize: 999 }); - if (resolveVersion !== userResolveVersion.value) { - return; - } - const records = res?.records || res?.result?.records || res || []; - const userNameMap = Array.isArray(records) - ? records.reduce((cache: Record, item: any) => { - const username = String(item?.username || '').trim(); - const realname = String(item?.realname || item?.name || '').trim(); - if (username && realname) { - cache[username] = realname; - } - return cache; - }, {}) - : {}; - const names = usernames - .split(',') - .map((username) => userNameMap[username] || username) - .filter(Boolean); - subApproveUserNameText.value = normalizeDeptNames(names.join(',')); - } catch { - if (resolveVersion === userResolveVersion.value) { - subApproveUserNameText.value = normalizeDeptNames(usernames); - } - } - } function handleProcessSuccess() { emit('success'); diff --git a/src/views/bg/xispeak/components/BgXiSpeakForm.vue b/src/views/bg/xispeak/components/BgXiSpeakForm.vue index f5c0a91..bdf0b11 100644 --- a/src/views/bg/xispeak/components/BgXiSpeakForm.vue +++ b/src/views/bg/xispeak/components/BgXiSpeakForm.vue @@ -92,11 +92,11 @@ - - - - - + + + + + @@ -107,17 +107,17 @@ - - - - 未发起流程 - 正在落实措施收集流程 - 落实措施收集流程结束 - 正在经办人执行反馈流程 - 经办人执行反馈流程结束 - - - + + + + + + + + + + + @@ -205,7 +205,7 @@ import { PARTY_COMMITTEE_DEPT_ID, SDW_LEADER_ROLE_ID } from '/@/constant/supervi implMeasures: [{ required: true, message: '请输入贯彻落实措施' }], numberOfResolutions: [{ required: true, message: '请输入会议决策数' }], reportFeedbackStatus: [{ required: true, message: '请输入报告反馈情况' }], - completionStatus: [{ required: true, message: '请选择完成状态' }], + // completionStatus: [{ required: true, message: '请选择完成状态' }], deadline: [{ required: true, message: '请选择截止日期' }], implDept: [{ required: true, message: '请选择牵头部门' }], }); diff --git a/src/views/dq/inspectTask/DqInspectTaskList.vue b/src/views/dq/inspectTask/DqInspectTaskList.vue index 5f00320..e0c527a 100644 --- a/src/views/dq/inspectTask/DqInspectTaskList.vue +++ b/src/views/dq/inspectTask/DqInspectTaskList.vue @@ -157,7 +157,7 @@ import Icon from '/@/components/Icon/index'; import SzSelectDept from '/@/components/Form/src/jeecg/components/SzSelectDept.vue'; import SzDeptUserModal from '/@/components/semri/deptUserComponent/SzDeptUserModal.vue'; - import { startProcessSchedules, getBusinessStatus } from '/@/api/common/api'; + import { startProcessSchedules } from '/@/api/common/api'; import { dateUtil } from '/@/utils/dateUtil'; import FlowScheduleStartModal from './components/DqInspectTaskFlowScheduleStartModal.vue'; import BusinessProcessListModal from '/src/components/semri/process/BusinessProcessListModal.vue'; @@ -403,24 +403,24 @@ onClick: handleQueryProcess.bind(null, record), }); // if (!record.bpmStatus || record.bpmStatus == '1') { - list.push({ - text: '调整为未发起巡视整改流程状态', - icon: 'ant-design:rollback-outlined', - event: 'adj0', - onClick: () => adjustCompletedStage(record, 0), - }); - list.push({ - text: '调整为未发起销号流程状态', - icon: 'ant-design:check-circle-outlined', - event: 'adj2', - onClick: () => adjustCompletedStage(record, 2), - }); - list.push({ - text: '调整为已完成销号流程状态', - icon: 'ant-design:check-circle-outlined', - event: 'adj4', - onClick: () => adjustCompletedStage(record, 4), - }); + // list.push({ + // text: '调整为未发起巡视整改流程状态', + // icon: 'ant-design:rollback-outlined', + // event: 'adj0', + // onClick: () => adjustCompletedStage(record, 0), + // }); + // list.push({ + // text: '调整为未发起销号流程状态', + // icon: 'ant-design:check-circle-outlined', + // event: 'adj2', + // onClick: () => adjustCompletedStage(record, 2), + // }); + // list.push({ + // text: '调整为已完成销号流程状态', + // icon: 'ant-design:check-circle-outlined', + // event: 'adj4', + // onClick: () => adjustCompletedStage(record, 4), + // }); //} return list; } @@ -610,30 +610,8 @@ reload(); } - async function refreshBusinessStatus(records) { - if (!records || records.length === 0) return; - try { - const results = await Promise.all(records.map((item) => getBusinessStatus({ businessId: item.id }).catch(() => null))); - const statusMap: Record = {}; - for (const item of results) { - if (item?.businessId) { - statusMap[item.businessId] = item.status_dictText || ''; - } - } - for (const item of records) { - const status = statusMap[item.id]; - if (status !== undefined) { - item.status_dictText = status; - } - } - } catch (e) { - // 静默处理查询异常 - } - } - async function onFetchSuccess(result) { if (result?.items?.length > 0) { - await refreshBusinessStatus(result.items); setTableData([...getDataSource()]); } } diff --git a/src/views/dq/inspectTask/components/DqInspectTaskBPMForm.vue b/src/views/dq/inspectTask/components/DqInspectTaskBPMForm.vue index 7536aec..804bcbe 100644 --- a/src/views/dq/inspectTask/components/DqInspectTaskBPMForm.vue +++ b/src/views/dq/inspectTask/components/DqInspectTaskBPMForm.vue @@ -245,6 +245,8 @@ import SzDeptUserModal from '/@/components/semri/deptUserComponent/SzDeptUserMod import { usePermission } from '/@/hooks/web/usePermission'; import { PARTY_COMMITTEE_DEPT_ID, SDW_LEADER_ROLE_ID } from '/@/constant/supervision'; import { useSelectNameResolver } from '/@/composables/useSelectNameResolver'; +import { useSubApproveUserResolver } from '/@/composables/useSubApproveUserResolver'; +import { buildDeptLeaderAssignReason, normalizeDeptNames } from '/@/composables/useDefaultApprovalReason'; import TaskHandleInnerContent from '/@/views/super/bpm/process/personalOffice/myHandleTask/content/TaskHandleInnerContent.vue'; import DqInspectTaskBPMFeedbackModal from './DqInspectTaskBPMFeedbackModal.vue'; import SUploadFile from '/@/components/semri/fileComponent/SUploadFile.vue'; @@ -279,8 +281,7 @@ import { useSelectNameResolver } from '/@/composables/useSelectNameResolver'; const showBaseInfoDetail = ref(false); const showFeedbackDetail = ref(true); const feedbackList = ref([]); - const subApproveUser = ref(''); - const subApproveUserNames = ref(''); + const { usernames: subApproveUser, displayNames: subApproveUserNames, setDisplayNames } = useSubApproveUserResolver(); const isEnd = ref(0); const problemTreeData = ref([]); const loadingProblemOptions = ref(false); @@ -408,6 +409,22 @@ import { useSelectNameResolver } from '/@/composables/useSelectNameResolver'; processTableName: props.formData?.processTableName, })); + // ==================== 默认审批意见 ==================== + // 仅覆盖需要动态内容(人名)的节点,其余节点走后端节点配置 + const handleReasonTemplateMap: Record string> = { + // 责任部门领导接受任务并分配 + Task_1c64uvl: () => { + if (isEnd.value === 1) return ''; + return buildDeptLeaderAssignReason(normalizeDeptNames(subApproveUserNames.value)); + }, + }; + + const defaultHandleReason = computed(() => { + const builder = handleReasonTemplateMap[String(processInfo.value.taskDefKey || '')]; + return builder ? builder() : ''; + }); + + provide('formDefaultReason', defaultHandleReason); provide('extraVars', formScope); provide('flowVars', computed(() => props.formData?.vars || {})); @@ -613,7 +630,7 @@ import { useSelectNameResolver } from '/@/composables/useSelectNameResolver'; } function onSubApproveUserConfirm(userIds: string, realnames: string) { - subApproveUserNames.value = realnames || ''; + setDisplayNames(userIds, realnames); } async function saveSubApproveUserVariable(options: { showSuccessMessage?: boolean } = {}) {