!74 fix(bpm): 修复选人组件 Name 翻译使用错误字段及查询顺序问题

* fix(bpm): 修复选人组件 Name 翻译使用错误字段及查询顺序问题
* feat(bpm): 默认审批意见改为完全由后端节点配置驱动,移除所有写死模板
* fix(bpm): 修复节点默认审批意见配置 UI 绑定错误,支持 extraVars 变量解析
* feat(bpm): 新增条件变量默认审批意见,支持按流程变量值动态预填审批意见
This commit is contained in:
wsm
2026-07-01 11:07:18 +00:00
parent 08a29734a8
commit 4df8b3e31d
10 changed files with 326 additions and 82 deletions
@@ -266,7 +266,7 @@
</template>
<script lang="ts" setup>
import { computed, onMounted, reactive, ref, watch } from 'vue';
import { computed, onMounted, reactive, ref, watch, provide } from 'vue';
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
@@ -487,6 +487,18 @@ import {
return builder ? builder() : '';
});
// 合并 mainForm + 表单局部变量,供占位符 ${变量名} 解析
const formScope = computed(() => ({
...mainForm,
isEnd: isEnd.value,
subApproveUser: subApproveUser.value,
subApproveUserNameText: subApproveUserNameText.value,
}));
provide('extraVars', formScope);
provide('flowVars', computed(() => props.formData?.vars || {}));
provide('formDefaultReason', defaultHandleReason);
onMounted(() => {
initFormData();
});
@@ -72,17 +72,17 @@
</a-col>
<a-col :span="12">
<a-form-item label="措施责任领导" name="measureResLeader">
<j-select-user v-model:value="mainForm.measureResLeader" :disabled="mainDisabled" allow-clear />
<j-select-user v-model:value="mainForm.measureResLeader" :disabled="mainDisabled" allow-clear @select="selectHandler('measureResLeader')" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="措施责任部门" name="measureResDept">
<j-select-dept v-model:value="mainForm.measureResDept" :disabled="mainDisabled" :multiple="true" checkStrictly allow-clear />
<j-select-dept v-model:value="mainForm.measureResDept" :disabled="mainDisabled" :multiple="true" checkStrictly allow-clear @select="selectHandler('measureResDept')" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="分管所领导" name="chargeLeaderId">
<j-select-user v-model:value="mainForm.chargeLeaderId" :disabled="mainDisabled" allow-clear />
<j-select-user v-model:value="mainForm.chargeLeaderId" :disabled="mainDisabled" allow-clear @select="selectHandler('chargeLeaderId')" />
</a-form-item>
</a-col>
<a-col :span="12">
@@ -102,7 +102,7 @@
</a-col>
<a-col :span="12">
<a-form-item label="党群领导" name="supDeptleaderid">
<j-select-user v-model:value="mainForm.supDeptleaderid" :disabled="mainDisabled" allow-clear />
<j-select-user v-model:value="mainForm.supDeptleaderid" :disabled="mainDisabled" allow-clear @select="selectHandler('supDeptleaderid')" />
</a-form-item>
</a-col>
<a-col :span="12">
@@ -194,34 +194,33 @@
</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" />
</a-form-item>
</a-col>
</a-row>
</a-form>
<a-form v-if="showIsNeedLeaderApprove" class="process-variable-form" labelAlign="left" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="是否需要所领导审批" :labelCol="wideLabelCol" :wrapperCol="wideWrapperCol">
<a-radio-group v-model:value="isNeedLeaderApprove" :disabled="savingIsNeedLeaderApprove">
<a-radio :value="0">不需要</a-radio>
<a-radio :value="1">需要所领导审批</a-radio>
</a-radio-group>
</a-form-item>
</a-col>
<a-col v-if="showIsNeedLeaderApproveSelector" :span="12">
<a-form-item label="分管所领导" :labelCol="wideLabelCol" :wrapperCol="wideWrapperCol">
<j-select-user v-model:value="leaderApproveUser" :disabled="savingIsNeedLeaderApprove" allow-clear />
<sz-dept-user-modal v-model:value="subApproveUser" :disabled="savingSubApproveUser" @confirm="onSubApproveUserConfirm" />
</a-form-item>
</a-col>
</a-row>
</a-form>
<!-- <a-form v-if="showIsNeedLeaderApprove" class="process-variable-form" labelAlign="left" :labelCol="labelCol" :wrapperCol="wrapperCol">-->
<!-- <a-row :gutter="16">-->
<!-- <a-col :span="12">-->
<!-- <a-form-item label="是否需要所领导审批" :labelCol="wideLabelCol" :wrapperCol="wideWrapperCol">-->
<!-- <a-radio-group v-model:value="isNeedLeaderApprove" :disabled="savingIsNeedLeaderApprove">-->
<!-- <a-radio :value="0">不需要</a-radio>-->
<!-- <a-radio :value="1">需要所领导审批</a-radio>-->
<!-- </a-radio-group>-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<!-- <a-col v-if="showIsNeedLeaderApproveSelector" :span="12">-->
<!-- <a-form-item label="分管所领导" :labelCol="wideLabelCol" :wrapperCol="wideWrapperCol">-->
<!-- <j-select-user v-model:value="leaderApproveUser" :disabled="savingIsNeedLeaderApprove" allow-clear @select="selectHandler('leaderApproveUser')" />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<!-- </a-row>-->
<!-- </a-form>-->
<TaskHandleInnerContent
:form-data="formData"
:claim="claim"
:showSelnextUser="showSelnextUser"
:beforeHandle="saveMainFormBeforeProcessHandle"
:defaultReason="defaultHandleReason"
:defaultCc="defaultCcUsers"
@success="handleProcessSuccess"
@claimSuccess="handleClaimSuccess"
@@ -232,7 +231,7 @@
</template>
<script lang="ts" setup>
import { computed, onMounted, reactive, ref, watch } from 'vue';
import { computed, onMounted, reactive, ref, watch, provide } from 'vue';
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { useUserStore } from '/@/store/modules/user';
@@ -245,23 +244,7 @@ import SzDeptUserModal from '/@/components/semri/deptUserComponent/SzDeptUserMod
import { list as progressList, deleteOne as progressDelete } from '../../inspectProgress/DqInspectProgress.api';
import { usePermission } from '/@/hooks/web/usePermission';
import { PARTY_COMMITTEE_DEPT_ID, SDW_LEADER_ROLE_ID } from '/@/constant/supervision';
import {
buildApproveReason,
buildDeptHandlerFeedbackReason,
buildCollectDoneReason,
buildSecretaryApprovedReason,
buildDisciplineSecretaryApprovedReason,
buildDeptLeaderApprovedReason,
buildChargeDeptApprovedReason,
buildChargeLeaderApprovedReason,
buildAlreadyApprovedReason,
buildAlreadyReviewedReason,
buildPleaseDeptHandleReason,
buildLaunchSupervisionReason,
buildPartyMassesConfirmedReason,
buildAssignProcessReason,
buildJiJianCheckedReason,
} from '/@/composables/useDefaultApprovalReason';
import { useSelectNameResolver } from '/@/composables/useSelectNameResolver';
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';
@@ -297,6 +280,7 @@ import {
const showFeedbackDetail = ref(true);
const feedbackList = ref<any[]>([]);
const subApproveUser = ref('');
const subApproveUserNames = ref('');
const isEnd = ref(0);
const problemTreeData = ref<any[]>([]);
const loadingProblemOptions = ref(false);
@@ -305,32 +289,6 @@ import {
const savingIsNeedLeaderApprove = ref(false);
const defaultCcUsers = ref<Array<{ username: string; realname: string }>>([]);
const handleReasonTemplateMap: Record<string, () => string> = {
Task_0g8sc6n: buildApproveReason,
Task_0ixi1rs: buildCollectDoneReason,
Task_0l5ik22: buildApproveReason,
Task_0mbr735: buildDeptHandlerFeedbackReason,
Task_0mxtg05: buildAlreadyApprovedReason,
Task_14226iy: buildAlreadyReviewedReason,
Task_1c64uvl: buildPleaseDeptHandleReason,
Task_1i99s6v: buildApproveReason,
Task_1nj4k7b: buildLaunchSupervisionReason,
Task_09qxoto: buildDisciplineSecretaryApprovedReason,
Task_0cfjknn: buildSecretaryApprovedReason,
Task_0r2vutj: buildChargeDeptApprovedReason,
Task_1azpeqj: buildJiJianCheckedReason,
Task_1cvft2f: buildPartyMassesConfirmedReason,
Task_1k1zt37: buildChargeLeaderApprovedReason,
Task_1k36lmv: buildDeptLeaderApprovedReason,
Task_1k6n75g: buildAssignProcessReason,
};
const defaultHandleReason = computed(() => {
const builder = handleReasonTemplateMap[String(processInfo.value.taskDefKey || '')];
return builder ? builder() : '';
});
const mainForm = reactive<Record<string, any>>({
id: '',
problemId: '',
@@ -339,12 +297,16 @@ import {
deadline: '',
targetNode: '',
measureResLeader: '',
measureResLeaderNames: '',
measureResDept: '',
measureResDeptNames: '',
chargeLeaderId: '',
chargeLeaderIdNames: '',
rectificationEvidence: '',
evaluationCriterion: '',
isNeedAppro: '',
supDeptleaderid: '',
supDeptleaderidNames: '',
inspectionStatus: '',
supervisoryOpinion: '',
measureCount: undefined,
@@ -353,8 +315,28 @@ import {
taskStatus: '',
superviseCount: '',
sortNo: undefined,
leaderApproveUserNames: '',
});
// 选人/选部门 ID→Name 翻译
const { resolveAll, selectHandler } = useSelectNameResolver(mainForm, [
{ field: 'measureResDept', type: 'dept' },
{ field: 'measureResLeader', type: 'user' },
{ field: 'chargeLeaderId', type: 'user' },
{ field: 'supDeptleaderid', type: 'user' },
{ field: 'leaderApproveUser', type: 'user', getValue: () => leaderApproveUser.value },
]);
// 合并 mainForm + 表单局部变量,供占位符 ${变量名} 解析
const formScope = computed(() => ({
...mainForm,
isEnd: isEnd.value,
subApproveUser: subApproveUser.value,
subApproveUserNames: subApproveUserNames.value,
isNeedLeaderApprove: isNeedLeaderApprove.value,
leaderApproveUser: leaderApproveUser.value,
}));
const feedbackColumns = computed(() => {
const cols: any[] = [
{ title: '序号', key: 'seq', align: 'center', width: 60 },
@@ -426,6 +408,9 @@ import {
processTableName: props.formData?.processTableName,
}));
provide('extraVars', formScope);
provide('flowVars', computed(() => props.formData?.vars || {}));
onMounted(() => {
initFormData();
});
@@ -443,6 +428,14 @@ import {
},
{ immediate: true }
);
// 反向同步:本地切换 isEnd 时更新 formData.vars,使 conditionalDefaultOpinion 响应
watch(isEnd, (val) => {
const vars = props.formData?.vars;
if (vars) {
vars.is_end = String(val);
vars.isEnd = String(val);
}
});
watch(
() => props.formData?.vars?.isNeedLeaderApprove,
@@ -451,6 +444,14 @@ import {
},
{ immediate: true }
);
// 反向同步:本地切换 isNeedLeaderApprove 时更新 formData.vars
watch(isNeedLeaderApprove, (val) => {
const vars = props.formData?.vars;
if (vars) {
vars.is_need_leader_approve = String(val);
vars.isNeedLeaderApprove = String(val);
}
});
async function fetchDefaultCcUsers() {
try {
@@ -503,6 +504,7 @@ import {
const data = await defHttp.get({ url: queryByIdUrl, params: { id: dataId } });
setMainForm(data || {});
leaderApproveUser.value = mainForm.chargeLeaderId || '';
await resolveAll();
await loadFeedbackList();
} finally {
loading.value = false;
@@ -614,6 +616,10 @@ import {
await progressDelete({ id: record.id }, loadFeedbackList);
}
function onSubApproveUserConfirm(userIds: string, realnames: string) {
subApproveUserNames.value = realnames || '';
}
async function saveSubApproveUserVariable(options: { showSuccessMessage?: boolean } = {}) {
const { showSuccessMessage = true } = options;
const processInstanceId = processInfo.value.processInstanceId;
@@ -114,7 +114,7 @@
</template>
<script>
import { ref, reactive, computed, toRaw, unref, watch, watchEffect } from 'vue';
import { ref, reactive, computed, toRaw, unref, watch, watchEffect, inject } from 'vue';
import { initDictOptions } from '/@/utils/dict';
import { useMessage } from '/@/hooks/web/useMessage';
import { taskComplaint, taskComplete, beforeAddSignTask, afterAddSignTask, addMultiInstance} from "../task.handle.api";
@@ -216,6 +216,19 @@
*/
const selectUserType = ref('');
const remarksDictOptions = ref([]);
const extraVars = inject('extraVars', ref({}));
const flowVars = inject('flowVars', ref({}));
function resolvePlaceholders(text) {
if (!text) return '';
const extra = extraVars.value || {};
const flow = flowVars.value || {};
return text.replace(/\$\{(\w+)\}/g, (_, key) => {
if (key in extra) return String(extra[key] ?? '');
return String(flow[key] ?? '');
});
}
const historyCount = computed(() => {
return props.historyList.length;
});
@@ -264,9 +277,17 @@
return false;
}
const formDefaultReason = inject('formDefaultReason', ref(''));
// 表单写死 > 节点配置(props.defaultReason 来自 TaskHandleInnerContent 的节点优先级链)
const resolvedDefaultReason = computed(() => {
const opinion = formDefaultReason.value || props.defaultReason;
return resolvePlaceholders(opinion);
});
// 默认处理意见只在空值或仍为上一条自动意见时刷新,避免覆盖用户手动输入。
watch(
() => props.defaultReason,
resolvedDefaultReason,
(value) => {
if (isRejectProcessModel(model.processModel)) {
return;
@@ -279,7 +300,7 @@
() => model.processModel,
(value) => {
const isReject = isRejectProcessModel(value);
applyAutoReason(isReject ? REJECT_DEFAULT_REASON : props.defaultReason, [
applyAutoReason(isReject ? REJECT_DEFAULT_REASON : resolvedDefaultReason.value, [
isReject ? props.defaultReason : REJECT_DEFAULT_REASON,
]);
}
@@ -20,7 +20,7 @@
:allowCounterSignAddUser="allowCounterSignAddUser"
:allowReject="allowReject"
:beforeHandle="beforeHandle"
:defaultReason="defaultReason"
:defaultReason="conditionalDefaultOpinion || nodeDefaultOpinion || defaultReason"
:defaultCc="defaultCc"
:currentTaskName="currentNode.taskName">
</my-handle-content>
@@ -34,7 +34,7 @@
<script lang="ts">
import { taskTransInfo, taskComplete, taskClaim } from '../task.handle.api';
import { ref, watch } from 'vue';
import { ref, watch, computed } from 'vue';
import TaskNodeStepList from './TaskNodeStepList.vue';
import TaskCommentList from './TaskCommentList.vue';
import MyHandleContent from './MyHandleContent.vue';
@@ -102,6 +102,24 @@
const selnextUserStatus = ref(true);
// 选择抄送人
const ccStatus = ref(true);
// 节点配置的默认审批意见
const nodeDefaultOpinion = ref('');
// 条件变量默认审批意见
const condOpinionVar = ref(''); // 条件变量名 — API: data.defaultOpinionVar
const condOpinionWhen0 = ref(''); // 变量=0时的意见 — API: data.defaultOpinionCond0
const condOpinionWhen1 = ref(''); // 变量=1时的意见 — API: data.defaultOpinionCond1
// 条件变量 > 节点默认 > 表单传入
const conditionalDefaultOpinion = computed(() => {
const varName = condOpinionVar.value;
if (!varName) return '';
const vars = props.formData?.vars;
if (!vars) return '';
const varValue = String(vars[varName] ?? '');
if (varValue === '0') return condOpinionWhen0.value;
if (varValue === '1') return condOpinionWhen1.value;
return '';
});
getTaskTransInfo();
@@ -139,6 +157,12 @@
allowReject.value = data?.rejectStatus == '1';
//是否多实例- 会签加签 是否允许会签节点加人0否、1允许
allowCounterSignAddUser.value = (data?.allowCounterSignAddUser && data.allowCounterSignAddUser =='1');
//节点配置的默认审批意见
nodeDefaultOpinion.value = data?.defaultOpinion || '';
//条件变量默认审批意见
condOpinionVar.value = data?.defaultOpinionVar || '';
condOpinionWhen0.value = data?.defaultOpinionCond0 || '';
condOpinionWhen1.value = data?.defaultOpinionCond1 || '';
taskStepList.value = data.bpmLogStepList;
bpmLogList.value = data.bpmLogList;
@@ -204,7 +228,9 @@
allowCounterSignAddUser,
allowReject,
selnextUserStatus,
turnbackTaskId
turnbackTaskId,
nodeDefaultOpinion,
conditionalDefaultOpinion
};
},
};
@@ -67,7 +67,7 @@
const [registerNodeModal, { openModal: openNodeModal }] = useModal();
const [registerNodeAuthModal, { openModal: openNodeAuthModal }] = useModal();
function addQueryParams(params) {
params.processId = props.processId;
@@ -145,7 +145,7 @@
},
];
}
function openAuthModal(isNewAuthModal, row) {
if(isNewAuthModal===true){
openNodeAuthModal(true, row);
@@ -36,7 +36,24 @@
<question-circle-outlined style="color: rgb(110 110 110)"/>
</a-tooltip>
</template>
<template #defaultOpinionBlock="{ model, field }">
<div class="opinion-block">
<div class="opinion-switch-row">
<span>是否生成默认审批意见</span>
<a-switch v-model:checked="model.enableDefaultOpinion" checked-children="" un-checked-children="" />
</div>
<template v-if="model.enableDefaultOpinion">
<div class="opinion-cond-label">条件变量名</div>
<a-input v-model:value="model.defaultOpinionVar" placeholder="条件变量名,如 approval_result,值为 0 或 1" style="margin-bottom: 12px;" />
<div class="opinion-cond-label">默认审批意见变量 = 0</div>
<a-textarea v-model:value="model.defaultOpinion" :rows="2" placeholder="变量值=0 时的默认审批意见" style="margin-bottom: 12px;" />
<div class="opinion-cond-label">默认审批意见变量 = 1</div>
<a-textarea v-model:value="model.defaultOpinion2" :rows="2" placeholder="变量值=1 时的默认审批意见" />
</template>
</div>
</template>
</BasicForm>
</BasicModal>
</template>
@@ -48,7 +65,7 @@
import { nodeFormSchema } from './process.node.data';
import { saveOrUpdate } from './process.node.api';
import { QuestionCircleOutlined } from '@ant-design/icons-vue';
export default {
name: 'ProcessNodeModal',
components: {
@@ -94,7 +111,7 @@
//update-end-author:taoyan date:2023-2-14 for: QQYUN-4266【老版流程】新增节点 节点名称和编码不能输入,子流程无法添加start节点
} else {
delete data.isUpdate;
setFieldsValue({ ...data });
setFieldsValue({ ...data, enableDefaultOpinion: !!(data.defaultOpinion || data.defaultOpinionVar) });
//update-begin-author:taoyan date:2023-2-14 for: QQYUN-4266【老版流程】新增节点 节点名称和编码不能输入,子流程无法添加start节点
await updateSchema([
{
@@ -119,7 +136,7 @@
emit('success');
closeModal();
}
const designerUrl = "3.表单设计器:{{DOMAIN_URL}}/desform/edit/设计器编码/${BPM_DES_DATA_ID}?token={{TOKEN}}&taskId={{TASKID}}"
return {
@@ -142,9 +159,28 @@
}
}
</style>
<style scoped>
<style scoped lang="less">
:deep(.ant-modal-body) {
padding-bottom: 5px !important;
padding-top: 5px !important;
}
.opinion-block {
background-color: #eee;
border-radius: 10px;
padding: 10px;
.opinion-switch-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
span {
font-size: 14px;
}
}
.opinion-cond-label {
font-size: 13px;
color: #4b4a4a;
margin-bottom: 4px;
}
}
</style>
@@ -104,4 +104,29 @@ export const nodeFormSchema: FormSchema[] = [
component: 'Input',
slot: 'nodeTimeout',
},
{
label: '是否生成默认审批意见',
field: 'enableDefaultOpinion',
component: 'Switch',
defaultValue: false,
show: false,
},
{
label: '条件变量名',
field: 'defaultOpinionVar',
component: 'Input',
show: false,
},
{
label: '默认审批意见(变量=1',
field: 'defaultOpinion2',
component: 'InputTextArea',
show: false,
},
{
label: '默认审批意见',
field: 'defaultOpinion',
component: 'InputTextArea',
slot: 'defaultOpinionBlock',
},
];
@@ -132,6 +132,7 @@
/>
</span>
</div>
</a-tab-pane>
</a-tabs>
</a-spin>