改善提案 Task_improve005 不显示 TaskHandleInnerContent。评委选择“投票通过”或“投票反对”后弹出确认框;确认即锁定个人投票并直接完成当前流程任务。
555 lines
23 KiB
Vue
555 lines
23 KiB
Vue
<template>
|
||
<a-spin :spinning="loading">
|
||
<section class="improvement-proposal-bpm-form">
|
||
<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="提出日期">{{ 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>
|
||
<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>
|
||
<JDictSelectTag v-model:value="initialAward" dictCode="proposal_prize" type="radio" />
|
||
<div class="form-help">金奖、银奖进入部门评议小组打分;铜奖、参与奖直接进入部门负责人审核。</div>
|
||
</a-form-item>
|
||
|
||
<template v-if="isTask('Task_improve002')">
|
||
<a-form-item label="我的评分">
|
||
<a-descriptions bordered size="small" :column="1">
|
||
<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="scoreLocked" @click="openScoreModal">{{ scoreLocked ? '评分已锁定' : '打分' }}</a-button>
|
||
</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-if="leaderAwardBase" v-model:value="leaderFinalAward">
|
||
<a-radio v-for="item in leaderAwardOptions" :key="item.value" :value="item.value">{{ item.label }}</a-radio>
|
||
</a-radio-group>
|
||
<div v-if="leaderAwardBase" class="form-help">评定基准:{{ awardLabel(leaderAwardBase) }},仅可选择当前档位或降档奖项。</div>
|
||
<div v-else class="form-help">部门评议建议奖项尚未生成,暂不能确认负责人奖项。</div>
|
||
</a-form-item>
|
||
</template>
|
||
|
||
<template v-if="isTask('Task_improve004')">
|
||
<a-form-item label="负责人确认奖项">{{ awardLabel(proposal.leaderFinalAward) }}</a-form-item>
|
||
<a-form-item label="所级评议人员" required>
|
||
<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>
|
||
<div v-else 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="currentVote.voteResult === 'agree' ? 'primary' : 'default'" :loading="savingVote" @click="confirmInstituteVote('agree')">投票通过</a-button>
|
||
<a-button danger :type="currentVote.voteResult === 'disagree' ? 'primary' : 'default'" :loading="savingVote" @click="confirmInstituteVote('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
|
||
v-if="!isTask('Task_improve005')"
|
||
: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" :body-style="{ padding: '24px 28px 20px' }">
|
||
<a-form layout="vertical">
|
||
<a-alert class="score-range-alert" type="info" show-icon message="所有评分项均须填写 0-100 分,最多可保留两位小数。" />
|
||
<a-row :gutter="12">
|
||
<a-col :span="24">
|
||
<a-form-item label="改善效果(权重 50%)" required>
|
||
<a-row :gutter="12">
|
||
<a-col :xs="24" :sm="12" :lg="6">
|
||
<a-form-item label="安全" required><a-input-number v-model:value="scoreForm.safetyScore" :min="0" :max="100" :precision="2" :disabled="scoreLocked" style="width: 100%" /></a-form-item>
|
||
</a-col>
|
||
<a-col :xs="24" :sm="12" :lg="6">
|
||
<a-form-item label="质量" required><a-input-number v-model:value="scoreForm.qualityScore" :min="0" :max="100" :precision="2" :disabled="scoreLocked" style="width: 100%" /></a-form-item>
|
||
</a-col>
|
||
<a-col :xs="24" :sm="12" :lg="6">
|
||
<a-form-item label="效率" required><a-input-number v-model:value="scoreForm.efficiencyScore" :min="0" :max="100" :precision="2" :disabled="scoreLocked" style="width: 100%" /></a-form-item>
|
||
</a-col>
|
||
<a-col :xs="24" :sm="12" :lg="6">
|
||
<a-form-item label="成本" required><a-input-number v-model:value="scoreForm.costScore" :min="0" :max="100" :precision="2" :disabled="scoreLocked" style="width: 100%" /></a-form-item>
|
||
</a-col>
|
||
</a-row>
|
||
<div class="form-help">改善效果得分按安全、质量、效率、成本四项的平均分自动计算:{{ effectAveragePreview }}</div>
|
||
</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>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { computed, ref, watch } from 'vue';
|
||
import { useMessage } from '/@/hooks/web/useMessage';
|
||
import { useUserStore } from '/@/store/modules/user';
|
||
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||
import SUploadFile from '/@/components/semri/fileComponent/SUploadFile.vue';
|
||
import TaskHandleInnerContent from '/@/views/super/bpm/process/personalOffice/myHandleTask/content/TaskHandleInnerContent.vue';
|
||
import {
|
||
queryDataById,
|
||
queryInstituteVoteCandidates,
|
||
queryImprovementInstituteVoteListByMainId,
|
||
queryMyDeptScore,
|
||
saveArchiveAward,
|
||
saveDeptScore,
|
||
saveInitialReview,
|
||
saveInstituteVoteMembers,
|
||
saveLeaderAward,
|
||
submitInstituteVote,
|
||
submitDeptScore,
|
||
} from '../ImprovementProposal.api';
|
||
|
||
const props = defineProps({
|
||
formData: { type: Object, default: () => ({}) },
|
||
formBpm: { type: Boolean, default: true },
|
||
claim: { type: Boolean, default: false },
|
||
});
|
||
const emit = defineEmits(['success', 'claimSuccess']);
|
||
const { createMessage, createConfirm } = 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 currentScore = ref<Recordable | null>(null);
|
||
const voteRows = ref<Recordable[]>([]);
|
||
const instituteVoteCandidates = ref<Recordable[]>([]);
|
||
const selectedInstituteVoterIds = ref<string[]>([]);
|
||
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 } };
|
||
|
||
const awardOptions = [
|
||
{ value: '0', label: '金奖' },
|
||
{ value: '1', label: '银奖' },
|
||
{ value: '2', label: '铜奖' },
|
||
{ value: '3', label: '参与奖' },
|
||
];
|
||
// 流程引擎在运行待办中提供 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 scoreLocked = computed(() => currentScore.value?.scoreStatus === 'completed');
|
||
const scoreStatusLabel = computed(() => {
|
||
if (!currentScore.value) return '未保存';
|
||
return scoreLocked.value ? '评分已锁定' : '已保存,待流程提交';
|
||
});
|
||
const effectAveragePreview = computed(() => {
|
||
const values = ['safetyScore', 'qualityScore', 'efficiencyScore', 'costScore'].map((key) => scoreForm.value[key]);
|
||
if (values.some((value) => value === undefined || value === null)) return '-';
|
||
return (values.reduce((sum, value) => sum + Number(value), 0) / values.length).toFixed(2);
|
||
});
|
||
// 部门评分完成后必须以系统建议奖项为基准,不能回退到初审奖项。
|
||
const leaderAwardBase = computed(() => {
|
||
const award = proposal.value.needDeptScore === '1' ? proposal.value.suggestedAward : proposal.value.initialAward;
|
||
return awardOptions.some((item) => item.value === String(award)) ? String(award) : '';
|
||
});
|
||
const leaderAwardOptions = computed(() => {
|
||
if (!leaderAwardBase.value) return [];
|
||
return awardOptions.filter((item) => Number(item.value) >= Number(leaderAwardBase.value));
|
||
});
|
||
const currentVote = computed(() => voteRows.value.find((item) => String(item.voterId) === currentUserId.value));
|
||
|
||
watch(
|
||
() => [processInfo.value.mainId, processInfo.value.processInstanceId, processInfo.value.taskId, processInfo.value.taskDefKey],
|
||
() => loadProposal(),
|
||
{ immediate: true }
|
||
);
|
||
|
||
async function loadProposal() {
|
||
const mainId = processInfo.value.mainId;
|
||
if (!mainId) {
|
||
proposal.value = {};
|
||
currentScore.value = null;
|
||
voteRows.value = [];
|
||
instituteVoteCandidates.value = [];
|
||
selectedInstituteVoterIds.value = [];
|
||
return;
|
||
}
|
||
loading.value = true;
|
||
try {
|
||
const [main, votes, myScore] = await Promise.all([
|
||
queryDataById(mainId),
|
||
queryImprovementInstituteVoteListByMainId(mainId),
|
||
isTask('Task_improve002') && processInfo.value.processInstanceId && processInfo.value.taskId
|
||
? queryMyDeptScore(processInfo.value)
|
||
: Promise.resolve(null),
|
||
]);
|
||
proposal.value = main || {};
|
||
currentScore.value = myScore || null;
|
||
voteRows.value = votes || [];
|
||
initialAward.value = proposal.value.initialAward || '';
|
||
leaderFinalAward.value = proposal.value.leaderFinalAward || '';
|
||
finalAward.value = proposal.value.finalAward || '';
|
||
if (isTask('Task_improve004') && processInfo.value.processInstanceId && processInfo.value.taskId) {
|
||
instituteVoteCandidates.value = await queryInstituteVoteCandidates(processInfo.value);
|
||
const candidateIds = new Set(instituteVoteCandidates.value.map((item) => String(item.id)));
|
||
// 流程提交失败后重新打开 Task4 时,回显本次尚未流转的有效名单。
|
||
selectedInstituteVoterIds.value = voteRows.value
|
||
.map((item) => String(item.voterId))
|
||
.filter((voterId) => candidateIds.has(voterId));
|
||
} else {
|
||
instituteVoteCandidates.value = [];
|
||
selectedInstituteVoterIds.value = [];
|
||
}
|
||
} catch (error) {
|
||
createMessage.warning('提案数据加载失败');
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}
|
||
|
||
function isTask(taskDefKey: string) {
|
||
return processInfo.value.taskDefKey === taskDefKey;
|
||
}
|
||
|
||
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_improve002')) {
|
||
// 弹窗仅保存草稿;通用流程办理前才锁定评分,确保评委在此之前仍可修改。
|
||
await submitDeptScore(actionPayload());
|
||
}
|
||
if (isTask('Task_improve003')) {
|
||
if (!leaderAwardBase.value) {
|
||
createMessage.warning('部门评议建议奖项尚未生成,不能确认负责人奖项');
|
||
return false;
|
||
}
|
||
if (!leaderFinalAward.value) {
|
||
createMessage.warning('请选择负责人确认奖项');
|
||
return false;
|
||
}
|
||
if (!leaderAwardOptions.value.some((item) => item.value === leaderFinalAward.value)) {
|
||
createMessage.warning('负责人确认奖项只能选择当前档位或降档奖项');
|
||
return false;
|
||
}
|
||
await saveLeaderAward(actionPayload({ leaderFinalAward: leaderFinalAward.value }));
|
||
}
|
||
if (isTask('Task_improve004')) {
|
||
if (!selectedInstituteVoterIds.value.length) {
|
||
createMessage.warning('请至少选择一名所级评议人员');
|
||
return false;
|
||
}
|
||
await saveInstituteVoteMembers(actionPayload({ voterIds: selectedInstituteVoterIds.value }));
|
||
}
|
||
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;
|
||
}
|
||
}
|
||
|
||
function confirmInstituteVote(voteResult: 'agree' | 'disagree') {
|
||
const voteLabel = voteResult === 'agree' ? '通过' : '反对';
|
||
createConfirm({
|
||
iconType: 'warning',
|
||
title: '确认投票',
|
||
content: `确认提交投票${voteLabel}吗?`,
|
||
okText: '确认提交',
|
||
cancelText: '取消',
|
||
onOk: () => submitInstituteVoteAndComplete(voteResult),
|
||
});
|
||
}
|
||
|
||
async function submitInstituteVoteAndComplete(voteResult: 'agree' | 'disagree') {
|
||
savingVote.value = true;
|
||
try {
|
||
// 后端在锁定投票后复用通用流程办理服务完成当前 Task5 任务。
|
||
await submitInstituteVote(actionPayload({ voteResult }));
|
||
createMessage.success('投票提交成功');
|
||
emit('success');
|
||
} catch (error: any) {
|
||
createMessage.warning(error?.message || '投票提交失败');
|
||
} finally {
|
||
savingVote.value = false;
|
||
}
|
||
}
|
||
|
||
function openScoreModal() {
|
||
const score = currentScore.value;
|
||
scoreForm.value = {
|
||
safetyScore: score?.safetyScore ?? undefined,
|
||
qualityScore: score?.qualityScore ?? undefined,
|
||
efficiencyScore: score?.efficiencyScore ?? undefined,
|
||
costScore: score?.costScore ?? 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('评分保存成功,可在流程提交前继续修改');
|
||
scoreModalVisible.value = false;
|
||
await loadProposal();
|
||
} catch (error: any) {
|
||
createMessage.warning(error?.message || '评分保存失败');
|
||
} finally {
|
||
savingScore.value = false;
|
||
}
|
||
}
|
||
|
||
function createEmptyScoreForm() {
|
||
return {
|
||
safetyScore: undefined,
|
||
qualityScore: undefined,
|
||
efficiencyScore: undefined,
|
||
costScore: undefined,
|
||
promotionScore: undefined,
|
||
originalityScore: undefined,
|
||
effortScore: undefined,
|
||
scoreOpinion: '',
|
||
};
|
||
}
|
||
|
||
function hasValidScoreValues() {
|
||
return ['safetyScore', 'qualityScore', 'efficiencyScore', 'costScore', '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 || '-';
|
||
}
|
||
|
||
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 formatDateTime(value?: string) {
|
||
return value ? String(value) : '-';
|
||
}
|
||
|
||
function handleSuccess() {
|
||
emit('success');
|
||
}
|
||
|
||
function handleClaimSuccess() {
|
||
emit('claimSuccess');
|
||
}
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.improvement-proposal-bpm-form {
|
||
padding: 8px 12px 16px;
|
||
|
||
:deep(.ant-descriptions-item-content) {
|
||
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(2, 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;
|
||
}
|
||
|
||
.score-range-alert {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.vote-member-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||
gap: 10px 12px;
|
||
width: 100%;
|
||
}
|
||
|
||
.vote-member-option {
|
||
display: flex;
|
||
align-items: center;
|
||
min-height: 42px;
|
||
margin-inline-start: 0;
|
||
padding: 8px 10px;
|
||
border: 1px solid #d9e2ec;
|
||
border-radius: 4px;
|
||
background: #fff;
|
||
}
|
||
|
||
.vote-member-name {
|
||
margin-left: 6px;
|
||
color: #1f2937;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.vote-member-username {
|
||
margin-left: 6px;
|
||
color: #64748b;
|
||
font-size: 12px;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.attachment-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
</style>
|