yxk-20260728

改善提案
实现部门评议小组打分功能
This commit is contained in:
ye1023
2026-07-28 14:55:49 +08:00
parent 14c093a59e
commit 594d730fa4
2 changed files with 112 additions and 27 deletions
@@ -45,16 +45,15 @@
</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 label="我的评分">
<a-descriptions bordered size="small" :column="2">
<a-descriptions-item label="评分状态">{{ scoreStatusLabel }}</a-descriptions-item>
<a-descriptions-item label="加权总分">{{ currentScore?.totalScore ?? '-' }}</a-descriptions-item>
<a-descriptions-item label="评分时间" :span="2">{{ formatDateTime(currentScore?.scoreTime) }}</a-descriptions-item>
</a-descriptions>
</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-button type="primary" :disabled="scoreLocked" @click="openScoreModal">{{ scoreLocked ? '评分已锁定' : '打分' }}</a-button>
</a-form-item>
</template>
@@ -111,11 +110,37 @@
</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-form layout="vertical">
<a-row :gutter="12">
<a-col :xs="24" :sm="12">
<a-form-item label="改善效果(权重 50%" required>
<a-input-number v-model:value="scoreForm.effectScore" :min="0" :max="100" :precision="2" :disabled="scoreLocked" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="12">
<a-form-item label="可推广度(权重 20%" required>
<a-input-number v-model:value="scoreForm.promotionScore" :min="0" :max="100" :precision="2" :disabled="scoreLocked" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="12">
<a-form-item label="独创性(权重 20%" required>
<a-input-number v-model:value="scoreForm.originalityScore" :min="0" :max="100" :precision="2" :disabled="scoreLocked" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="12">
<a-form-item label="努力度(权重 10%" required>
<a-input-number v-model:value="scoreForm.effortScore" :min="0" :max="100" :precision="2" :disabled="scoreLocked" style="width: 100%" />
</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>
</a-space>
</a-form>
</a-modal>
</section>
</a-spin>
@@ -131,11 +156,13 @@
import {
castInstituteVote,
queryDataById,
queryImprovementDeptScoreListByMainId,
queryImprovementInstituteVoteListByMainId,
queryMyDeptScore,
saveArchiveAward,
saveDeptScore,
saveInitialReview,
saveLeaderAward,
submitDeptScore,
} from '../ImprovementProposal.api';
const props = defineProps({
@@ -147,14 +174,16 @@
const { createMessage } = useMessage();
const userStore = useUserStore();
const loading = ref(false);
const savingScore = ref(false);
const savingVote = ref(false);
const scoreModalVisible = ref(false);
const proposal = ref<Recordable>({});
const scoreRows = ref<Recordable[]>([]);
const currentScore = ref<Recordable | null>(null);
const voteRows = ref<Recordable[]>([]);
const initialAward = ref('');
const leaderFinalAward = ref('');
const finalAward = ref('');
const scoreForm = ref<Recordable>(createEmptyScoreForm());
const labelCol = { xs: { span: 24 }, sm: { span: 5 } };
const wrapperCol = { xs: { span: 24 }, sm: { span: 19 } };
@@ -164,11 +193,6 @@
{ 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 },
@@ -189,11 +213,15 @@
}));
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 scoreLocked = computed(() => currentScore.value?.scoreStatus === 'completed');
const scoreStatusLabel = computed(() => {
if (!currentScore.value) return '未保存';
return scoreLocked.value ? '评分已锁定' : '已保存,待流程提交';
});
const currentVote = computed(() => voteRows.value.find((item) => String(item.voterId) === currentUserId.value));
watch(
() => [processInfo.value.mainId, processInfo.value.processInstanceId],
() => [processInfo.value.mainId, processInfo.value.processInstanceId, processInfo.value.taskId, processInfo.value.taskDefKey],
() => loadProposal(),
{ immediate: true }
);
@@ -202,19 +230,21 @@
const mainId = processInfo.value.mainId;
if (!mainId) {
proposal.value = {};
scoreRows.value = [];
currentScore.value = null;
voteRows.value = [];
return;
}
loading.value = true;
try {
const [main, scores, votes] = await Promise.all([
const [main, votes, myScore] = await Promise.all([
queryDataById(mainId),
queryImprovementDeptScoreListByMainId(mainId),
queryImprovementInstituteVoteListByMainId(mainId),
isTask('Task_improve002') && processInfo.value.processInstanceId && processInfo.value.taskId
? queryMyDeptScore(processInfo.value)
: Promise.resolve(null),
]);
proposal.value = main || {};
scoreRows.value = scores || [];
currentScore.value = myScore || null;
voteRows.value = votes || [];
initialAward.value = proposal.value.initialAward || '';
leaderFinalAward.value = proposal.value.leaderFinalAward || '';
@@ -243,6 +273,10 @@
}
await saveInitialReview(actionPayload({ initialAward: initialAward.value }));
}
if (isTask('Task_improve002')) {
// 弹窗仅保存草稿;通用流程办理前才锁定评分,确保评委在此之前仍可修改。
await submitDeptScore(actionPayload());
}
if (isTask('Task_improve003')) {
if (!leaderFinalAward.value) {
createMessage.warning('请选择负责人确认奖项');
@@ -282,10 +316,51 @@
}
function openScoreModal() {
// 评分字段、权重计算和完成条件将由下一阶段单独实现,避免当前占位入口误写评分结果。
const score = currentScore.value;
scoreForm.value = {
effectScore: score?.effectScore ?? undefined,
promotionScore: score?.promotionScore ?? undefined,
originalityScore: score?.originalityScore ?? undefined,
effortScore: score?.effortScore ?? undefined,
scoreOpinion: score?.scoreOpinion || '',
};
scoreModalVisible.value = true;
}
async function saveScoreDraft() {
if (!hasValidScoreValues()) {
createMessage.warning('请完整填写 0 到 100 分之间的四项评分');
return;
}
savingScore.value = true;
try {
await saveDeptScore(actionPayload(scoreForm.value));
createMessage.success('评分保存成功,可在流程提交前继续修改');
await loadProposal();
} catch (error: any) {
createMessage.warning(error?.message || '评分保存失败');
} finally {
savingScore.value = false;
}
}
function createEmptyScoreForm() {
return {
effectScore: undefined,
promotionScore: undefined,
originalityScore: undefined,
effortScore: undefined,
scoreOpinion: '',
};
}
function hasValidScoreValues() {
return ['effectScore', 'promotionScore', 'originalityScore', 'effortScore'].every((key) => {
const value = scoreForm.value[key];
return value !== undefined && value !== null && Number(value) >= 0 && Number(value) <= 100;
});
}
function awardLabel(value: string) {
return awardOptions.find((item) => item.value === String(value))?.label || '-';
}
@@ -299,6 +374,10 @@
return value ? String(value).slice(0, 10) : '-';
}
function formatDateTime(value?: string) {
return value ? String(value) : '-';
}
function handleSuccess() {
emit('success');
}