From 5cb913cb0ae7c53d76abc0cde7c259282131419c Mon Sep 17 00:00:00 2001 From: lzm <2316711944@qq.com> Date: Wed, 13 May 2026 11:41:30 +0800 Subject: [PATCH] =?UTF-8?q?0513=E6=96=B0=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/tjt/outputSplit/index.ts | 12 + src/api/tjt/planning/index.ts | 10 + src/api/tjt/planningQuarter/index.ts | 13 + src/api/tjt/specialtyRoleSplit/index.ts | 1 + .../tjt/employee-year-cost-budget/index.vue | 7 + .../tjt/employee-year-leader-output/index.vue | 7 + src/views/tjt/employee/index.vue | 7 + src/views/tjt/office/index.vue | 7 + src/views/tjt/output-split/index.vue | 229 ++++++++++-------- src/views/tjt/output/PlanningOutputForm.vue | 15 +- .../tjt/output/QuarterDistributionForm.vue | 22 +- src/views/tjt/output/index.vue | 26 +- src/views/tjt/profit/index.vue | 165 +++++++------ src/views/tjt/project/index.vue | 7 + src/views/tjt/report-budget/index.vue | 7 + .../tjt/report-project-quarter/index.vue | 33 ++- .../tjt/report-specialty-person/index.vue | 17 +- src/views/tjt/report-summary/index.vue | 7 + src/views/tjt/staff-assignment/index.vue | 72 ++++-- src/views/tjt/year-k-value/index.vue | 7 + 20 files changed, 442 insertions(+), 229 deletions(-) diff --git a/src/api/tjt/outputSplit/index.ts b/src/api/tjt/outputSplit/index.ts index 45829b9..f127d58 100644 --- a/src/api/tjt/outputSplit/index.ts +++ b/src/api/tjt/outputSplit/index.ts @@ -1,4 +1,6 @@ import request from '@/config/axios' +import type { ProjectPlanningVO } from '@/api/tjt/planning' +import type { ProjectPlanningQuarterVO } from '@/api/tjt/planningQuarter' export interface ProjectOutputSplitVO { id?: number @@ -45,10 +47,20 @@ export type ProjectOutputSplitSaveVO = Pick< | 'digitalRatio' > +export interface ProjectOutputSplitPlanningDetailVO { + planning: ProjectPlanningVO + outputSplit: ProjectOutputSplitVO + quarters: ProjectPlanningQuarterVO[] +} + export const getProjectOutputSplitByPlanningId = (planningId: number) => { return request.get({ url: '/tjt/output-split/get-by-planning', params: { planningId } }) } +export const getProjectOutputSplitPlanningDetail = (planningId: number) => { + return request.get({ url: '/tjt/output-split/planning-detail', params: { planningId } }) +} + export const saveProjectOutputSplit = (data: ProjectOutputSplitSaveVO) => { return request.put({ url: '/tjt/output-split/save', data }) } diff --git a/src/api/tjt/planning/index.ts b/src/api/tjt/planning/index.ts index a02d1e3..62d8ff9 100644 --- a/src/api/tjt/planning/index.ts +++ b/src/api/tjt/planning/index.ts @@ -1,4 +1,5 @@ import request from '@/config/axios' +import type { ProjectPlanningGuideDetailVO } from '@/api/tjt/planningGuideDetail' export interface ProjectPlanningVO { id?: number @@ -71,6 +72,11 @@ export interface ProjectPlanningPageReqVO extends PageParam { createTime?: string[] } +export interface ProjectPlanningOutputEditDetailVO { + planning: ProjectPlanningVO + guideDetails: ProjectPlanningGuideDetailVO[] +} + export const getProjectPlanningPage = (params: ProjectPlanningPageReqVO) => { return request.get({ url: '/tjt/planning/page', params }) } @@ -79,6 +85,10 @@ export const getProjectPlanning = (id: number) => { return request.get({ url: '/tjt/planning/get', params: { id } }) } +export const getProjectPlanningOutputEditDetail = (id: number) => { + return request.get({ url: '/tjt/planning/output-edit-detail', params: { id } }) +} + export const getProjectPlanningListByProjectId = (projectId: number) => { return request.get({ url: '/tjt/planning/list-by-project', params: { projectId } }) } diff --git a/src/api/tjt/planningQuarter/index.ts b/src/api/tjt/planningQuarter/index.ts index 7cdc217..253fe59 100644 --- a/src/api/tjt/planningQuarter/index.ts +++ b/src/api/tjt/planningQuarter/index.ts @@ -1,4 +1,5 @@ import request from '@/config/axios' +import type { ProjectPlanningVO } from '@/api/tjt/planning' export interface ProjectPlanningQuarterVO { id?: number @@ -15,6 +16,11 @@ export type ProjectPlanningQuarterSaveVO = Omit< 'distributionAmount' | 'createTime' > +export interface ProjectPlanningQuarterPlanningDetailVO { + planning: ProjectPlanningVO + quarters: ProjectPlanningQuarterVO[] +} + export const getProjectPlanningQuarter = (id: number) => { return request.get({ url: '/tjt/planning-quarter/get', params: { id } }) } @@ -23,6 +29,13 @@ export const getProjectPlanningQuarterListByPlanningId = (planningId: number) => return request.get({ url: '/tjt/planning-quarter/list-by-planning', params: { planningId } }) } +export const getProjectPlanningQuarterPlanningDetail = (planningId: number) => { + return request.get({ + url: '/tjt/planning-quarter/planning-detail', + params: { planningId } + }) +} + export const createProjectPlanningQuarter = (data: ProjectPlanningQuarterSaveVO) => { return request.post({ url: '/tjt/planning-quarter/create', data }) } diff --git a/src/api/tjt/specialtyRoleSplit/index.ts b/src/api/tjt/specialtyRoleSplit/index.ts index 6356e0d..5f37c46 100644 --- a/src/api/tjt/specialtyRoleSplit/index.ts +++ b/src/api/tjt/specialtyRoleSplit/index.ts @@ -34,6 +34,7 @@ export interface SpecialtyRoleSplitSaveItemVO { export interface SpecialtyRoleSplitBatchSaveVO { planningId: number items: SpecialtyRoleSplitSaveItemVO[] + temporarySave?: boolean } export const getSpecialtyRoleSplitListByPlanningId = (planningId: number) => { diff --git a/src/views/tjt/employee-year-cost-budget/index.vue b/src/views/tjt/employee-year-cost-budget/index.vue index b958bda..a72e8f9 100644 --- a/src/views/tjt/employee-year-cost-budget/index.vue +++ b/src/views/tjt/employee-year-cost-budget/index.vue @@ -450,11 +450,18 @@ const handleDelete = async (id: number) => { } catch {} } +let activatedOnce = false + onMounted(() => { getList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getList() }) diff --git a/src/views/tjt/employee-year-leader-output/index.vue b/src/views/tjt/employee-year-leader-output/index.vue index aeea094..4d01b01 100644 --- a/src/views/tjt/employee-year-leader-output/index.vue +++ b/src/views/tjt/employee-year-leader-output/index.vue @@ -451,11 +451,18 @@ const handleDelete = async (id: number) => { } catch {} } +let activatedOnce = false + onMounted(() => { getList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getList() }) diff --git a/src/views/tjt/employee/index.vue b/src/views/tjt/employee/index.vue index 5fcaceb..62edd58 100644 --- a/src/views/tjt/employee/index.vue +++ b/src/views/tjt/employee/index.vue @@ -504,12 +504,19 @@ const handleDelete = async (id: number) => { } catch {} } +let activatedOnce = false + onMounted(async () => { await loadOfficeOptions() await getList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getList() }) diff --git a/src/views/tjt/office/index.vue b/src/views/tjt/office/index.vue index 0d87bdf..e4ea4e8 100644 --- a/src/views/tjt/office/index.vue +++ b/src/views/tjt/office/index.vue @@ -236,11 +236,18 @@ const handleDelete = async (id: number) => { } catch {} } +let activatedOnce = false + onMounted(() => { getList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getList() }) diff --git a/src/views/tjt/output-split/index.vue b/src/views/tjt/output-split/index.vue index ea4e8b8..03cc43e 100644 --- a/src/views/tjt/output-split/index.vue +++ b/src/views/tjt/output-split/index.vue @@ -103,108 +103,126 @@ - -
-
-
{{ currentPlanning.planningContent }}
-
- 年度:{{ formData.year || '-' }},考核产值:{{ formatAmountText(formData.assessmentOutputValue) }} 元 + +
+ - - + +
@@ -618,14 +636,12 @@ const loadPlanningRelatedData = async (planning: PlanningApi.ProjectPlanningVO) } quarterLoading.value = true try { - const [planningDetail, outputSplit, quarterList] = await Promise.all([ - PlanningApi.getProjectPlanning(planning.id), - OutputSplitApi.getProjectOutputSplitByPlanningId(planning.id), - PlanningQuarterApi.getProjectPlanningQuarterListByPlanningId(planning.id) - ]) - currentPlanning.value = planningDetail - formData.value = outputSplit - quarterRows.value = buildQuarterRows(planningDetail, quarterList) + const detail = await OutputSplitApi.getProjectOutputSplitPlanningDetail(planning.id) + currentPlanning.value = detail?.planning + formData.value = detail?.outputSplit + quarterRows.value = detail?.planning + ? buildQuarterRows(detail.planning, detail.quarters || []) + : [] } finally { quarterLoading.value = false } @@ -723,11 +739,18 @@ const handleSave = async () => { } } +let activatedOnce = false + onMounted(() => { getProjectList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getProjectList() }) diff --git a/src/views/tjt/output/PlanningOutputForm.vue b/src/views/tjt/output/PlanningOutputForm.vue index d020a5f..9a54da4 100644 --- a/src/views/tjt/output/PlanningOutputForm.vue +++ b/src/views/tjt/output/PlanningOutputForm.vue @@ -1192,12 +1192,17 @@ const open = async (id: number) => { dialogVisible.value = true formLoading.value = true try { - const data = await PlanningApi.getProjectPlanning(id) - formData.value = normalizeFormData(data) + const detail = await PlanningApi.getProjectPlanningOutputEditDetail(id) + if (!detail?.planning) { + formData.value = createFormData() + guideDetails.value = [] + dialogVisible.value = false + message.warning('合约规划不存在或已被删除') + return + } + formData.value = normalizeFormData(detail.planning) guideDetails.value = showGuideDetailSection.value - ? normalizeGuideDetailList( - await PlanningGuideDetailApi.getProjectPlanningGuideDetailListByPlanningId(id) - ) + ? normalizeGuideDetailList(detail.guideDetails) : [] applyCalculationRatioDefault() if (formData.value.reviewOutsourceRatio === undefined || formData.value.reviewOutsourceRatio === null) { diff --git a/src/views/tjt/output/QuarterDistributionForm.vue b/src/views/tjt/output/QuarterDistributionForm.vue index fc4e572..86192e7 100644 --- a/src/views/tjt/output/QuarterDistributionForm.vue +++ b/src/views/tjt/output/QuarterDistributionForm.vue @@ -205,7 +205,24 @@ const open = async (id: number) => { loading.value = true deletedQuarterIds.value = [] try { - const planning = await PlanningApi.getProjectPlanning(id) + const detail = await PlanningQuarterApi.getProjectPlanningQuarterPlanningDetail(id) + if (!detail?.planning) { + planningId.value = undefined + formData.value = { + projectId: 0, + ownershipType: '', + calculationMethod: '', + planningContent: '', + totalDistributionAmount: 1, + progressRemark: '' + } + quarterRows.value = [] + deletedQuarterIds.value = [] + dialogVisible.value = false + message.warning('合约规划不存在或已被删除') + return + } + const planning = detail.planning formData.value = { ...planning, contractValueQuantity: planning.contractValueQuantity ?? 1, @@ -214,8 +231,7 @@ const open = async (id: number) => { totalDistributionAmount: planning.totalDistributionAmount ?? 1, progressRemark: planning.progressRemark ?? '' } - const quarterList = await PlanningQuarterApi.getProjectPlanningQuarterListByPlanningId(id) - quarterRows.value = buildQuarterRows(formData.value, quarterList) + quarterRows.value = buildQuarterRows(formData.value, detail.quarters || []) } finally { loading.value = false } diff --git a/src/views/tjt/output/index.vue b/src/views/tjt/output/index.vue index 04f6b17..6f9f1a5 100644 --- a/src/views/tjt/output/index.vue +++ b/src/views/tjt/output/index.vue @@ -166,7 +166,9 @@ - +
+ - + +
@@ -581,12 +585,11 @@ const getPlanningList = async () => { } const loadPlanningDetail = async (planningId: number) => { - const planning = await PlanningApi.getProjectPlanning(planningId) - currentPlanning.value = planning quarterLoading.value = true try { - const quarterList = await PlanningQuarterApi.getProjectPlanningQuarterListByPlanningId(planningId) - quarterRows.value = buildQuarterRows(planning, quarterList) + const detail = await PlanningQuarterApi.getProjectPlanningQuarterPlanningDetail(planningId) + currentPlanning.value = detail?.planning + quarterRows.value = detail?.planning ? buildQuarterRows(detail.planning, detail.quarters || []) : [] } finally { quarterLoading.value = false } @@ -643,11 +646,18 @@ const handlePlanningOutputFormSuccess = async () => { } } +let activatedOnce = false + onMounted(() => { getProjectList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getProjectList() }) diff --git a/src/views/tjt/profit/index.vue b/src/views/tjt/profit/index.vue index 81a1b13..d7ee701 100644 --- a/src/views/tjt/profit/index.vue +++ b/src/views/tjt/profit/index.vue @@ -159,71 +159,73 @@ /> - -
-
{{ currentProfit.projectName }}
- - - 编辑盈亏参数 - + +
+ + +
- - - - {{ formatAmountText(currentProfit.contractAmount) }} - - - {{ formatAmountText(currentProfit.finalSettlementAmount) }} - - - - {{ formatAmountText(currentProfit.effectiveSettlementAmount) }} - - {{ formatAmountText(currentProfit.effectiveSettlementAmount) }} - - - {{ currentProfit.projectStartYear || '-' }} - - - {{ formatAmountText(currentProfit.comprehensivePlanningAmount) }} - - - {{ formatAmountText(currentProfit.subcontractPlanningAmount) }} - - - {{ formatAmountText(currentProfit.majorOutputValue) }} - - - {{ formatAmountText(currentProfit.majorExpectedPerformance) }} - - - {{ formatPercentText(currentProfit.innovationOutputRate) }} - - - {{ formatAmountText(currentProfit.innovationOutputValue) }} - - - {{ formatAmountText(currentProfit.otherCost) }} - - - - {{ formatAmountText(currentProfit.profitLossValue) }} - - - - - {{ formatPercentText(currentProfit.profitLossRate) }} - - - -
- - - @@ -286,6 +288,7 @@ const message = useMessage() const { t } = useI18n() const loading = ref(false) +const detailLoading = ref(false) const total = ref(0) const list = ref([]) const currentProfit = ref() @@ -337,21 +340,24 @@ const queryProjectStartYearValue = computed({ const getList = async () => { loading.value = true + let targetProfit: ProfitApi.ProjectProfitVO | undefined try { const data = await ProfitApi.getProjectProfitPage(queryParams) list.value = data.list total.value = data.total if (!list.value.length) { currentProfit.value = undefined - return + } else { + const targetProjectId = currentProfit.value?.projectId || list.value[0].projectId + targetProfit = list.value.find((item) => item.projectId === targetProjectId) || list.value[0] } - const targetProjectId = currentProfit.value?.projectId || list.value[0].projectId - const targetProfit = list.value.find((item) => item.projectId === targetProjectId) || list.value[0] - await nextTick() - profitTableRef.value?.setCurrentRow(targetProfit) } finally { loading.value = false } + if (targetProfit) { + await nextTick() + profitTableRef.value?.setCurrentRow(targetProfit) + } } const handleQuery = () => { @@ -369,14 +375,24 @@ const handleCurrentProfitChange = async (row?: ProfitApi.ProjectProfitVO) => { currentProfit.value = undefined return } - currentProfit.value = await ProfitApi.getProjectProfit(row.projectId) + detailLoading.value = true + try { + currentProfit.value = await ProfitApi.getProjectProfit(row.projectId) + } finally { + detailLoading.value = false + } } const refreshCurrentProfit = async () => { if (!currentProfit.value?.projectId) { return } - currentProfit.value = await ProfitApi.getProjectProfit(currentProfit.value.projectId) + detailLoading.value = true + try { + currentProfit.value = await ProfitApi.getProjectProfit(currentProfit.value.projectId) + } finally { + detailLoading.value = false + } await getList() } @@ -440,11 +456,18 @@ const profitLossClass = (value?: number) => { const isUsingContractAmount = (row?: ProfitApi.ProjectProfitVO) => !!row && Number(row.finalSettlementAmount || 0) <= 0 && Number(row.contractAmount || 0) > 0 +let activatedOnce = false + onMounted(() => { getList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getList() }) diff --git a/src/views/tjt/project/index.vue b/src/views/tjt/project/index.vue index ad2132b..63f6f7e 100644 --- a/src/views/tjt/project/index.vue +++ b/src/views/tjt/project/index.vue @@ -526,11 +526,18 @@ const handlePlanningFormSuccess = async () => { await getPlanningList() } +let activatedOnce = false + onMounted(() => { getList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getList() }) diff --git a/src/views/tjt/report-budget/index.vue b/src/views/tjt/report-budget/index.vue index bbb55b7..be344ff 100644 --- a/src/views/tjt/report-budget/index.vue +++ b/src/views/tjt/report-budget/index.vue @@ -384,11 +384,18 @@ const submitProjectBudgetExport = async () => { } } +let activatedOnce = false + onMounted(() => { getProjectList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getProjectList() }) diff --git a/src/views/tjt/report-project-quarter/index.vue b/src/views/tjt/report-project-quarter/index.vue index d239264..f3c6a3b 100644 --- a/src/views/tjt/report-project-quarter/index.vue +++ b/src/views/tjt/report-project-quarter/index.vue @@ -103,7 +103,9 @@ - + +
+ - - + +
@@ -566,14 +568,12 @@ const loadPlanningRelatedData = async (planning: PlanningApi.ProjectPlanningVO) } quarterLoading.value = true try { - const [planningDetail, outputSplit, quarterList] = await Promise.all([ - PlanningApi.getProjectPlanning(planning.id), - OutputSplitApi.getProjectOutputSplitByPlanningId(planning.id), - PlanningQuarterApi.getProjectPlanningQuarterListByPlanningId(planning.id) - ]) - currentPlanning.value = planningDetail - formData.value = outputSplit - quarterRows.value = buildQuarterRows(planningDetail, quarterList) + const detail = await OutputSplitApi.getProjectOutputSplitPlanningDetail(planning.id) + currentPlanning.value = detail?.planning + formData.value = detail?.outputSplit + quarterRows.value = detail?.planning + ? buildQuarterRows(detail.planning, detail.quarters || []) + : [] } finally { quarterLoading.value = false } @@ -684,11 +684,18 @@ const submitProjectLeadQuarterExport = async () => { } } +let activatedOnce = false + onMounted(() => { getProjectList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getProjectList() }) diff --git a/src/views/tjt/report-specialty-person/index.vue b/src/views/tjt/report-specialty-person/index.vue index 02fc00f..bf3abbc 100644 --- a/src/views/tjt/report-specialty-person/index.vue +++ b/src/views/tjt/report-specialty-person/index.vue @@ -105,7 +105,9 @@ - + +
+ - - + +
@@ -545,11 +547,18 @@ watch( } ) +let activatedOnce = false + onMounted(() => { getProjectList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getProjectList() }) diff --git a/src/views/tjt/report-summary/index.vue b/src/views/tjt/report-summary/index.vue index cb6528d..a76acd1 100644 --- a/src/views/tjt/report-summary/index.vue +++ b/src/views/tjt/report-summary/index.vue @@ -565,7 +565,14 @@ watch( } ) +let activatedOnce = false + onActivated(() => { + // immediate watch 已经负责首次预览加载,跳过 KeepAlive 首轮激活避免重复请求。 + if (!activatedOnce) { + activatedOnce = true + return + } refreshCurrentPreview() }) diff --git a/src/views/tjt/staff-assignment/index.vue b/src/views/tjt/staff-assignment/index.vue index d2edbb3..abc4c03 100644 --- a/src/views/tjt/staff-assignment/index.vue +++ b/src/views/tjt/staff-assignment/index.vue @@ -105,7 +105,9 @@ - + +
+ - + - - + +
@@ -306,7 +308,8 @@
@@ -349,6 +352,7 @@ const message = useMessage() const loading = ref(false) const planningLoading = ref(false) +const roleLoading = ref(false) const saveLoading = ref(false) const total = ref(0) const projectList = ref([]) @@ -374,7 +378,7 @@ const queryParams = reactive({ }) const getProjectRowIndex = (index: number) => - (queryParams.pageNo - 1) * queryParams.pageSize + index + 1 + (Number(queryParams.pageNo || 1) - 1) * Number(queryParams.pageSize || 10) + index + 1 const queryProjectStartYearValue = computed({ get: () => (queryParams.projectStartYear ? String(queryParams.projectStartYear) : undefined), @@ -681,7 +685,8 @@ const updateRoleRatio = (row: SpecialtyRoleSplitVO, value?: number) => { } const buildSavePersons = ( - row: SpecialtyRoleSplitVO + row: SpecialtyRoleSplitVO, + validate: boolean ): | { persons: SpecialtyRolePersonVO[]; error?: never } | { persons?: never; error: string } => { @@ -693,35 +698,39 @@ const buildSavePersons = ( if (!hasEmployeeId && !hasRatio) { continue } - if (!hasEmployeeId || !hasRatio) { + if (!validate && !hasEmployeeId) { + continue + } + if (validate && (!hasEmployeeId || !hasRatio)) { return { error: `${row.roleName} 的员工和比例必须同时填写` } } persons.push({ employeeId: person.employeeId, employeeName: employeeName || undefined, - personRatio: roundRatio(person.personRatio) + personRatio: roundRatio(hasRatio ? person.personRatio : 0) }) } return { persons } } -const validateAndBuildSaveItems = () => { +const buildSaveItems = (validate: boolean) => { const items: SpecialtyRoleSplitApi.SpecialtyRoleSplitSaveItemVO[] = [] for (const group of editGroups.value) { let roleTotal = 0 for (const row of group.rows) { - const result = buildSavePersons(row) + const result = buildSavePersons(row, validate) if (result.error) { message.warning(result.error) return undefined } const persons = result.persons || [] const personTotalRatio = sumPersonRatios(persons) - if (personTotalRatio > 1 + EPSILON) { + if (validate && personTotalRatio > 1 + EPSILON) { message.warning(`${group.specialtyName}-${row.roleName} 的人员比例合计不能大于 100%`) return undefined } if ( + validate && row.roleCode === DESIGN_ROLE_CODE && Number(row.roleAmount || 0) > EPSILON && persons.length === 0 @@ -737,7 +746,7 @@ const validateAndBuildSaveItems = () => { persons: isProjectLeadRow(row) ? [] : persons }) } - if (Math.abs(roleTotal - 1) > EPSILON) { + if (validate && Math.abs(roleTotal - 1) > EPSILON) { message.warning(`${group.specialtyName} 的角色比例合计必须等于 100%`) return undefined } @@ -798,10 +807,15 @@ const getPlanningList = async () => { } const loadRoleList = async (planningId: number) => { - const data = await SpecialtyRoleSplitApi.getSpecialtyRoleSplitListByPlanningId(planningId) - roleList.value = cloneRoleRows(data) - roleList.value.forEach((row) => syncRoleRatiosForGroup(roleList.value, row.specialtyCode)) - syncAllDerivedValues(roleList.value) + roleLoading.value = true + try { + const data = await SpecialtyRoleSplitApi.getSpecialtyRoleSplitListByPlanningId(planningId) + roleList.value = cloneRoleRows(data) + roleList.value.forEach((row) => syncRoleRatiosForGroup(roleList.value, row.specialtyCode)) + syncAllDerivedValues(roleList.value) + } finally { + roleLoading.value = false + } } const handleQuery = () => { @@ -841,11 +855,11 @@ const openEditDialog = () => { dialogVisible.value = true } -const handleSave = async () => { +const saveRoleSplit = async (temporarySave: boolean) => { if (!currentPlanning.value?.id) { return } - const items = validateAndBuildSaveItems() + const items = buildSaveItems(!temporarySave) if (!items) { return } @@ -853,21 +867,35 @@ const handleSave = async () => { try { await SpecialtyRoleSplitApi.saveSpecialtyRoleSplitBatch({ planningId: currentPlanning.value.id, - items + items, + temporarySave }) - message.success('保存成功') - dialogVisible.value = false + message.success(temporarySave ? '临时保存成功' : '保存成功') + if (!temporarySave) { + dialogVisible.value = false + } await loadRoleList(currentPlanning.value.id) } finally { saveLoading.value = false } } +const handleTemporarySave = () => saveRoleSplit(true) + +const handleSave = () => saveRoleSplit(false) + +let activatedOnce = false + onMounted(() => { getProjectList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getProjectList() }) diff --git a/src/views/tjt/year-k-value/index.vue b/src/views/tjt/year-k-value/index.vue index 934c3f5..c6b6475 100644 --- a/src/views/tjt/year-k-value/index.vue +++ b/src/views/tjt/year-k-value/index.vue @@ -299,11 +299,18 @@ const handleDelete = async (id: number) => { } catch {} } +let activatedOnce = false + onMounted(() => { getList() }) onActivated(() => { + // KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。 + if (!activatedOnce) { + activatedOnce = true + return + } getList() })