Files
supervision-test-frontend-repo/src/views/bg/xispeak/components/BgXiSpeakBPMForm.vue
T

1084 lines
39 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<a-spin :spinning="loading">
<div class="bg-xispeak-bpm-form">
<a-form
class="main-form"
:class="{ 'main-form-readonly': mainDisabled }"
labelAlign="left"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
:model="mainForm"
>
<div class="base-info-header section-toolbar">
<div class="section-title">基础信息</div>
<a-space class="section-actions">
<a-button v-if="!mainDisabled" class="base-save-button" type="link" size="small" :loading="savingMain" @click="submitForm">
<Icon icon="ant-design:save-outlined" />
保存
</a-button>
<a-button
class="section-action-button"
:type="showBaseInfoDetail ? 'default' : 'link'"
size="small"
@click="showBaseInfoDetail = !showBaseInfoDetail"
>
<Icon :icon="showBaseInfoDetail ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
{{ showBaseInfoDetail ? '收起基础信息' : '展开全部信息' }}
</a-button>
</a-space>
</div>
<a-row class="base-info-row" :gutter="[12, 4]">
<a-col :xs="24" :md="12">
<a-form-item label="重要讲话指示批示" name="speakStatus">
<a-textarea v-model:value="mainForm.speakStatus" :auto-size="{ minRows: 1, maxRows: 7 }" :disabled="mainDisabled" allow-clear />
</a-form-item>
</a-col>
<a-col :xs="24" :md="12">
<a-form-item label="学习传达研究部署" name="status">
<a-textarea v-model:value="mainForm.status" :auto-size="{ minRows: 1, maxRows: 7 }" :disabled="mainDisabled" allow-clear />
</a-form-item>
</a-col>
<template v-if="showBaseInfoDetail">
<a-divider />
<a-col :span="12">
<a-form-item label="时间" name="time">
<a-date-picker v-model:value="mainForm.time" value-format="YYYY-MM-DD" :disabled="mainDisabled" style="width: 100%" allow-clear />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="密级" name="secretLevel">
<j-dict-select-tag
v-model:value="mainForm.secretLevel"
dictCode="secret_level"
placeholder="请选择密级"
:disabled="mainDisabled"
allow-clear
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="责任领导" name="responsiblePerson">
<j-select-user v-model:value="mainForm.responsiblePerson" :disabled="mainDisabled" allow-clear />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="企业负责同志批示情况" name="elmComment">
<a-input v-model:value="mainForm.elmComment" :disabled="mainDisabled" allow-clear />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="牵头部门" name="implDept">
<SzSelectDept v-model:value="mainForm.implDept" :disabled="mainDisabled" :multiple="true" checkStrictly allow-clear />
</a-form-item>
</a-col>
<!-- <a-col :span="12">-->
<!-- <a-form-item label="落实方案" name="implPlan">-->
<!-- <a-input v-model:value="mainForm.implPlan" :disabled="mainDisabled" allow-clear />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<a-col :span="12">
<a-form-item label="贯彻落实措施" name="implMeasures">
<a-input v-model:value="mainForm.implMeasures" :disabled="mainDisabled" allow-clear />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="会议决策数" name="numberOfResolutions">
<a-input-number v-model:value="mainForm.numberOfResolutions" :disabled="mainDisabled" style="width: 100%" />
</a-form-item>
</a-col>
<!-- <a-col :span="12">-->
<!-- <a-form-item label="落实条数" name="implCount">-->
<!-- <a-input-number v-model:value="mainForm.implCount" :disabled="mainDisabled" style="width: 100%" />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<!-- <a-col :span="12">-->
<!-- <a-form-item label="已闭环数量" name="closedCount">-->
<!-- <a-input-number v-model:value="mainForm.closedCount" :disabled="mainDisabled" style="width: 100%" />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<a-col :span="12">
<a-form-item label="完成状态" name="completionStatus">
<JDictSelectTag
v-model:value="mainForm.completionStatus"
dictCode="db_status"
placeholder="请选择完成状态"
type="radio"
:stringToNumber="true"
:disabled="mainDisabled"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="截止日期" name="deadline">
<a-date-picker v-model:value="mainForm.deadline" value-format="YYYY-MM-DD" :disabled="mainDisabled" style="width: 100%" allow-clear />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="报告反馈情况" name="reportFeedbackStatus">
<a-input v-model:value="mainForm.reportFeedbackStatus" :disabled="mainDisabled" allow-clear />
</a-form-item>
</a-col>
<!-- <a-col :span="12">-->
<!-- <a-form-item label="是否存在完成风险" name="isCompletionRisk">-->
<!-- <a-radio-group v-model:value="mainForm.isCompletionRisk" :disabled="mainDisabled">-->
<!-- <a-radio :value="0">不存在</a-radio>-->
<!-- <a-radio :value="1">存在</a-radio>-->
<!-- </a-radio-group>-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<a-col :span="12">
<a-form-item label="是否需要督办领导" name="needSdwApproval">
<a-radio-group v-model:value="mainForm.needSdwApproval" :disabled="mainDisabled">
<a-radio :value="1"></a-radio>
<a-radio :value="0"></a-radio>
</a-radio-group>
</a-form-item>
</a-col>
<a-col v-if="mainForm.needSdwApproval === 1" :span="12">
<a-form-item label="督导领导列表" name="sdwLeaderList">
<DeptRoleUserSelectRadioGroup
v-model:value="mainForm.sdwLeaderList"
:deptId="PARTY_COMMITTEE_DEPT_ID"
:roleId="SDW_LEADER_ROLE_ID"
:disabled="mainDisabled"
/>
</a-form-item>
</a-col>
<!-- <a-col :span="12">-->
<!-- <a-form-item label="拖期风险应对措施" name="delayRiskMitigation">-->
<!-- <a-input v-model:value="mainForm.delayRiskMitigation" :disabled="mainDisabled" allow-clear />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<a-col :span="12">
<a-form-item label="督办次数" name="supervisionCount">
<a-input-number v-model:value="mainForm.supervisionCount" :disabled="mainDisabled" style="width: 100%" />
</a-form-item>
</a-col>
<!-- <a-col :span="12">-->
<!-- <a-form-item label="父级节点" name="pid">-->
<!-- <j-tree-select-->
<!-- v-model:value="mainForm.pid"-->
<!-- dict="bg_xi_speak,impl_status,id"-->
<!-- pidField="pid"-->
<!-- pidValue="0"-->
<!-- hasChildField="has_child"-->
<!-- :disabled="mainDisabled"-->
<!-- allow-clear-->
<!-- />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<!-- <a-col :span="12">-->
<!-- <a-form-item label="落实情况" name="implStatus">-->
<!-- <a-textarea v-model:value="mainForm.implStatus" :auto-size="{ minRows: 1, maxRows: 7 }" :disabled="mainDisabled" allow-clear />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
</template>
</a-row>
</a-form>
<a-divider />
<div class="feedback-header section-toolbar" v-if="showFeedbackInfo">
<div class="section-title">办理情况</div>
<a-space class="section-actions">
<a-button v-if="showAddFeedback" class="section-action-button feedback-add-button" type="primary" @click="openFeedbackModal">
<Icon icon="ant-design:plus-outlined" />
新增反馈
</a-button>
<a-button
class="section-action-button"
:type="showFeedbackDetail ? 'default' : 'link'"
size="small"
@click="showFeedbackDetail = !showFeedbackDetail"
>
<Icon :icon="showFeedbackDetail ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
{{ showFeedbackDetail ? '收起办理情况' : '展开办理情况' }}
</a-button>
</a-space>
</div>
<a-table
v-if="showFeedbackInfo && showFeedbackDetail"
rowKey="id"
size="small"
bordered
:columns="feedbackColumns"
:data-source="feedbackList"
:pagination="false"
:scroll="{ x: 1980 }"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'seq'">{{ index + 1 }}</template>
<template v-if="column.key === 'attachments'">
<SUploadFile v-if="record.id" class="feedback-attachment-list" :bussiness-id="record.id" :disabled="true" :multiple="true" />
<span v-else>-</span>
</template>
<template v-if="column.key === 'feedbackAction'">
<a-button type="link" size="small" @click="handleEditFeedback(record)">{{ showJiJianFields && nonJiJianFieldsReadonly ? '督察' : '编辑' }}</a-button>
<a-popconfirm title="确定删除该反馈吗?" @confirm="handleDeleteFeedback(record)">
<a-button type="link" size="small" danger>删除</a-button>
</a-popconfirm>
</template>
</template>
</a-table>
<BgXiSpeakBPMFeedbackModal
ref="feedbackModalRef"
:showJiJianFields="showJiJianFields"
:jiJianFieldsReadonly="jiJianFieldsReadonly"
:nonJiJianFieldsReadonly="nonJiJianFieldsReadonly"
@success="loadFeedbackList"
/>
<template v-if="showProcessHandle">
<a-divider />
<div class="process-header section-toolbar">
<div class="section-title">流程办理</div>
</div>
<a-form v-if="showSubApproveUser" 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="isEnd" :disabled="savingSubApproveUser">
<a-radio :value="0">分配部门经办人</a-radio>
<a-radio :value="1">办结</a-radio>
</a-radio-group>
</a-form-item>
</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" @confirm="setDisplayNames" />
</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"
/>
</template>
</div>
</a-spin>
</template>
<script lang="ts" setup>
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';
import SzSelectDept from '/@/components/Form/src/jeecg/components/SzSelectDept.vue';
import JSelectUser from '/@/components/Form/src/jeecg/components/JSelectUser.vue';
import SzDeptUserModal from '/@/components/semri/deptUserComponent/SzDeptUserModal.vue';
import JTreeSelect from '/@/components/Form/src/jeecg/components/JTreeSelect.vue';
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 { 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';
import SUploadFile from '/@/components/semri/fileComponent/SUploadFile.vue';
import DeptRoleUserSelectRadioGroup from '/@/components/semri/userComponent/DeptRoleUserSelectRadioGroup.vue';
import { PARTY_COMMITTEE_DEPT_ID, SDW_LEADER_ROLE_ID } from '/@/constant/supervision';
import {
buildApproveReason,
buildDeptHandlerFeedbackReason,
buildDeptLeaderAssignReason,
buildDeptLeaderDirectFeedbackReason,
buildSuperviseConfirmAllReason,
buildSuperviseCheckReason,
buildJiJianCheckReason,
normalizeDeptNames,
} from '/@/composables/useDefaultApprovalReason';
const { isDisabledAuth, hasPermission, initBpmFormData } = usePermission();
const userStore = useUserStore();
const props = defineProps({
formDisabled: { type: Boolean, default: false },
formData: { type: Object, default: () => ({}) },
formBpm: { type: Boolean, default: true },
claim: { type: Boolean, default: false },
});
initBpmFormData(props.formData);
console.log('@props.formData', props.formData);
console.log('@props', props);
const emit = defineEmits(['ok', 'success', 'claimSuccess']);
const { createMessage } = useMessage();
const queryByIdUrl = '/bg/xispeak/bgXiSpeak/queryById';
const labelCol = { xs: { span: 24 }, sm: { span: 7 } };
const wrapperCol = { xs: { span: 24 }, sm: { span: 17 } };
const wideLabelCol = { xs: { span: 24 }, sm: { span: 3 } };
const wideWrapperCol = { xs: { span: 24 }, sm: { span: 21 } };
const compactLabelCol = { xs: { span: 24 }, sm: { span: 5 } };
const compactWrapperCol = { xs: { span: 24 }, sm: { span: 19 } };
const feedbackModalRef = ref();
const loading = ref(false);
const savingMain = ref(false);
const savingSubApproveUser = ref(false);
const showBaseInfoDetail = ref(false);
const showFeedbackDetail = ref(true);
const feedbackList = ref<any[]>([]);
const { usernames: subApproveUser, displayNames: subApproveUserNameText, setDisplayNames, initFromData } = useSubApproveUserResolver();
const isEnd = ref(0);
const defaultCcUsers = ref<Array<{ username: string; realname: string }>>([]);
const mainForm = reactive<Record<string, any>>({
id: '',
pid: '',
speakStatus: '',
time: '',
elmComment: '',
status: '',
secretLevel: '',
responsiblePerson: '',
needSdwApproval: 0,
sdwLeaderList: '',
implPlan: '',
implMeasures: '',
numberOfResolutions: undefined,
implStatus: '',
implCount: undefined,
closedCount: undefined,
reportFeedbackStatus: '',
isCompletionRisk: undefined,
delayRiskMitigation: '',
completionStatus: undefined,
deadline: '',
implDept: '',
treeDepth: undefined,
sortOrder: undefined,
bpmStatus: '',
supervisionCount: undefined,
});
const feedbackColumns = computed(() => {
const cols: any[] = [
{ title: '序号', key: 'seq', align: 'center', width: 60 },
{ title: '反馈部门名称', dataIndex: 'responDeptname', align: 'center', width: 140 },
{ title: '反馈人姓名', dataIndex: 'responPersonname', align: 'center', width: 120 },
{ title: '具体措施', dataIndex: 'method', align: 'left', width: 200 },
{ title: '完成状态', dataIndex: 'completionStatus_dictText', align: 'center', width: 100 },
{ title: '是否有报送上级报告', dataIndex: 'isReportedToHigher_dictText', align: 'center', width: 140 },
{ title: '进展情况', dataIndex: 'progress', align: 'left', width: 200 },
// { title: '落实情况', dataIndex: 'implStatus', align: 'left', width: 200 },
{ title: '附件', dataIndex: 'id', key: 'attachments', align: 'left', width: 280 },
];
if (showJiJianFields.value) {
cols.push(
{ title: '检查情况(纪检)', dataIndex: 'checkStatus', align: 'left', width: 160 },
{ title: '监督意见(纪检)', dataIndex: 'inspectionAdvice', align: 'left', width: 160 },
{ title: '措施数量(纪检)', dataIndex: 'measureNum', align: 'center', width: 100 }
);
}
if (showEditFeedback.value) {
cols.push({ title: '操作', dataIndex: 'id', key: 'feedbackAction', align: 'center', width: 120, fixed: 'right' });
}
return cols;
});
const mainDisabled = computed(() => {
if (props.formBpm) {
return props.formData?.disabled !== false;
}
return props.formDisabled;
});
const showProcessHandle = computed(() => {
const explicit = props.formData?.extendUrlParams?.showProcessHandle;
if (explicit === '0') return false;
if (explicit === '1') return true;
return props.formBpm && !!props.formData?.taskId;
});
const showAddFeedback = computed(
() => String(props.formData?.extendUrlParams?.showAddFeedback ?? props.formData?.extendUrlParams?.addfeedback ?? '') === '1'
);
const showFeedbackInfo = computed(() => {
const p = props.formData?.extendUrlParams;
const explicit = p?.showFeedbackInfo ?? p?.showApproveInfo;
if (explicit === '0') return false;
if (explicit === '1') return true;
// 未显式设置时,任一子属性开启则自动显示反馈区域
return (
String(p?.showAddFeedback ?? p?.addfeedback ?? '') === '1' ||
String(p?.showEditFeedback ?? p?.editfeedback ?? '') === '1' ||
String(p?.showDeptFeedback ?? p?.deptfeedback ?? '') === '1'
);
});
const showEditFeedback = computed(
() => String(props.formData?.extendUrlParams?.showEditFeedback ?? props.formData?.extendUrlParams?.editfeedback ?? '') === '1'
);
const showDeptFeedback = computed(
() => String(props.formData?.extendUrlParams?.showDeptFeedback ?? props.formData?.extendUrlParams?.deptfeedback ?? '') === '1'
);
const showJiJianFields = computed(() => String(props.formData?.extendUrlParams?.showJiJianFields ?? '') === '1');
const jiJianFieldsReadonly = computed(() => String(props.formData?.extendUrlParams?.jiJianFieldsReadonly ?? '') === '1');
const nonJiJianFieldsReadonly = computed(() => String(props.formData?.extendUrlParams?.nonJiJianFieldsReadonly ?? '') === '1');
const showSelnextUser = computed(() => String(props.formData?.extendUrlParams?.showSelnextUser ?? '') === '1');
const showDeptFields = computed(() => String(props.formData?.extendUrlParams?.deptfields ?? '') === '1');
const showSubApproveUser = computed(
() => 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,
taskDefKey: props.formData?.taskDefKey,
processInstanceId:
props.formData?.procInsId ||
props.formData?.procInstId ||
props.formData?.processInstanceId ||
props.formData?.vars?.BPM_INST_ID ||
props.formData?.vars?.JG_LOCAL_PROCESS_ID ||
props.formData?.vars?.process_inst_id ||
props.formData?.vars?.processInstanceId,
processDataId: props.formData?.processDataId,
processTableName: props.formData?.processTableName,
}));
// ==================== 默认审批意见 ====================
const handleReasonTemplateMap: Record<string, () => string> = {
// 部门负责人审批 / 所党委审批 / 督办部门负责人审批 / 纪检负责人审批
Task_15sm4w5: buildApproveReason,
Task_00i7rrp: buildApproveReason,
Task_04bazej: buildApproveReason,
Task_0bj578x: buildApproveReason,
Task_0mf32ge: buildApproveReason,
Task_0zmn6ik: buildApproveReason,
Task_133caii: buildApproveReason,
Task_175afz2: buildApproveReason,
Task_1ogk921: buildApproveReason,
Task_1w4vxgc: buildApproveReason,
Task_1wfkrvj: buildApproveReason,
// 反馈流程节点
Task_005iiwi: buildApproveReason,
Task_06di2wf: buildApproveReason,
Task_1l650tz: buildApproveReason,
// 部门经办人反馈完成情况 / 收集流程部门经办人填写 / 反馈流程部门经办人填写反馈
Task_00v3pcv: buildDeptHandlerFeedbackReason,
Task_08zb04x: buildDeptHandlerFeedbackReason,
Task_0jrgrzs: buildDeptHandlerFeedbackReason,
Task_12vdqzv: buildDeptHandlerFeedbackReason,
// 部门负责人接受任务并分配
Task_1v9ce78: () => {
if (isEnd.value === 1) return '';
return buildDeptLeaderAssignReason(normalizeDeptNames(subApproveUserNameText.value));
},
// 部门负责人直接反馈
Task_0sialna: buildDeptLeaderDirectFeedbackReason,
// 督办部门经办人确认全部反馈事项
// (暂无映射,预留 buildSuperviseConfirmAllReason)
// 督办经办人核查 / 反馈流程督办经办人核查
Task_13olnz1: buildSuperviseCheckReason,
// 纪检经办人监察
Task_0bahwr8: buildJiJianCheckReason,
};
const defaultHandleReason = computed(() => {
const builder = handleReasonTemplateMap[String(processInfo.value.taskDefKey || '')];
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();
});
watch(
() => props.formData?.dataId,
() => initFormData()
);
watch(
() => processInfo.value.processInstanceId,
(newVal) => {
if (newVal) loadFeedbackList();
}
);
watch(showDeptFeedback, () => {
loadFeedbackList();
});
watch(
() => props.formData?.vars?.isEnd,
(value) => {
isEnd.value = String(value ?? '0') === '1' ? 1 : 0;
},
{ 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(
() => showDefaultCc.value,
() => {
if (showDefaultCc.value) {
fetchDefaultCcUsers();
} else {
defaultCcUsers.value = [];
}
},
{ immediate: true }
);
async function initFormData() {
const dataId = props.formData?.dataId;
if (!dataId) {
return;
}
showBaseInfoDetail.value = false;
loading.value = true;
try {
const data = await defHttp.get({ url: queryByIdUrl, params: { id: dataId } });
setMainForm(data || {});
await loadFeedbackList();
} finally {
loading.value = false;
}
}
function setMainForm(record: Record<string, any>) {
Object.keys(mainForm).forEach((key) => {
mainForm[key] = record[key] ?? '';
});
// 从 approveInfo JSON 初始化当前部门的 isEnd 和 subApproveUser
const approveInfo = record.approveInfo;
const deptId = getCurrentUserDeptId();
if (approveInfo && deptId && approveInfo[deptId]) {
const detail = approveInfo[deptId];
isEnd.value = detail.isEnd ?? 0;
initFromData(detail.implWorker ?? '');
}
}
async function getProcessVarDeptIds(): Promise<string[]> {
const taskId = props.formData?.taskId;
console.log('【部门过滤】taskId:', taskId, 'processInstanceId:', processInfo.value.processInstanceId);
if (taskId) {
try {
const res = await getProcessVariable({ taskId, key: 'impl_dept_id', isLocal: true });
const value = res?.result?.value ?? res?.value;
if (value) {
const result = String(value).split(',').map((s: string) => s.trim()).filter(Boolean);
console.log('【部门过滤】从流程局部变量 impl_dept_id 获取到:', result);
return result;
}
} catch (e) {
console.log('【部门过滤】获取局部变量 impl_dept_id 失败:', e);
}
}
// 局部变量未找到,尝试从流程级变量获取
const vars = (props.formData?.vars ?? {}) as Record<string, any>;
console.log('【部门过滤】vars所有key:', Object.keys(vars), 'implDept:', vars.implDept, 'pending_depts_id:', vars.pending_depts_id);
const value = vars.implDept ?? vars.pending_depts_id ?? vars.dept_id ?? vars.deptid;
if (value) {
const result = Array.isArray(value)
? value.map((v: any) => String(v).trim()).filter(Boolean)
: String(value).split(',').map((s: string) => s.trim()).filter(Boolean);
console.log('【部门过滤】从流程级变量获取到部门ID:', result);
return result;
}
// 最终 fallback 到主表已保存的牵头部门
if (mainForm.implDept) {
const result = String(mainForm.implDept).split(',').map((s: string) => s.trim()).filter(Boolean);
console.log('【部门过滤】fallback mainForm.implDept:', result);
return result;
}
console.log('【部门过滤】未获取到任何部门ID');
return [];
}
function getCurrentUserDeptId() {
const userInfo = (userStore.getUserInfo || {}) as Record<string, any>;
const loginInfo = (userStore.getLoginInfo || {}) as Record<string, any>;
const departs = Array.isArray(loginInfo.departs) ? loginInfo.departs : [];
if (userInfo.orgCode) {
const dept = departs.find((item: any) => item.orgCode === userInfo.orgCode);
return dept?.id || '';
}
return departs.length === 1 ? departs[0]?.id || '' : '';
}
function getCurrentAssignee() {
const userInfo = (userStore.getUserInfo || {}) as Record<string, any>;
return userInfo.username || '';
}
async function loadFeedbackList() {
const bpmProcessId = processInfo.value.processInstanceId;
if (!mainForm.id || !bpmProcessId) {
feedbackList.value = [];
return;
}
const apiFn = bgXiSpeakFeedbackList;
const res = await apiFn({ mainId: mainForm.id, bpmProcessId, pageNo: 1, pageSize: 999 });
let list = res?.records || res?.result?.records || [];
console.log('【部门过滤】showDeptFeedback:', showDeptFeedback.value, '反馈总数:', list.length);
if (list.length && showDeptFeedback.value) {
const deptIds = await getProcessVarDeptIds();
console.log('【部门过滤】用于过滤的部门ID列表:', deptIds);
if (deptIds.length) {
console.log('【部门过滤】过滤前各反馈的 responDeptid:', list.map((item: any) => ({ id: item.id, responDeptid: item.responDeptid, responDeptname: item.responDeptname })));
list = list.filter((item: any) => {
const responDeptIds = String(item.responDeptid || '')
.split(',')
.map((s: string) => s.trim());
return deptIds.some((id) => responDeptIds.includes(id));
});
console.log('【部门过滤】过滤后剩余:', list.map((item: any) => ({ id: item.id, responDeptid: item.responDeptid, responDeptname: item.responDeptname })));
}
}
feedbackList.value = list;
}
async function submitForm() {
return saveMainForm();
}
async function saveMainForm(options: { showMessage?: boolean; emitOk?: boolean } = {}) {
const { showMessage = true, emitOk = true } = options;
savingMain.value = true;
try {
const processInstanceId = processInfo.value.processInstanceId;
console.log('BgXiSpeak BPM process info', { ...processInfo.value, processInstanceId });
const res = await saveBpmForm({
processInstanceId,
varField: 'json_data',
formData: { ...mainForm },
});
if (res.success) {
if (showMessage) {
createMessage.success(res.message || '保存成功');
}
if (emitOk) {
emit('ok');
}
return true;
}
createMessage.warning(res.message || '保存失败');
return false;
} catch (error) {
createMessage.warning('保存失败');
return false;
} finally {
savingMain.value = false;
}
}
async function saveMainFormBeforeProcessHandle() {
if (!mainDisabled.value) {
const mainSaved = await saveMainForm({ showMessage: false, emitOk: false });
if (!mainSaved) {
return false;
}
}
if (showSubApproveUser.value) {
return saveSubApproveUserVariable({ showSuccessMessage: false });
}
return true;
}
function openFeedbackModal() {
if (!mainForm.id) {
createMessage.warning('主表数据不存在,无法新增反馈');
return;
}
const processInstanceId = processInfo.value.processInstanceId;
if (!processInstanceId) {
createMessage.warning('流程实例ID不能为空,无法新增反馈');
return;
}
feedbackModalRef.value?.open(mainForm.id, mainForm.secretLevel, processInstanceId);
}
function handleEditFeedback(record) {
feedbackModalRef.value?.openEdit(record);
}
async function handleDeleteFeedback(record) {
if (!record.id) {
createMessage.warning('反馈记录ID不存在');
return;
}
await bgXiSpeakFeedbackDelete({ id: record.id }, loadFeedbackList);
}
async function saveSubApproveUserVariable(options: { showSuccessMessage?: boolean } = {}) {
const { showSuccessMessage = true } = options;
const isEndValue = String(isEnd.value);
const usernameValue = normalizeUsernameList(subApproveUser.value);
const deptId = getCurrentUserDeptId();
if (!mainForm.id) {
createMessage.warning('主表ID不能为空');
return false;
}
if (!deptId) {
createMessage.warning('无法获取当前用户部门');
return false;
}
if (isEndValue !== '1' && !usernameValue) {
createMessage.warning('请选择部门经办人');
return false;
}
savingSubApproveUser.value = true;
try {
const params: Record<string, any> = {
mainId: mainForm.id,
deptId,
isEnd: Number(isEndValue),
};
if (isEndValue === '1') {
params.implWorker = getCurrentAssignee();
} else {
params.implUserNameList = usernameValue.split(',').filter(Boolean);
}
const res = await saveSubApprove(params);
if (!res?.success) {
createMessage.warning(res?.message || '保存失败');
return false;
}
if (showSuccessMessage) {
createMessage.success('保存成功');
}
return true;
} catch (error) {
createMessage.warning('保存失败');
return false;
} finally {
savingSubApproveUser.value = false;
}
}
function normalizeUsernameList(value: string) {
return String(value || '')
.split(',')
.map((item) => item.trim())
.filter(Boolean)
.join(',');
}
function handleProcessSuccess() {
emit('success');
}
function handleClaimSuccess() {
emit('claimSuccess');
}
defineExpose({
submitForm,
initFormData,
loadFeedbackList,
});
</script>
<style lang="less" scoped>
.bg-xispeak-bpm-form {
padding: 8px 12px 14px;
}
.main-form {
background: #fff;
}
.main-form,
.process-variable-form {
:deep(.ant-form-item-label) {
text-align: left;
}
:deep(.ant-form-item-label > label) {
justify-content: flex-start;
color: #1f2937;
font-weight: 500;
}
:deep(.ant-form-item-control),
:deep(.ant-form-item-control-input),
:deep(.ant-form-item-control-input-content) {
text-align: left;
}
}
.section-title {
margin-bottom: 8px;
padding-left: 8px;
border-left: 3px solid #1677ff;
color: #1f2937;
font-size: 14px;
font-weight: 600;
line-height: 16px;
}
.section-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
padding: 6px 10px;
background: #f6fbff;
border: 1px solid #d6e8ff;
border-radius: 6px;
.section-title {
margin-bottom: 0;
}
.section-actions {
display: inline-flex;
align-items: center;
gap: 4px;
}
.section-action-button {
display: inline-flex;
align-items: center;
gap: 4px;
min-width: 58px;
justify-content: center;
font-weight: 500;
box-shadow: none;
}
.base-save-button {
display: inline-flex;
align-items: center;
gap: 4px;
height: 24px;
padding: 0 6px;
color: #64748b;
font-weight: 400;
}
}
.base-info-header {
margin-top: 0;
}
.base-info-row {
padding: 0 10px;
:deep(.ant-form-item) {
margin-bottom: 6px;
}
:deep(.ant-form-item-label) {
padding-bottom: 0;
}
:deep(.ant-form-item-label > label) {
width: 100%;
}
:deep(.ant-input),
:deep(.ant-input-number),
:deep(.ant-picker),
:deep(.ant-select-selector) {
min-height: 30px;
}
}
.main-form-readonly {
:deep(.ant-input[disabled]),
:deep(.ant-input-disabled),
:deep(.ant-input-affix-wrapper-disabled),
:deep(.ant-input-affix-wrapper-disabled.ant-input-outlined),
:deep(.ant-input-affix-wrapper-disabled:hover),
:deep(.ant-input-affix-wrapper-disabled:focus),
:deep(.ant-input-affix-wrapper-disabled-focused),
:deep(.ant-input-outlined[disabled]),
:deep(.ant-input-outlined.ant-input-disabled),
:deep(textarea.ant-input[disabled]),
:deep(.ant-input-number-disabled),
:deep(.ant-input-number-disabled:hover),
:deep(.ant-input-number-disabled:focus),
:deep(.ant-picker-disabled),
:deep(.ant-select-disabled .ant-select-selector) {
background: transparent !important;
border-color: transparent !important;
color: #1f2937 !important;
box-shadow: none !important;
cursor: default !important;
opacity: 1 !important;
}
:deep(.ant-input[disabled]),
:deep(.ant-input-disabled),
:deep(.ant-input-affix-wrapper-disabled),
:deep(.ant-input-number-disabled),
:deep(textarea.ant-input[disabled]) {
padding-left: 0 !important;
padding-right: 0 !important;
}
:deep(.ant-input-affix-wrapper-disabled .ant-input) {
background: transparent !important;
color: #1f2937 !important;
cursor: default !important;
}
:deep(.ant-input-number-disabled .ant-input-number-input) {
background: transparent !important;
color: #1f2937 !important;
-webkit-text-fill-color: #1f2937 !important;
cursor: default !important;
}
:deep(.ant-input[disabled]::placeholder),
:deep(.ant-input-disabled::placeholder),
:deep(.ant-input-affix-wrapper-disabled .ant-input::placeholder) {
color: #9ca3af !important;
}
:deep(.ant-picker-disabled input),
:deep(.ant-select-disabled .ant-select-selection-item),
:deep(.ant-select-disabled .ant-select-selection-item span),
:deep(.ant-select-disabled .ant-select-selection-placeholder),
:deep(.ant-select-disabled .ant-select-selection-placeholder span) {
color: #1f2937 !important;
-webkit-text-fill-color: #1f2937 !important;
cursor: default !important;
}
:deep(.ant-picker-disabled),
:deep(.ant-select-disabled .ant-select-selector) {
padding-left: 0 !important;
}
:deep(.ant-select-disabled),
:deep(.ant-select-disabled *),
:deep(.ant-select-disabled.ant-select-outlined),
:deep(.ant-select-disabled.ant-select-outlined .ant-select-selector) {
color: #1f2937 !important;
-webkit-text-fill-color: #1f2937 !important;
opacity: 1 !important;
}
:deep(.ant-select-disabled .ant-select-arrow),
:deep(.ant-picker-disabled .ant-picker-suffix),
:deep(.ant-input-disabled .ant-input-clear-icon),
:deep(.ant-input-affix-wrapper-disabled .ant-input-clear-icon),
:deep(.ant-input-number-disabled .ant-input-number-handler-wrap),
:deep(.ant-select-disabled .ant-select-clear) {
display: none;
}
:deep(.ant-radio-wrapper-disabled) {
color: #1f2937 !important;
cursor: default !important;
}
:deep(.ant-radio-wrapper-disabled:not(.ant-radio-wrapper-checked)) {
display: none;
}
:deep(.ant-radio-disabled .ant-radio-inner) {
display: none;
}
}
.feedback-header {
margin-bottom: 8px;
.feedback-add-button {
min-width: 104px;
}
}
.process-variable-form {
margin-bottom: 8px;
}
.sub-approve-user-row {
display: flex;
width: 100%;
:deep(.ant-input-affix-wrapper),
:deep(.ant-input) {
min-width: 280px;
}
}
:deep(.ant-divider-horizontal) {
margin: 10px 0;
}
.feedback-attachment-list {
min-width: 240px;
:deep(.file-list-wrapper) {
min-height: 36px;
max-height: 130px;
overflow-y: auto;
padding: 4px 8px;
}
:deep(.file-list-header) {
margin-bottom: 6px;
padding-bottom: 6px;
}
:deep(.file-list .file-item) {
padding: 8px;
margin-bottom: 6px;
}
:deep(.ant-empty) {
margin: 0;
padding: 4px 0;
.ant-empty-image {
display: none;
}
.ant-empty-description {
font-size: 12px;
color: #999;
padding: 0;
margin: 0;
}
}
}
</style>