Merge branch 'refs/heads/master' into wsq-20260727

This commit is contained in:
王淑勤
2026-07-30 10:52:06 +08:00
3 changed files with 91 additions and 49 deletions
@@ -109,7 +109,8 @@ export const startProposalProcess = (id: string) => defHttp.post({ url: Api.star
/** 流程节点专用接口会在任务提交前保存业务字段和网关变量。 */
export const saveInitialReview = (params) => defHttp.post({ url: Api.bpmInitialReview, params });
export const queryMyDeptScore = (params) => defHttp.get({ url: Api.bpmMyDeptScore, params });
export const saveDeptScore = (params) => defHttp.post({ url: Api.bpmDeptScore, params });
// 评分弹窗会显示包含后续操作说明的定制成功提示,关闭通用提示以避免重复弹窗。
export const saveDeptScore = (params) => defHttp.post({ url: Api.bpmDeptScore, params }, { successMessageMode: 'none' });
export const submitDeptScore = (params) => defHttp.post({ url: Api.bpmSubmitDeptScore, params });
export const saveLeaderAward = (params) => defHttp.post({ url: Api.bpmLeaderAward, params });
export const queryInstituteVoteCandidates = (params) => defHttp.get({ url: Api.bpmInstituteVoteCandidates, params });
@@ -1,36 +1,43 @@
<template>
<a-spin :spinning="loading">
<section class="improvement-proposal-bpm-form">
<div class="section-header">
<div class="section-header base-info-header">
<span>基本信息</span>
<a-button class="base-info-toggle" type="link" size="small" @click="showBaseInfoDetail = !showBaseInfoDetail">
<Icon :icon="showBaseInfoDetail ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
{{ showBaseInfoDetail ? '收起基本信息' : '展开基本信息' }}
</a-button>
</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="提出日期">{{ 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="团队名称" :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.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" />
<!-- 使用 v-show 保留只读附件组件实例展开时无需重新加载附件 -->
<div v-show="showBaseInfoDetail">
<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="提出日期">{{ 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="团队名称" :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.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>
<div class="attachment-label">改善后附件</div>
<SUploadFile :bussiness-id="`${proposal.id}:after`" :disabled="true" :multiple="true" />
</div>
</div>
<span v-else>-</span>
</a-descriptions-item>
</a-descriptions>
<span v-else>-</span>
</a-descriptions-item>
</a-descriptions>
</div>
<template v-if="showProcessHandle">
<a-divider />
@@ -77,7 +84,6 @@
<a-checkbox-group v-model:value="selectedInstituteVoterIds" class="vote-member-grid">
<a-checkbox v-for="member in instituteVoteCandidates" :key="member.id" :value="member.id" class="vote-member-option">
<span class="vote-member-name">{{ member.realname || member.username }}</span>
<span class="vote-member-username">{{ member.username }}</span>
</a-checkbox>
</a-checkbox-group>
<div v-if="!instituteVoteCandidates.length" class="form-help">未查询到所级评议小组人员</div>
@@ -185,9 +191,6 @@
</a-form-item>
</a-col>
</a-row>
<a-form-item label="评分意见">
<a-textarea v-model:value="scoreForm.scoreOpinion" :rows="3" :disabled="scoreLocked" />
</a-form-item>
<a-space>
<a-button v-if="!scoreLocked" type="primary" :loading="savingScore" @click="saveScoreDraft">保存评分</a-button>
<span v-else>评分已锁定请重新提交流程办理</span>
@@ -200,6 +203,7 @@
<script lang="ts" setup>
import { computed, ref, watch } from 'vue';
import Icon from '/@/components/Icon/index';
import { useMessage } from '/@/hooks/web/useMessage';
import { useUserStore } from '/@/store/modules/user';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
@@ -228,6 +232,8 @@
const { createMessage, createConfirm } = useMessage();
const userStore = useUserStore();
const loading = ref(false);
// 收起时保留基本信息和附件组件,避免展开后重复初始化只读附件。
const showBaseInfoDetail = ref(true);
const savingScore = ref(false);
const savingVote = ref(false);
const scoreModalVisible = ref(false);
@@ -438,7 +444,6 @@
promotionScore: score?.promotionScore ?? undefined,
originalityScore: score?.originalityScore ?? undefined,
effortScore: score?.effortScore ?? undefined,
scoreOpinion: score?.scoreOpinion || '',
};
scoreModalVisible.value = true;
}
@@ -470,7 +475,6 @@
promotionScore: undefined,
originalityScore: undefined,
effortScore: undefined,
scoreOpinion: '',
};
}
@@ -527,6 +531,21 @@
font-weight: 600;
}
.base-info-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.base-info-toggle {
display: inline-flex;
flex: 0 0 auto;
align-items: center;
gap: 4px;
padding-inline: 4px;
}
.attachment-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
@@ -541,6 +560,28 @@
.process-form {
margin-bottom: 12px;
font-size: 16px;
:deep(.ant-form-item-label > label),
:deep(.ant-form-item-control-input),
:deep(.ant-radio-wrapper),
:deep(.ant-checkbox-wrapper),
:deep(.ant-input),
:deep(.ant-input-number-input),
:deep(.ant-select-selection-item),
:deep(.ant-descriptions-item-label),
:deep(.ant-descriptions-item-content) {
font-size: 16px;
}
.form-help {
font-size: 14px;
}
.institute-vote-summary-label,
.vote-action-status {
font-size: 16px;
}
}
.form-help {
@@ -630,17 +671,17 @@
.vote-member-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 10px 12px;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 8px;
width: 100%;
}
.vote-member-option {
display: flex;
align-items: center;
min-height: 42px;
min-height: 44px;
margin-inline-start: 0;
padding: 8px 10px;
padding: 7px 10px;
border: 1px solid #d9e2ec;
border-radius: 4px;
background: #fff;
@@ -649,13 +690,9 @@
.vote-member-name {
margin-left: 6px;
color: #1f2937;
font-size: 16px;
font-weight: 500;
}
.vote-member-username {
margin-left: 6px;
color: #64748b;
font-size: 12px;
line-height: 1.4;
}
@media (max-width: 768px) {
@@ -665,6 +702,10 @@
}
@media (max-width: 576px) {
.base-info-header {
align-items: flex-start;
}
.institute-vote-summary-item {
flex: 1 1 120px;
}
@@ -57,7 +57,7 @@
</a-col>
<a-col :span="24">
<a-form-item label="改善前图片" :labelCol="longLabelCol" :wrapperCol="longWrapperCol">
<SUploadFile ref="beforeFileRef" :bussiness-id="formData.proposalNo ? `${formData.proposalNo}:before` : ''" :multiple="true" :disabled="disabled" />
<SUploadFile ref="beforeFileRef" :bussiness-id="formData.id ? `${formData.id}:before` : ''" :multiple="true" :disabled="disabled" />
</a-form-item>
</a-col>
<a-col :span="24">
@@ -67,7 +67,7 @@
</a-col>
<a-col :span="24">
<a-form-item label="改善后图片" :labelCol="longLabelCol" :wrapperCol="longWrapperCol">
<SUploadFile ref="afterFileRef" :bussiness-id="formData.proposalNo ? `${formData.proposalNo}:after` : ''" :multiple="true" :disabled="disabled" />
<SUploadFile ref="afterFileRef" :bussiness-id="formData.id ? `${formData.id}:after` : ''" :multiple="true" :disabled="disabled" />
</a-form-item>
</a-col>
<a-col :span="24">
@@ -415,13 +415,13 @@
}
console.log('表单提交数据', values)
const result = await saveOrUpdate(values, isUpdate);
// 新增时,保存成功后绑定附件的 bussinessId
// 新增阶段附件暂不绑定;主表生成 ID 后统一关联,保证普通表单和 BPM 使用同一查询键。
if (!isUpdate) {
const newId = typeof result === 'string' ? result : (result?.id || result);
if (newId) {
formData.id = newId;
await beforeFileRef.value?.bindBussinessId(`${formData.proposalNo}:before`);
await afterFileRef.value?.bindBussinessId(`${formData.proposalNo}:after`);
await beforeFileRef.value?.bindBussinessId(`${formData.id}:before`);
await afterFileRef.value?.bindBussinessId(`${formData.id}:after`);
}
}
emit('success');