feat(bpm): 抽取 useSubApproveUserResolver 统一 username→realname 解析,修复 isEnd 切换时审批意见不响应
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -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<string, string> = {};
|
||||
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 };
|
||||
}
|
||||
@@ -246,7 +246,7 @@
|
||||
</a-col>
|
||||
<a-col v-if="showSubApproveUserSelector" :span="12">
|
||||
<a-form-item label="部门经办人" :labelCol="wideLabelCol" :wrapperCol="wideWrapperCol">
|
||||
<sz-dept-user-modal v-model:value="subApproveUser" :disabled="savingSubApproveUser" />
|
||||
<sz-dept-user-modal v-model:value="subApproveUser" :disabled="savingSubApproveUser" @confirm="setDisplayNames" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
@@ -278,7 +278,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,9 +328,7 @@ import {
|
||||
const showBaseInfoDetail = ref(false);
|
||||
const showFeedbackDetail = ref(true);
|
||||
const feedbackList = ref<any[]>([]);
|
||||
const subApproveUser = ref('');
|
||||
const subApproveUserNameText = ref('');
|
||||
const userResolveVersion = ref(0);
|
||||
const { usernames: subApproveUser, displayNames: subApproveUserNameText, setDisplayNames, initFromData } = useSubApproveUserResolver();
|
||||
const isEnd = ref(0);
|
||||
|
||||
const mainForm = reactive<Record<string, any>>({
|
||||
@@ -469,9 +467,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,14 +524,13 @@ import {
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
subApproveUser,
|
||||
(value) => {
|
||||
resolveSubApproveUserName(value);
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
watch(isEnd, (val) => {
|
||||
const vars = props.formData?.vars;
|
||||
if (vars) {
|
||||
vars.is_end = String(val);
|
||||
vars.isEnd = String(val);
|
||||
}
|
||||
});
|
||||
|
||||
async function initFormData() {
|
||||
const dataId = props.formData?.dataId;
|
||||
@@ -560,7 +558,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 +769,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<string, string>, 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');
|
||||
|
||||
@@ -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<any[]>([]);
|
||||
const subApproveUser = ref('');
|
||||
const subApproveUserNames = ref('');
|
||||
const { usernames: subApproveUser, displayNames: subApproveUserNames, setDisplayNames } = useSubApproveUserResolver();
|
||||
const isEnd = ref(0);
|
||||
const problemTreeData = ref<any[]>([]);
|
||||
const loadingProblemOptions = ref(false);
|
||||
@@ -408,6 +409,22 @@ import { useSelectNameResolver } from '/@/composables/useSelectNameResolver';
|
||||
processTableName: props.formData?.processTableName,
|
||||
}));
|
||||
|
||||
// ==================== 默认审批意见 ====================
|
||||
// 仅覆盖需要动态内容(人名)的节点,其余节点走后端节点配置
|
||||
const handleReasonTemplateMap: Record<string, () => 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 } = {}) {
|
||||
|
||||
Reference in New Issue
Block a user