Merge branch 'refs/heads/master' into wsq-20260727
This commit is contained in:
@@ -16,6 +16,10 @@ enum Api {
|
||||
improvementInstituteVoteList = '/improvementproposal/improvementProposal/queryImprovementInstituteVoteByMainId',
|
||||
getLatestProposalSequence = '/improvementproposal/improvementProposal/getLatestProposalSequence',
|
||||
startProcess = '/improvementproposal/improvementProposal/startProcess',
|
||||
bpmInitialReview = '/improvementproposal/improvementProposal/bpm/initialReview',
|
||||
bpmLeaderAward = '/improvementproposal/improvementProposal/bpm/leaderAward',
|
||||
bpmArchiveAward = '/improvementproposal/improvementProposal/bpm/archiveAward',
|
||||
bpmInstituteVote = '/improvementproposal/improvementProposal/bpm/instituteVote',
|
||||
}
|
||||
/**
|
||||
* 导出api
|
||||
@@ -95,3 +99,9 @@ export const getLatestProposalSequence = (year) => defHttp.get({url: Api.getLate
|
||||
|
||||
/** 发起改善提案审批流程。 */
|
||||
export const startProposalProcess = (id: string) => defHttp.post({ url: Api.startProcess, params: { id } });
|
||||
|
||||
/** 流程节点专用接口会在任务提交前保存业务字段和网关变量。 */
|
||||
export const saveInitialReview = (params) => defHttp.post({ url: Api.bpmInitialReview, params });
|
||||
export const saveLeaderAward = (params) => defHttp.post({ url: Api.bpmLeaderAward, params });
|
||||
export const saveArchiveAward = (params) => defHttp.post({ url: Api.bpmArchiveAward, params });
|
||||
export const castInstituteVote = (params) => defHttp.post({ url: Api.bpmInstituteVote, params });
|
||||
|
||||
@@ -1,76 +1,316 @@
|
||||
<template>
|
||||
<a-spin :spinning="loading">
|
||||
<section class="improvement-proposal-bpm-form">
|
||||
<a-descriptions title="改善提案" bordered size="small" :column="2">
|
||||
<div class="section-header">
|
||||
<span>基本信息</span>
|
||||
</div>
|
||||
<a-descriptions bordered size="small" :column="2">
|
||||
<a-descriptions-item label="提案编号">{{ proposal.proposalNo || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="提案名称">{{ proposal.proposalName || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="提出日期">{{ proposal.proposalDate || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="提出日期">{{ formatDate(proposal.proposalDate) }}</a-descriptions-item>
|
||||
<a-descriptions-item label="提案类别">{{ proposal.proposalCategory || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="提案部门">{{ proposal.proposalDeptName || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="申请人">{{ proposal.applicantName || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="团队名称">{{ proposal.teamName || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="最终奖项">{{ proposal.finalAward || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="团队名称" :span="2">{{ proposal.teamName || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="问题描述" :span="2">{{ proposal.problemDesc || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="改善方法及措施" :span="2">{{ proposal.improvementMethod || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="改善前情况描述" :span="2">{{ proposal.beforeDesc || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="改善后情况描述" :span="2">{{ proposal.afterDesc || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="改善前情况" :span="2">{{ proposal.beforeDesc || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="改善后情况" :span="2">{{ proposal.afterDesc || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="改善效果" :span="2">{{ proposal.improvementEffect || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="附件" :span="2">
|
||||
<div v-if="proposal.id" class="attachment-grid">
|
||||
<div>
|
||||
<div class="attachment-label">改善前附件</div>
|
||||
<SUploadFile :bussiness-id="`${proposal.id}:before`" :disabled="true" :multiple="true" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="attachment-label">改善后附件</div>
|
||||
<SUploadFile :bussiness-id="`${proposal.id}:after`" :disabled="true" :multiple="true" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="attachment-label">其他附件</div>
|
||||
<SUploadFile :bussiness-id="`${proposal.id}:other`" :disabled="true" :multiple="true" />
|
||||
</div>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<template v-if="showProcessHandle">
|
||||
<a-divider />
|
||||
<div class="section-header">
|
||||
<span>流程办理</span>
|
||||
</div>
|
||||
|
||||
<a-form class="process-form" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-form-item v-if="isTask('Task_improve001')" label="初步评定奖项" required>
|
||||
<a-radio-group v-model:value="initialAward">
|
||||
<a-radio v-for="item in awardOptions" :key="item.value" :value="item.value">{{ item.label }}</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-help">金奖、银奖进入部门评议小组打分;铜奖、参与奖直接进入部门负责人审核。</div>
|
||||
</a-form-item>
|
||||
|
||||
<template v-if="isTask('Task_improve002')">
|
||||
<a-form-item label="部门评分记录">
|
||||
<a-table row-key="id" size="small" bordered :columns="scoreColumns" :data-source="scoreRows" :pagination="false">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'status'">{{ record.scoreStatus === 'completed' ? '已评分' : '待评分' }}</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-form-item>
|
||||
<a-form-item label="评分操作">
|
||||
<a-button type="primary" :disabled="!currentScore" @click="openScoreModal">打分</a-button>
|
||||
<span v-if="!currentScore" class="form-help">当前用户不在部门评分名单中。</span>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<template v-if="isTask('Task_improve003')">
|
||||
<a-form-item label="初步评定奖项">{{ awardLabel(proposal.initialAward) }}</a-form-item>
|
||||
<a-form-item v-if="proposal.needDeptScore === '1'" label="部门评议结果">
|
||||
平均分:{{ proposal.deptAvgScore ?? '-' }};系统建议奖项:{{ awardLabel(proposal.suggestedAward) }}
|
||||
</a-form-item>
|
||||
<a-form-item label="负责人确认奖项" required>
|
||||
<a-radio-group v-model:value="leaderFinalAward">
|
||||
<a-radio v-for="item in awardOptions" :key="item.value" :value="item.value">{{ item.label }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<template v-if="isTask('Task_improve004')">
|
||||
<a-form-item label="所级评议人员">
|
||||
<a-table row-key="id" size="small" bordered :columns="voteMemberColumns" :data-source="voteRows" :pagination="false" />
|
||||
<div class="form-help">所级评议人员选择和投票记录初始化将在后续功能中接入。</div>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<template v-if="isTask('Task_improve005')">
|
||||
<a-form-item label="我的投票">
|
||||
<a-space v-if="currentVote">
|
||||
<a-button type="primary" :disabled="currentVote.voteStatus === 'voted'" :loading="savingVote" @click="castVote('agree')">同意</a-button>
|
||||
<a-button danger :disabled="currentVote.voteStatus === 'voted'" :loading="savingVote" @click="castVote('disagree')">不同意</a-button>
|
||||
<span>{{ voteResultLabel(currentVote) }}</span>
|
||||
</a-space>
|
||||
<span v-else class="form-help">当前用户不在所级评议投票名单中。</span>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<template v-if="isTask('Task_improve006')">
|
||||
<a-form-item label="负责人确认奖项">{{ awardLabel(proposal.leaderFinalAward) }}</a-form-item>
|
||||
<a-form-item v-if="proposal.isneedvote === '1'" label="所级评议结果">
|
||||
同意票:{{ proposal.instituteAgreeCount ?? '-' }};不同意票:{{ proposal.instituteDisagreeCount ?? '-' }};结果:{{ proposal.instituteVoteResult || '-' }}
|
||||
</a-form-item>
|
||||
<a-form-item label="最终奖项" required>
|
||||
<a-radio-group v-model:value="finalAward">
|
||||
<a-radio v-for="item in awardOptions" :key="item.value" :value="item.value">{{ item.label }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-form>
|
||||
|
||||
<TaskHandleInnerContent
|
||||
:formData="formData"
|
||||
:form-data="formData"
|
||||
:claim="claim"
|
||||
:before-handle="saveNodeAction"
|
||||
@success="handleSuccess"
|
||||
@claimSuccess="handleClaimSuccess"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<a-modal v-model:open="scoreModalVisible" title="部门评议打分" :footer="null" :mask-closable="false">
|
||||
<a-descriptions v-if="currentScore" bordered size="small" :column="1">
|
||||
<a-descriptions-item label="评委">{{ currentScore.scorerName || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="评分状态">{{ currentScore.scoreStatus === 'completed' ? '已评分' : '待评分' }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<div class="form-help">四个评分维度录入、加权计算和评分提交将在下一阶段开发。</div>
|
||||
</a-modal>
|
||||
</section>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch } from 'vue';
|
||||
import { queryDataById } from '../ImprovementProposal.api';
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import SUploadFile from '/@/components/semri/fileComponent/SUploadFile.vue';
|
||||
import TaskHandleInnerContent from '/@/views/super/bpm/process/personalOffice/myHandleTask/content/TaskHandleInnerContent.vue';
|
||||
import {
|
||||
castInstituteVote,
|
||||
queryDataById,
|
||||
queryImprovementDeptScoreListByMainId,
|
||||
queryImprovementInstituteVoteListByMainId,
|
||||
saveArchiveAward,
|
||||
saveInitialReview,
|
||||
saveLeaderAward,
|
||||
} from '../ImprovementProposal.api';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ImprovementProposalBPMForm',
|
||||
components: { TaskHandleInnerContent },
|
||||
props: {
|
||||
const props = defineProps({
|
||||
formData: { type: Object, default: () => ({}) },
|
||||
formBpm: { type: Boolean, default: true },
|
||||
claim: { type: Boolean, default: false },
|
||||
},
|
||||
emits: ['success', 'claimSuccess'],
|
||||
setup(props, { emit }) {
|
||||
});
|
||||
const emit = defineEmits(['success', 'claimSuccess']);
|
||||
const { createMessage } = useMessage();
|
||||
const userStore = useUserStore();
|
||||
const loading = ref(false);
|
||||
const savingVote = ref(false);
|
||||
const scoreModalVisible = ref(false);
|
||||
const proposal = ref<Recordable>({});
|
||||
const scoreRows = ref<Recordable[]>([]);
|
||||
const voteRows = ref<Recordable[]>([]);
|
||||
const initialAward = ref('');
|
||||
const leaderFinalAward = ref('');
|
||||
const finalAward = ref('');
|
||||
const labelCol = { xs: { span: 24 }, sm: { span: 5 } };
|
||||
const wrapperCol = { xs: { span: 24 }, sm: { span: 19 } };
|
||||
|
||||
// processDataId 是引擎保存的原始业务键;兼容普通待办没有该字段时回退 dataId。
|
||||
const proposalId = computed(() => props.formData?.processDataId || props.formData?.dataId);
|
||||
const awardOptions = [
|
||||
{ value: '0', label: '金奖' },
|
||||
{ value: '1', label: '银奖' },
|
||||
{ value: '2', label: '铜奖' },
|
||||
{ value: '3', label: '参与奖' },
|
||||
];
|
||||
const scoreColumns = [
|
||||
{ title: '评委', dataIndex: 'scorerName', width: 180 },
|
||||
{ title: '状态', key: 'status', width: 120 },
|
||||
{ title: '总分', dataIndex: 'totalScore', width: 120 },
|
||||
];
|
||||
const voteMemberColumns = [
|
||||
{ title: '评委', dataIndex: 'voterName', width: 180 },
|
||||
{ title: '状态', dataIndex: 'voteStatus', width: 120 },
|
||||
];
|
||||
|
||||
// 流程引擎在运行待办中提供 taskDefKey,节点功能只依赖该稳定标识而非表单 URL 参数。
|
||||
const processInfo = computed(() => ({
|
||||
mainId: props.formData?.processDataId || props.formData?.dataId,
|
||||
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?.processInstanceId,
|
||||
}));
|
||||
const showProcessHandle = computed(() => props.formBpm && props.formData?.PROCESS_TAB_TYPE === 'run' && !!processInfo.value.taskId);
|
||||
const currentUserId = computed(() => String(userStore.getUserInfo?.id || ''));
|
||||
const currentScore = computed(() => scoreRows.value.find((item) => String(item.scorerId) === currentUserId.value));
|
||||
const currentVote = computed(() => voteRows.value.find((item) => String(item.voterId) === currentUserId.value));
|
||||
|
||||
watch(
|
||||
() => [processInfo.value.mainId, processInfo.value.processInstanceId],
|
||||
() => loadProposal(),
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
async function loadProposal() {
|
||||
if (!proposalId.value) {
|
||||
const mainId = processInfo.value.mainId;
|
||||
if (!mainId) {
|
||||
proposal.value = {};
|
||||
scoreRows.value = [];
|
||||
voteRows.value = [];
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
proposal.value = await queryDataById(proposalId.value);
|
||||
const [main, scores, votes] = await Promise.all([
|
||||
queryDataById(mainId),
|
||||
queryImprovementDeptScoreListByMainId(mainId),
|
||||
queryImprovementInstituteVoteListByMainId(mainId),
|
||||
]);
|
||||
proposal.value = main || {};
|
||||
scoreRows.value = scores || [];
|
||||
voteRows.value = votes || [];
|
||||
initialAward.value = proposal.value.initialAward || '';
|
||||
leaderFinalAward.value = proposal.value.leaderFinalAward || '';
|
||||
finalAward.value = proposal.value.finalAward || '';
|
||||
} catch (error) {
|
||||
createMessage.warning('提案数据加载失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch(proposalId, loadProposal, { immediate: true });
|
||||
function isTask(taskDefKey: string) {
|
||||
return processInfo.value.taskDefKey === taskDefKey;
|
||||
}
|
||||
|
||||
return {
|
||||
loading,
|
||||
proposal,
|
||||
handleSuccess: () => emit('success'),
|
||||
handleClaimSuccess: () => emit('claimSuccess'),
|
||||
};
|
||||
},
|
||||
});
|
||||
function actionPayload(extra: Recordable = {}) {
|
||||
return { ...processInfo.value, ...extra };
|
||||
}
|
||||
|
||||
async function saveNodeAction() {
|
||||
try {
|
||||
if (isTask('Task_improve001')) {
|
||||
if (!initialAward.value) {
|
||||
createMessage.warning('请选择初步评定奖项');
|
||||
return false;
|
||||
}
|
||||
await saveInitialReview(actionPayload({ initialAward: initialAward.value }));
|
||||
}
|
||||
if (isTask('Task_improve003')) {
|
||||
if (!leaderFinalAward.value) {
|
||||
createMessage.warning('请选择负责人确认奖项');
|
||||
return false;
|
||||
}
|
||||
await saveLeaderAward(actionPayload({ leaderFinalAward: leaderFinalAward.value }));
|
||||
}
|
||||
if (isTask('Task_improve005') && currentVote.value?.voteStatus !== 'voted') {
|
||||
createMessage.warning('请先完成投票');
|
||||
return false;
|
||||
}
|
||||
if (isTask('Task_improve006')) {
|
||||
if (!finalAward.value) {
|
||||
createMessage.warning('请选择最终奖项');
|
||||
return false;
|
||||
}
|
||||
await saveArchiveAward(actionPayload({ finalAward: finalAward.value }));
|
||||
}
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
createMessage.warning(error?.message || '流程办理数据保存失败');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function castVote(voteResult: string) {
|
||||
savingVote.value = true;
|
||||
try {
|
||||
await castInstituteVote(actionPayload({ voteResult }));
|
||||
createMessage.success('投票成功');
|
||||
await loadProposal();
|
||||
} catch (error: any) {
|
||||
createMessage.warning(error?.message || '投票失败');
|
||||
} finally {
|
||||
savingVote.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function openScoreModal() {
|
||||
// 评分字段、权重计算和完成条件将由下一阶段单独实现,避免当前占位入口误写评分结果。
|
||||
scoreModalVisible.value = true;
|
||||
}
|
||||
|
||||
function awardLabel(value: string) {
|
||||
return awardOptions.find((item) => item.value === String(value))?.label || '-';
|
||||
}
|
||||
|
||||
function voteResultLabel(vote: Recordable) {
|
||||
if (vote.voteStatus !== 'voted') return '待投票';
|
||||
return vote.voteResult === 'agree' ? '已投同意票' : '已投不同意票';
|
||||
}
|
||||
|
||||
function formatDate(value: string) {
|
||||
return value ? String(value).slice(0, 10) : '-';
|
||||
}
|
||||
|
||||
function handleSuccess() {
|
||||
emit('success');
|
||||
}
|
||||
|
||||
function handleClaimSuccess() {
|
||||
emit('claimSuccess');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@@ -81,4 +321,41 @@
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.section-header {
|
||||
margin-bottom: 10px;
|
||||
padding: 7px 10px;
|
||||
border-left: 3px solid #1677ff;
|
||||
background: #f6fbff;
|
||||
color: #1f2937;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.attachment-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.attachment-label {
|
||||
margin-bottom: 6px;
|
||||
color: #475569;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.process-form {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.form-help {
|
||||
margin-top: 6px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.attachment-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
+12
@@ -34,6 +34,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { taskTransInfo, taskComplete, taskClaim } from '../task.handle.api';
|
||||
import { queryRejectTargetCodes } from '../../../processDesign/processNode/process.node.api';
|
||||
import { ref, watch, computed } from 'vue';
|
||||
import TaskNodeStepList from './TaskNodeStepList.vue';
|
||||
import TaskCommentList from './TaskCommentList.vue';
|
||||
@@ -177,6 +178,17 @@
|
||||
currentNode.value = nodeObject;
|
||||
|
||||
historyList.value = data.histListNode;
|
||||
// 驳回目标节点过滤:若配置了可驳回目标节点,则前端过滤历史节点;查询失败时不阻塞,展示全部
|
||||
if (data.rejectStatus == '1') {
|
||||
try {
|
||||
const allowedCodes = await queryRejectTargetCodes({ processKey: data.processKey, nodeCode: data.taskDefinitionKey });
|
||||
if (allowedCodes && allowedCodes.length > 0) {
|
||||
historyList.value = historyList.value.filter(item => allowedCodes.includes(item.TASK_DEF_KEY_));
|
||||
}
|
||||
} catch {
|
||||
// 查询失败时不阻塞审批流程,显示所有历史节点
|
||||
}
|
||||
}
|
||||
branchList.value = data.transitionList;
|
||||
|
||||
turnbackTaskId.value = data.turnbackTaskId;
|
||||
|
||||
@@ -6,7 +6,10 @@ enum Api {
|
||||
deleteBatch = '/act/process/extActProcessNode/deleteBatch',
|
||||
add = '/act/process/extActProcessNode/add',
|
||||
edit = '/act/process/extActProcessNode/edit',
|
||||
batchSavePermission = '/act/process/extActProcessNodePermission/saveOrUpdateBatch'
|
||||
batchSavePermission = '/act/process/extActProcessNodePermission/saveOrUpdateBatch',
|
||||
queryRejectTargets = '/act/process/extActProcessNode/queryRejectTargets',
|
||||
saveRejectTargets = '/act/process/extActProcessNode/saveRejectTargets',
|
||||
queryRejectTargetCodes = '/act/process/extActProcessNode/queryRejectTargetCodes',
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,3 +42,24 @@ export const saveOrUpdate = (params, isUpdate) => {
|
||||
export const batchSavePermission = (params) => {
|
||||
return defHttp.post({ url: Api.batchSavePermission, params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询节点的驳回目标配置
|
||||
* @param params { processId, sourceNodeCode }
|
||||
*/
|
||||
export const queryRejectTargets = (params) =>
|
||||
defHttp.get({ url: Api.queryRejectTargets, params });
|
||||
|
||||
/**
|
||||
* 保存节点的驳回目标配置
|
||||
* @param queryParams - { processId, sourceNodeCode }
|
||||
* @param bodyData - array of { targetNodeCode, targetNodeName }
|
||||
*/
|
||||
export const saveRejectTargets = (queryParams, bodyData) =>
|
||||
defHttp.post({ url: Api.saveRejectTargets, params: queryParams, data: bodyData }, { isTransformResponse: false });
|
||||
|
||||
/**
|
||||
* 根据 processKey + nodeCode 查询可驳回的目标节点CODE列表(运行时过滤用)
|
||||
*/
|
||||
export const queryRejectTargetCodes = (params) =>
|
||||
defHttp.get({ url: Api.queryRejectTargetCodes, params });
|
||||
@@ -133,6 +133,31 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 驳回目标节点选择,仅在"是否允许驳回"开启时显示 -->
|
||||
<div v-if="buttonStatus.rejectStatus === '1'" style="padding: 0 10px; margin-bottom: 10px;">
|
||||
<div style="margin-bottom: 8px; font-size: 14px; color: #4b4a4a; font-weight: 500;">
|
||||
可驳回的目标节点:
|
||||
</div>
|
||||
<div style="background: #fafafa; border: 1px solid #d9d9d9; border-radius: 6px; padding: 12px;">
|
||||
<div v-if="allProcessNodes.length === 0" style="color: #999; text-align: center; padding: 10px;">
|
||||
暂无可选节点
|
||||
</div>
|
||||
<a-checkbox-group v-model:value="checkedTargetNodeCodes" v-else>
|
||||
<div v-for="node in allProcessNodes" :key="node.processNodeCode"
|
||||
style="margin-bottom: 6px;">
|
||||
<a-checkbox
|
||||
:value="node.processNodeCode"
|
||||
:disabled="node.processNodeCode === processInfo.processNodeCode">
|
||||
{{ node.processNodeName }}
|
||||
<span style="color: #999; font-size: 12px;">({{ node.processNodeCode }})</span>
|
||||
<span v-if="node.processNodeCode === processInfo.processNodeCode"
|
||||
style="color: #ff4d4f; font-size: 12px;"> [当前节点]</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-spin>
|
||||
@@ -154,7 +179,7 @@
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
import { useAuthField, useAuthButton } from './useNodeAuthEasyModal';
|
||||
import { saveOrUpdate, batchSavePermission } from '../processNode/process.node.api';
|
||||
import { saveOrUpdate, batchSavePermission, saveRejectTargets } from '../processNode/process.node.api';
|
||||
import NodeAuthEasyForSelect from './NodeAuthEasyForSelect.vue'
|
||||
import NodeAuthEasyForInput from './NodeAuthEasyForInput.vue'
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
@@ -193,7 +218,10 @@
|
||||
|
||||
const { formTypeArray, activeFormType, activeTableName, myFormList, handleChangeFormType, queryBizFormType, queryLastAuthData, authDataList } = useAuthField(spinningLoading, processInfo);
|
||||
|
||||
const { buttonStatus, initButtonStatus, handleChangeFormEditStatus } = useAuthButton(activeFormType, activeTableName);
|
||||
const { buttonStatus, initButtonStatus, handleChangeFormEditStatus, rejectTargetList, allProcessNodes } = useAuthButton(activeFormType, activeTableName);
|
||||
|
||||
// 驳回目标节点勾选状态
|
||||
const checkedTargetNodeCodes = ref([]);
|
||||
|
||||
//useModalInner
|
||||
const [registerModal, { closeModal }] = useModalInner(async (data) => {
|
||||
@@ -204,7 +232,9 @@
|
||||
processInfo.processNodeCode = processNodeCode;
|
||||
activeTableName.value = '';
|
||||
/**--------------按钮----------------*/
|
||||
initButtonStatus(data);
|
||||
await initButtonStatus(data);
|
||||
// 回填已配置的驳回目标节点勾选状态
|
||||
checkedTargetNodeCodes.value = rejectTargetList.value.map(r => r.targetNodeCode);
|
||||
|
||||
/**--------------字段----------------*/
|
||||
//1.查询已经存在的权限数据 ruleName ruleCode formType ruleType status
|
||||
@@ -235,7 +265,6 @@
|
||||
|
||||
let allIsOk = true;
|
||||
const nodeUpdateResult = await defHttp.put({ url: '/act/process/extActProcessNode/edit', params: node }, { isTransformResponse: false });
|
||||
spinningLoading.value = false;
|
||||
// console.log('nodeUpdateResult', nodeUpdateResult)
|
||||
if(nodeUpdateResult.success){
|
||||
//保存成功
|
||||
@@ -245,12 +274,35 @@
|
||||
createMessage.warning(nodeUpdateResult.message);
|
||||
}
|
||||
|
||||
// 保存驳回目标节点配置
|
||||
if (buttonStatus.rejectStatus === '1') {
|
||||
const rejectTargets = checkedTargetNodeCodes.value.map(targetCode => {
|
||||
const nodeInfo = allProcessNodes.value.find(n => n.processNodeCode === targetCode);
|
||||
return {
|
||||
processId: processInfo.processId,
|
||||
sourceNodeCode: processInfo.processNodeCode,
|
||||
targetNodeCode: targetCode,
|
||||
targetNodeName: nodeInfo ? nodeInfo.processNodeName : '',
|
||||
};
|
||||
});
|
||||
try {
|
||||
await saveRejectTargets(
|
||||
{ processId: processInfo.processId, sourceNodeCode: processInfo.processNodeCode },
|
||||
rejectTargets
|
||||
);
|
||||
} catch {
|
||||
allIsOk = false;
|
||||
createMessage.warning('驳回目标节点保存失败');
|
||||
}
|
||||
}
|
||||
|
||||
//节点字段
|
||||
let data = [];
|
||||
if (activeFormType.value === '3') {
|
||||
//update-begin-author:liusq---date:2024-06-17--for: TV360X-990 代码生成的权限设置的小问题
|
||||
data = await customerTableRef.value.getData();
|
||||
if (!data) {
|
||||
spinningLoading.value = false;
|
||||
return;
|
||||
}
|
||||
//update-end-author:liusq---date:2024-06-17--for: TV360X-990 代码生成的权限设置的小问题
|
||||
@@ -272,6 +324,7 @@
|
||||
createMessage.warning(authUpdateResult.message);
|
||||
}
|
||||
}
|
||||
spinningLoading.value = false;
|
||||
if(allIsOk==true){
|
||||
createMessage.success('操作成功!');
|
||||
}
|
||||
@@ -352,6 +405,8 @@
|
||||
activeKey,
|
||||
buttonStatus,
|
||||
authDataList,
|
||||
checkedTargetNodeCodes,
|
||||
allProcessNodes,
|
||||
|
||||
spinningLoading,
|
||||
formTypeArray,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { queryFormTypeByProcessId, queryFormBizCodeByProcessid, list } from './node.auth.api';
|
||||
import { ref, reactive } from 'vue';
|
||||
import { list as listProcessNodes, queryRejectTargets } from '../processNode/process.node.api';
|
||||
|
||||
/**
|
||||
* 用于字段权限配置
|
||||
@@ -129,11 +130,44 @@ export function useAuthButton(activeFormType, activeTableName) {
|
||||
|
||||
});
|
||||
|
||||
function initButtonStatus(record) {
|
||||
// 驳回目标节点配置
|
||||
const rejectTargetList = ref<Array<{ processId: string; sourceNodeCode: string; targetNodeCode: string; targetNodeName: string }>>([]);
|
||||
// 当前流程所有节点
|
||||
const allProcessNodes = ref<Array<{ processNodeCode: string; processNodeName: string }>>([]);
|
||||
|
||||
async function fetchRejectTargets(processId: string, sourceNodeCode: string) {
|
||||
if (!processId || !sourceNodeCode) return;
|
||||
try {
|
||||
const result = await queryRejectTargets({ processId, sourceNodeCode });
|
||||
rejectTargetList.value = result || [];
|
||||
} catch {
|
||||
rejectTargetList.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchAllProcessNodes(processId: string) {
|
||||
if (!processId) return;
|
||||
try {
|
||||
const result = await listProcessNodes({ processId, pageSize: 500 });
|
||||
allProcessNodes.value = (result.records || []).map((r) => ({
|
||||
processNodeCode: r.processNodeCode,
|
||||
processNodeName: r.processNodeName,
|
||||
}));
|
||||
} catch {
|
||||
allProcessNodes.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function initButtonStatus(record) {
|
||||
Object.keys(buttonStatus).map((k) => {
|
||||
console.log(record[k]);
|
||||
buttonStatus[k] = record[k];
|
||||
});
|
||||
// 加载驳回目标配置
|
||||
if (record.processId && record.processNodeCode) {
|
||||
await fetchAllProcessNodes(record.processId);
|
||||
await fetchRejectTargets(record.processId, record.processNodeCode);
|
||||
}
|
||||
}
|
||||
|
||||
function handleChangeFormEditStatus(value) {
|
||||
@@ -184,5 +218,8 @@ export function useAuthButton(activeFormType, activeTableName) {
|
||||
buttonStatus,
|
||||
initButtonStatus,
|
||||
handleChangeFormEditStatus,
|
||||
rejectTargetList,
|
||||
allProcessNodes,
|
||||
fetchRejectTargets,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user