0513新功能优化
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import request from '@/config/axios'
|
import request from '@/config/axios'
|
||||||
|
import type { ProjectPlanningVO } from '@/api/tjt/planning'
|
||||||
|
import type { ProjectPlanningQuarterVO } from '@/api/tjt/planningQuarter'
|
||||||
|
|
||||||
export interface ProjectOutputSplitVO {
|
export interface ProjectOutputSplitVO {
|
||||||
id?: number
|
id?: number
|
||||||
@@ -45,10 +47,20 @@ export type ProjectOutputSplitSaveVO = Pick<
|
|||||||
| 'digitalRatio'
|
| 'digitalRatio'
|
||||||
>
|
>
|
||||||
|
|
||||||
|
export interface ProjectOutputSplitPlanningDetailVO {
|
||||||
|
planning: ProjectPlanningVO
|
||||||
|
outputSplit: ProjectOutputSplitVO
|
||||||
|
quarters: ProjectPlanningQuarterVO[]
|
||||||
|
}
|
||||||
|
|
||||||
export const getProjectOutputSplitByPlanningId = (planningId: number) => {
|
export const getProjectOutputSplitByPlanningId = (planningId: number) => {
|
||||||
return request.get({ url: '/tjt/output-split/get-by-planning', params: { planningId } })
|
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) => {
|
export const saveProjectOutputSplit = (data: ProjectOutputSplitSaveVO) => {
|
||||||
return request.put({ url: '/tjt/output-split/save', data })
|
return request.put({ url: '/tjt/output-split/save', data })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import request from '@/config/axios'
|
import request from '@/config/axios'
|
||||||
|
import type { ProjectPlanningGuideDetailVO } from '@/api/tjt/planningGuideDetail'
|
||||||
|
|
||||||
export interface ProjectPlanningVO {
|
export interface ProjectPlanningVO {
|
||||||
id?: number
|
id?: number
|
||||||
@@ -71,6 +72,11 @@ export interface ProjectPlanningPageReqVO extends PageParam {
|
|||||||
createTime?: string[]
|
createTime?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProjectPlanningOutputEditDetailVO {
|
||||||
|
planning: ProjectPlanningVO
|
||||||
|
guideDetails: ProjectPlanningGuideDetailVO[]
|
||||||
|
}
|
||||||
|
|
||||||
export const getProjectPlanningPage = (params: ProjectPlanningPageReqVO) => {
|
export const getProjectPlanningPage = (params: ProjectPlanningPageReqVO) => {
|
||||||
return request.get({ url: '/tjt/planning/page', params })
|
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 } })
|
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) => {
|
export const getProjectPlanningListByProjectId = (projectId: number) => {
|
||||||
return request.get({ url: '/tjt/planning/list-by-project', params: { projectId } })
|
return request.get({ url: '/tjt/planning/list-by-project', params: { projectId } })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import request from '@/config/axios'
|
import request from '@/config/axios'
|
||||||
|
import type { ProjectPlanningVO } from '@/api/tjt/planning'
|
||||||
|
|
||||||
export interface ProjectPlanningQuarterVO {
|
export interface ProjectPlanningQuarterVO {
|
||||||
id?: number
|
id?: number
|
||||||
@@ -15,6 +16,11 @@ export type ProjectPlanningQuarterSaveVO = Omit<
|
|||||||
'distributionAmount' | 'createTime'
|
'distributionAmount' | 'createTime'
|
||||||
>
|
>
|
||||||
|
|
||||||
|
export interface ProjectPlanningQuarterPlanningDetailVO {
|
||||||
|
planning: ProjectPlanningVO
|
||||||
|
quarters: ProjectPlanningQuarterVO[]
|
||||||
|
}
|
||||||
|
|
||||||
export const getProjectPlanningQuarter = (id: number) => {
|
export const getProjectPlanningQuarter = (id: number) => {
|
||||||
return request.get({ url: '/tjt/planning-quarter/get', params: { id } })
|
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 } })
|
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) => {
|
export const createProjectPlanningQuarter = (data: ProjectPlanningQuarterSaveVO) => {
|
||||||
return request.post({ url: '/tjt/planning-quarter/create', data })
|
return request.post({ url: '/tjt/planning-quarter/create', data })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export interface SpecialtyRoleSplitSaveItemVO {
|
|||||||
export interface SpecialtyRoleSplitBatchSaveVO {
|
export interface SpecialtyRoleSplitBatchSaveVO {
|
||||||
planningId: number
|
planningId: number
|
||||||
items: SpecialtyRoleSplitSaveItemVO[]
|
items: SpecialtyRoleSplitSaveItemVO[]
|
||||||
|
temporarySave?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSpecialtyRoleSplitListByPlanningId = (planningId: number) => {
|
export const getSpecialtyRoleSplitListByPlanningId = (planningId: number) => {
|
||||||
|
|||||||
@@ -450,11 +450,18 @@ const handleDelete = async (id: number) => {
|
|||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -451,11 +451,18 @@ const handleDelete = async (id: number) => {
|
|||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -504,12 +504,19 @@ const handleDelete = async (id: number) => {
|
|||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await loadOfficeOptions()
|
await loadOfficeOptions()
|
||||||
await getList()
|
await getList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -236,11 +236,18 @@ const handleDelete = async (id: number) => {
|
|||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -103,12 +103,17 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<ContentWrap v-if="currentPlanning && formData">
|
<ContentWrap>
|
||||||
|
<div v-loading="quarterLoading" class="min-h-320px">
|
||||||
|
<template v-if="currentPlanning && formData">
|
||||||
<div class="mb-16px flex items-center justify-between gap-16px">
|
<div class="mb-16px flex items-center justify-between gap-16px">
|
||||||
<div>
|
<div>
|
||||||
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
||||||
<div class="mt-4px text-13px text-[var(--el-text-color-secondary)]">
|
<div class="mt-4px text-13px text-[var(--el-text-color-secondary)]">
|
||||||
年度:{{ formData.year || '-' }},考核产值:{{ formatAmountText(formData.assessmentOutputValue) }} 元
|
年度:{{ formData.year || '-' }},考核产值:{{
|
||||||
|
formatAmountText(formData.assessmentOutputValue)
|
||||||
|
}}
|
||||||
|
元
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-12px">
|
<div class="flex items-center gap-12px">
|
||||||
@@ -125,10 +130,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-descriptions :column="2" border title="基础信息">
|
<el-descriptions :column="2" border title="基础信息">
|
||||||
<el-descriptions-item label="项目名称">{{ formData.projectName || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="项目名称">{{
|
||||||
<el-descriptions-item label="项目任务包">{{ formData.planningContent || '-' }}</el-descriptions-item>
|
formData.projectName || '-'
|
||||||
|
}}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="项目任务包">{{
|
||||||
|
formData.planningContent || '-'
|
||||||
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="工程负责人">
|
<el-descriptions-item label="工程负责人">
|
||||||
{{ getProjectLeadText(formData.projectManagerName, formData.engineeringLeaderName) }}
|
{{
|
||||||
|
getProjectLeadText(formData.projectManagerName, formData.engineeringLeaderName)
|
||||||
|
}}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
|
||||||
@@ -177,13 +188,20 @@
|
|||||||
<el-row :gutter="16" class="mb-16px">
|
<el-row :gutter="16" class="mb-16px">
|
||||||
<el-col v-for="item in annualSummaryCards" :key="item.label" :span="8">
|
<el-col v-for="item in annualSummaryCards" :key="item.label" :span="8">
|
||||||
<div class="rounded-8px bg-[var(--el-fill-color-light)] px-16px py-12px">
|
<div class="rounded-8px bg-[var(--el-fill-color-light)] px-16px py-12px">
|
||||||
<div class="text-12px text-[var(--el-text-color-secondary)]">{{ item.label }}</div>
|
<div class="text-12px text-[var(--el-text-color-secondary)]">{{
|
||||||
|
item.label
|
||||||
|
}}</div>
|
||||||
<div class="mt-6px text-18px font-600">{{ formatAmountText(item.amount) }}</div>
|
<div class="mt-6px text-18px font-600">{{ formatAmountText(item.amount) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-table v-loading="quarterLoading" :data="annualDistributionRows" border>
|
<el-table :data="annualDistributionRows" border>
|
||||||
<el-table-column align="center" label="分配年度" min-width="120" prop="distributionYear" />
|
<el-table-column
|
||||||
|
align="center"
|
||||||
|
label="分配年度"
|
||||||
|
min-width="120"
|
||||||
|
prop="distributionYear"
|
||||||
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-for="quarter in QUARTER_OPTIONS"
|
v-for="quarter in QUARTER_OPTIONS"
|
||||||
:key="String(quarter.value)"
|
:key="String(quarter.value)"
|
||||||
@@ -201,10 +219,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</ContentWrap>
|
</template>
|
||||||
|
|
||||||
<ContentWrap v-else>
|
<el-empty v-else-if="!quarterLoading" description="请选择合约规划后查看分配结果" />
|
||||||
<el-empty description="请选择合约规划后查看分配结果" />
|
</div>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -618,14 +636,12 @@ const loadPlanningRelatedData = async (planning: PlanningApi.ProjectPlanningVO)
|
|||||||
}
|
}
|
||||||
quarterLoading.value = true
|
quarterLoading.value = true
|
||||||
try {
|
try {
|
||||||
const [planningDetail, outputSplit, quarterList] = await Promise.all([
|
const detail = await OutputSplitApi.getProjectOutputSplitPlanningDetail(planning.id)
|
||||||
PlanningApi.getProjectPlanning(planning.id),
|
currentPlanning.value = detail?.planning
|
||||||
OutputSplitApi.getProjectOutputSplitByPlanningId(planning.id),
|
formData.value = detail?.outputSplit
|
||||||
PlanningQuarterApi.getProjectPlanningQuarterListByPlanningId(planning.id)
|
quarterRows.value = detail?.planning
|
||||||
])
|
? buildQuarterRows(detail.planning, detail.quarters || [])
|
||||||
currentPlanning.value = planningDetail
|
: []
|
||||||
formData.value = outputSplit
|
|
||||||
quarterRows.value = buildQuarterRows(planningDetail, quarterList)
|
|
||||||
} finally {
|
} finally {
|
||||||
quarterLoading.value = false
|
quarterLoading.value = false
|
||||||
}
|
}
|
||||||
@@ -723,11 +739,18 @@ const handleSave = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1192,12 +1192,17 @@ const open = async (id: number) => {
|
|||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
formLoading.value = true
|
formLoading.value = true
|
||||||
try {
|
try {
|
||||||
const data = await PlanningApi.getProjectPlanning(id)
|
const detail = await PlanningApi.getProjectPlanningOutputEditDetail(id)
|
||||||
formData.value = normalizeFormData(data)
|
if (!detail?.planning) {
|
||||||
|
formData.value = createFormData()
|
||||||
|
guideDetails.value = []
|
||||||
|
dialogVisible.value = false
|
||||||
|
message.warning('合约规划不存在或已被删除')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
formData.value = normalizeFormData(detail.planning)
|
||||||
guideDetails.value = showGuideDetailSection.value
|
guideDetails.value = showGuideDetailSection.value
|
||||||
? normalizeGuideDetailList(
|
? normalizeGuideDetailList(detail.guideDetails)
|
||||||
await PlanningGuideDetailApi.getProjectPlanningGuideDetailListByPlanningId(id)
|
|
||||||
)
|
|
||||||
: []
|
: []
|
||||||
applyCalculationRatioDefault()
|
applyCalculationRatioDefault()
|
||||||
if (formData.value.reviewOutsourceRatio === undefined || formData.value.reviewOutsourceRatio === null) {
|
if (formData.value.reviewOutsourceRatio === undefined || formData.value.reviewOutsourceRatio === null) {
|
||||||
|
|||||||
@@ -205,7 +205,24 @@ const open = async (id: number) => {
|
|||||||
loading.value = true
|
loading.value = true
|
||||||
deletedQuarterIds.value = []
|
deletedQuarterIds.value = []
|
||||||
try {
|
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 = {
|
formData.value = {
|
||||||
...planning,
|
...planning,
|
||||||
contractValueQuantity: planning.contractValueQuantity ?? 1,
|
contractValueQuantity: planning.contractValueQuantity ?? 1,
|
||||||
@@ -214,8 +231,7 @@ const open = async (id: number) => {
|
|||||||
totalDistributionAmount: planning.totalDistributionAmount ?? 1,
|
totalDistributionAmount: planning.totalDistributionAmount ?? 1,
|
||||||
progressRemark: planning.progressRemark ?? ''
|
progressRemark: planning.progressRemark ?? ''
|
||||||
}
|
}
|
||||||
const quarterList = await PlanningQuarterApi.getProjectPlanningQuarterListByPlanningId(id)
|
quarterRows.value = buildQuarterRows(formData.value, detail.quarters || [])
|
||||||
quarterRows.value = buildQuarterRows(formData.value, quarterList)
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,7 +166,9 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="15">
|
<el-col :span="15">
|
||||||
<ContentWrap v-if="currentPlanning">
|
<div v-loading="quarterLoading" class="min-h-320px">
|
||||||
|
<template v-if="currentPlanning">
|
||||||
|
<ContentWrap>
|
||||||
<div class="mb-16px flex items-center justify-between gap-16px">
|
<div class="mb-16px flex items-center justify-between gap-16px">
|
||||||
<div>
|
<div>
|
||||||
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
||||||
@@ -298,7 +300,7 @@
|
|||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
|
||||||
<ContentWrap v-if="currentPlanning">
|
<ContentWrap>
|
||||||
<div class="mb-16px flex items-center justify-between gap-16px">
|
<div class="mb-16px flex items-center justify-between gap-16px">
|
||||||
<div>
|
<div>
|
||||||
<div class="text-14px font-600">季度分配</div>
|
<div class="text-14px font-600">季度分配</div>
|
||||||
@@ -348,7 +350,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-table v-loading="quarterLoading" :data="quarterRows" border>
|
<el-table :data="quarterRows" border>
|
||||||
<el-table-column align="center" label="分配年度" width="150" prop="distributionYear" />
|
<el-table-column align="center" label="分配年度" width="150" prop="distributionYear" />
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-for="quarter in QUARTER_OPTIONS"
|
v-for="quarter in QUARTER_OPTIONS"
|
||||||
@@ -366,10 +368,12 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
</template>
|
||||||
|
|
||||||
<ContentWrap v-else>
|
<ContentWrap v-else-if="!quarterLoading">
|
||||||
<el-empty description="请选择合约规划后查看测算结果和季度分配" />
|
<el-empty description="请选择合约规划后查看测算结果和季度分配" />
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
@@ -581,12 +585,11 @@ const getPlanningList = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadPlanningDetail = async (planningId: number) => {
|
const loadPlanningDetail = async (planningId: number) => {
|
||||||
const planning = await PlanningApi.getProjectPlanning(planningId)
|
|
||||||
currentPlanning.value = planning
|
|
||||||
quarterLoading.value = true
|
quarterLoading.value = true
|
||||||
try {
|
try {
|
||||||
const quarterList = await PlanningQuarterApi.getProjectPlanningQuarterListByPlanningId(planningId)
|
const detail = await PlanningQuarterApi.getProjectPlanningQuarterPlanningDetail(planningId)
|
||||||
quarterRows.value = buildQuarterRows(planning, quarterList)
|
currentPlanning.value = detail?.planning
|
||||||
|
quarterRows.value = detail?.planning ? buildQuarterRows(detail.planning, detail.quarters || []) : []
|
||||||
} finally {
|
} finally {
|
||||||
quarterLoading.value = false
|
quarterLoading.value = false
|
||||||
}
|
}
|
||||||
@@ -643,11 +646,18 @@ const handlePlanningOutputFormSuccess = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -159,7 +159,9 @@
|
|||||||
/>
|
/>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
|
||||||
<ContentWrap v-if="currentProfit">
|
<ContentWrap>
|
||||||
|
<div v-loading="detailLoading" class="min-h-220px">
|
||||||
|
<template v-if="currentProfit">
|
||||||
<div class="mb-16px flex items-center justify-between gap-16px">
|
<div class="mb-16px flex items-center justify-between gap-16px">
|
||||||
<div class="text-16px font-600">{{ currentProfit.projectName }}</div>
|
<div class="text-16px font-600">{{ currentProfit.projectName }}</div>
|
||||||
<el-button plain type="primary" @click="openProfitEditDialog">
|
<el-button plain type="primary" @click="openProfitEditDialog">
|
||||||
@@ -220,10 +222,10 @@
|
|||||||
</span>
|
</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</ContentWrap>
|
</template>
|
||||||
|
|
||||||
<ContentWrap v-else>
|
<el-empty v-else-if="!detailLoading" description="请选择项目后查看盈亏详情" />
|
||||||
<el-empty description="请选择项目后查看盈亏详情" />
|
</div>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
|
||||||
<Dialog v-model="dialogVisible" title="编辑盈亏参数" width="520">
|
<Dialog v-model="dialogVisible" title="编辑盈亏参数" width="520">
|
||||||
@@ -286,6 +288,7 @@ const message = useMessage()
|
|||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
const detailLoading = ref(false)
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const list = ref<ProfitApi.ProjectProfitVO[]>([])
|
const list = ref<ProfitApi.ProjectProfitVO[]>([])
|
||||||
const currentProfit = ref<ProfitApi.ProjectProfitVO>()
|
const currentProfit = ref<ProfitApi.ProjectProfitVO>()
|
||||||
@@ -337,21 +340,24 @@ const queryProjectStartYearValue = computed({
|
|||||||
|
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
let targetProfit: ProfitApi.ProjectProfitVO | undefined
|
||||||
try {
|
try {
|
||||||
const data = await ProfitApi.getProjectProfitPage(queryParams)
|
const data = await ProfitApi.getProjectProfitPage(queryParams)
|
||||||
list.value = data.list
|
list.value = data.list
|
||||||
total.value = data.total
|
total.value = data.total
|
||||||
if (!list.value.length) {
|
if (!list.value.length) {
|
||||||
currentProfit.value = undefined
|
currentProfit.value = undefined
|
||||||
return
|
} else {
|
||||||
}
|
|
||||||
const targetProjectId = currentProfit.value?.projectId || list.value[0].projectId
|
const targetProjectId = currentProfit.value?.projectId || list.value[0].projectId
|
||||||
const targetProfit = list.value.find((item) => item.projectId === targetProjectId) || list.value[0]
|
targetProfit = list.value.find((item) => item.projectId === targetProjectId) || list.value[0]
|
||||||
await nextTick()
|
}
|
||||||
profitTableRef.value?.setCurrentRow(targetProfit)
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
if (targetProfit) {
|
||||||
|
await nextTick()
|
||||||
|
profitTableRef.value?.setCurrentRow(targetProfit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
@@ -369,14 +375,24 @@ const handleCurrentProfitChange = async (row?: ProfitApi.ProjectProfitVO) => {
|
|||||||
currentProfit.value = undefined
|
currentProfit.value = undefined
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
detailLoading.value = true
|
||||||
|
try {
|
||||||
currentProfit.value = await ProfitApi.getProjectProfit(row.projectId)
|
currentProfit.value = await ProfitApi.getProjectProfit(row.projectId)
|
||||||
|
} finally {
|
||||||
|
detailLoading.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshCurrentProfit = async () => {
|
const refreshCurrentProfit = async () => {
|
||||||
if (!currentProfit.value?.projectId) {
|
if (!currentProfit.value?.projectId) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
detailLoading.value = true
|
||||||
|
try {
|
||||||
currentProfit.value = await ProfitApi.getProjectProfit(currentProfit.value.projectId)
|
currentProfit.value = await ProfitApi.getProjectProfit(currentProfit.value.projectId)
|
||||||
|
} finally {
|
||||||
|
detailLoading.value = false
|
||||||
|
}
|
||||||
await getList()
|
await getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,11 +456,18 @@ const profitLossClass = (value?: number) => {
|
|||||||
const isUsingContractAmount = (row?: ProfitApi.ProjectProfitVO) =>
|
const isUsingContractAmount = (row?: ProfitApi.ProjectProfitVO) =>
|
||||||
!!row && Number(row.finalSettlementAmount || 0) <= 0 && Number(row.contractAmount || 0) > 0
|
!!row && Number(row.finalSettlementAmount || 0) <= 0 && Number(row.contractAmount || 0) > 0
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -526,11 +526,18 @@ const handlePlanningFormSuccess = async () => {
|
|||||||
await getPlanningList()
|
await getPlanningList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -384,11 +384,18 @@ const submitProjectBudgetExport = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -103,7 +103,9 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<ContentWrap v-if="currentPlanning && formData">
|
<ContentWrap>
|
||||||
|
<div v-loading="quarterLoading" class="min-h-320px">
|
||||||
|
<template v-if="currentPlanning && formData">
|
||||||
<div class="mb-16px flex items-center justify-between gap-16px">
|
<div class="mb-16px flex items-center justify-between gap-16px">
|
||||||
<div>
|
<div>
|
||||||
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
||||||
@@ -193,7 +195,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-table v-loading="quarterLoading" :data="annualDistributionRows" border>
|
<el-table :data="annualDistributionRows" border>
|
||||||
<el-table-column align="center" label="分配年度" min-width="120" prop="distributionYear" />
|
<el-table-column align="center" label="分配年度" min-width="120" prop="distributionYear" />
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-for="quarter in QUARTER_OPTIONS"
|
v-for="quarter in QUARTER_OPTIONS"
|
||||||
@@ -212,10 +214,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</ContentWrap>
|
</template>
|
||||||
|
|
||||||
<ContentWrap v-else>
|
<el-empty v-else-if="!quarterLoading" description="请选择合约规划后查看导出预览" />
|
||||||
<el-empty description="请选择合约规划后查看导出预览" />
|
</div>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -566,14 +568,12 @@ const loadPlanningRelatedData = async (planning: PlanningApi.ProjectPlanningVO)
|
|||||||
}
|
}
|
||||||
quarterLoading.value = true
|
quarterLoading.value = true
|
||||||
try {
|
try {
|
||||||
const [planningDetail, outputSplit, quarterList] = await Promise.all([
|
const detail = await OutputSplitApi.getProjectOutputSplitPlanningDetail(planning.id)
|
||||||
PlanningApi.getProjectPlanning(planning.id),
|
currentPlanning.value = detail?.planning
|
||||||
OutputSplitApi.getProjectOutputSplitByPlanningId(planning.id),
|
formData.value = detail?.outputSplit
|
||||||
PlanningQuarterApi.getProjectPlanningQuarterListByPlanningId(planning.id)
|
quarterRows.value = detail?.planning
|
||||||
])
|
? buildQuarterRows(detail.planning, detail.quarters || [])
|
||||||
currentPlanning.value = planningDetail
|
: []
|
||||||
formData.value = outputSplit
|
|
||||||
quarterRows.value = buildQuarterRows(planningDetail, quarterList)
|
|
||||||
} finally {
|
} finally {
|
||||||
quarterLoading.value = false
|
quarterLoading.value = false
|
||||||
}
|
}
|
||||||
@@ -684,11 +684,18 @@ const submitProjectLeadQuarterExport = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -105,7 +105,9 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<ContentWrap v-if="currentPlanning && currentGroup">
|
<ContentWrap>
|
||||||
|
<div v-loading="previewLoading" class="min-h-320px">
|
||||||
|
<template v-if="currentPlanning && currentGroup">
|
||||||
<div class="mb-16px flex items-center justify-between gap-12px">
|
<div class="mb-16px flex items-center justify-between gap-12px">
|
||||||
<div>
|
<div>
|
||||||
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
||||||
@@ -252,10 +254,10 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</ContentWrap>
|
</template>
|
||||||
|
|
||||||
<ContentWrap v-else>
|
<el-empty v-else-if="!previewLoading" description="请选择合约规划后查看导出预览" />
|
||||||
<el-empty description="请选择合约规划后查看导出预览" />
|
</div>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -545,11 +547,18 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -565,7 +565,14 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// immediate watch 已经负责首次预览加载,跳过 KeepAlive 首轮激活避免重复请求。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
refreshCurrentPreview()
|
refreshCurrentPreview()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,9 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<ContentWrap v-if="currentPlanning && currentGroup">
|
<ContentWrap>
|
||||||
|
<div v-loading="roleLoading" class="min-h-320px">
|
||||||
|
<template v-if="currentPlanning && currentGroup">
|
||||||
<div class="mb-16px flex items-center justify-between gap-12px">
|
<div class="mb-16px flex items-center justify-between gap-12px">
|
||||||
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
||||||
<div class="flex items-center gap-12px">
|
<div class="flex items-center gap-12px">
|
||||||
@@ -172,10 +174,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</ContentWrap>
|
</template>
|
||||||
|
|
||||||
<ContentWrap v-else>
|
<el-empty v-else-if="!roleLoading" description="请选择合约规划后查看人员分配" />
|
||||||
<el-empty description="请选择合约规划后查看人员分配" />
|
</div>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -306,7 +308,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button :loading="saveLoading" type="primary" @click="handleSave">保存</el-button>
|
<el-button :loading="saveLoading" @click="handleTemporarySave">临时保存</el-button>
|
||||||
|
<el-button :loading="saveLoading" type="primary" @click="handleSave">校验保存</el-button>
|
||||||
<el-button @click="dialogVisible = false">取消</el-button>
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
</template>
|
</template>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -349,6 +352,7 @@ const message = useMessage()
|
|||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const planningLoading = ref(false)
|
const planningLoading = ref(false)
|
||||||
|
const roleLoading = ref(false)
|
||||||
const saveLoading = ref(false)
|
const saveLoading = ref(false)
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const projectList = ref<ProjectApi.ProjectVO[]>([])
|
const projectList = ref<ProjectApi.ProjectVO[]>([])
|
||||||
@@ -374,7 +378,7 @@ const queryParams = reactive<ProjectApi.ProjectPageReqVO>({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const getProjectRowIndex = (index: number) =>
|
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({
|
const queryProjectStartYearValue = computed({
|
||||||
get: () => (queryParams.projectStartYear ? String(queryParams.projectStartYear) : undefined),
|
get: () => (queryParams.projectStartYear ? String(queryParams.projectStartYear) : undefined),
|
||||||
@@ -681,7 +685,8 @@ const updateRoleRatio = (row: SpecialtyRoleSplitVO, value?: number) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const buildSavePersons = (
|
const buildSavePersons = (
|
||||||
row: SpecialtyRoleSplitVO
|
row: SpecialtyRoleSplitVO,
|
||||||
|
validate: boolean
|
||||||
):
|
):
|
||||||
| { persons: SpecialtyRolePersonVO[]; error?: never }
|
| { persons: SpecialtyRolePersonVO[]; error?: never }
|
||||||
| { persons?: never; error: string } => {
|
| { persons?: never; error: string } => {
|
||||||
@@ -693,35 +698,39 @@ const buildSavePersons = (
|
|||||||
if (!hasEmployeeId && !hasRatio) {
|
if (!hasEmployeeId && !hasRatio) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (!hasEmployeeId || !hasRatio) {
|
if (!validate && !hasEmployeeId) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (validate && (!hasEmployeeId || !hasRatio)) {
|
||||||
return { error: `${row.roleName} 的员工和比例必须同时填写` }
|
return { error: `${row.roleName} 的员工和比例必须同时填写` }
|
||||||
}
|
}
|
||||||
persons.push({
|
persons.push({
|
||||||
employeeId: person.employeeId,
|
employeeId: person.employeeId,
|
||||||
employeeName: employeeName || undefined,
|
employeeName: employeeName || undefined,
|
||||||
personRatio: roundRatio(person.personRatio)
|
personRatio: roundRatio(hasRatio ? person.personRatio : 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return { persons }
|
return { persons }
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateAndBuildSaveItems = () => {
|
const buildSaveItems = (validate: boolean) => {
|
||||||
const items: SpecialtyRoleSplitApi.SpecialtyRoleSplitSaveItemVO[] = []
|
const items: SpecialtyRoleSplitApi.SpecialtyRoleSplitSaveItemVO[] = []
|
||||||
for (const group of editGroups.value) {
|
for (const group of editGroups.value) {
|
||||||
let roleTotal = 0
|
let roleTotal = 0
|
||||||
for (const row of group.rows) {
|
for (const row of group.rows) {
|
||||||
const result = buildSavePersons(row)
|
const result = buildSavePersons(row, validate)
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
message.warning(result.error)
|
message.warning(result.error)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
const persons = result.persons || []
|
const persons = result.persons || []
|
||||||
const personTotalRatio = sumPersonRatios(persons)
|
const personTotalRatio = sumPersonRatios(persons)
|
||||||
if (personTotalRatio > 1 + EPSILON) {
|
if (validate && personTotalRatio > 1 + EPSILON) {
|
||||||
message.warning(`${group.specialtyName}-${row.roleName} 的人员比例合计不能大于 100%`)
|
message.warning(`${group.specialtyName}-${row.roleName} 的人员比例合计不能大于 100%`)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
|
validate &&
|
||||||
row.roleCode === DESIGN_ROLE_CODE &&
|
row.roleCode === DESIGN_ROLE_CODE &&
|
||||||
Number(row.roleAmount || 0) > EPSILON &&
|
Number(row.roleAmount || 0) > EPSILON &&
|
||||||
persons.length === 0
|
persons.length === 0
|
||||||
@@ -737,7 +746,7 @@ const validateAndBuildSaveItems = () => {
|
|||||||
persons: isProjectLeadRow(row) ? [] : persons
|
persons: isProjectLeadRow(row) ? [] : persons
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (Math.abs(roleTotal - 1) > EPSILON) {
|
if (validate && Math.abs(roleTotal - 1) > EPSILON) {
|
||||||
message.warning(`${group.specialtyName} 的角色比例合计必须等于 100%`)
|
message.warning(`${group.specialtyName} 的角色比例合计必须等于 100%`)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
@@ -798,10 +807,15 @@ const getPlanningList = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadRoleList = async (planningId: number) => {
|
const loadRoleList = async (planningId: number) => {
|
||||||
|
roleLoading.value = true
|
||||||
|
try {
|
||||||
const data = await SpecialtyRoleSplitApi.getSpecialtyRoleSplitListByPlanningId(planningId)
|
const data = await SpecialtyRoleSplitApi.getSpecialtyRoleSplitListByPlanningId(planningId)
|
||||||
roleList.value = cloneRoleRows(data)
|
roleList.value = cloneRoleRows(data)
|
||||||
roleList.value.forEach((row) => syncRoleRatiosForGroup(roleList.value, row.specialtyCode))
|
roleList.value.forEach((row) => syncRoleRatiosForGroup(roleList.value, row.specialtyCode))
|
||||||
syncAllDerivedValues(roleList.value)
|
syncAllDerivedValues(roleList.value)
|
||||||
|
} finally {
|
||||||
|
roleLoading.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
@@ -841,11 +855,11 @@ const openEditDialog = () => {
|
|||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSave = async () => {
|
const saveRoleSplit = async (temporarySave: boolean) => {
|
||||||
if (!currentPlanning.value?.id) {
|
if (!currentPlanning.value?.id) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const items = validateAndBuildSaveItems()
|
const items = buildSaveItems(!temporarySave)
|
||||||
if (!items) {
|
if (!items) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -853,21 +867,35 @@ const handleSave = async () => {
|
|||||||
try {
|
try {
|
||||||
await SpecialtyRoleSplitApi.saveSpecialtyRoleSplitBatch({
|
await SpecialtyRoleSplitApi.saveSpecialtyRoleSplitBatch({
|
||||||
planningId: currentPlanning.value.id,
|
planningId: currentPlanning.value.id,
|
||||||
items
|
items,
|
||||||
|
temporarySave
|
||||||
})
|
})
|
||||||
message.success('保存成功')
|
message.success(temporarySave ? '临时保存成功' : '保存成功')
|
||||||
|
if (!temporarySave) {
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
await loadRoleList(currentPlanning.value.id)
|
await loadRoleList(currentPlanning.value.id)
|
||||||
} finally {
|
} finally {
|
||||||
saveLoading.value = false
|
saveLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleTemporarySave = () => saveRoleSplit(true)
|
||||||
|
|
||||||
|
const handleSave = () => saveRoleSplit(false)
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getProjectList()
|
getProjectList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -299,11 +299,18 @@ const handleDelete = async (id: number) => {
|
|||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let activatedOnce = false
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求列表。
|
||||||
|
if (!activatedOnce) {
|
||||||
|
activatedOnce = true
|
||||||
|
return
|
||||||
|
}
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user