Files
tjt_czjs_ui/src/views/tjt/profit/index.vue

816 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<ContentWrap>
<el-form
ref="queryFormRef"
:inline="true"
:model="queryParams"
class="-mb-15px"
label-width="88px"
>
<el-form-item label="项目名称" prop="projectName">
<el-input
v-model="queryParams.projectName"
class="!w-240px"
clearable
placeholder="请输入项目名称"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="是否签约" prop="contractSignedFlag">
<el-select
v-model="queryParams.contractSignedFlag"
class="!w-180px"
clearable
placeholder="请选择"
>
<el-option
v-for="item in CONTRACT_SIGN_OPTIONS"
:key="String(item.value)"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="开始年度" prop="projectStartYear">
<el-date-picker
v-model="queryProjectStartYearValue"
class="!w-180px"
clearable
placeholder="请选择年度"
type="year"
value-format="YYYY"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" />
搜索
</el-button>
<el-button @click="resetQuery">
<Icon class="mr-5px" icon="ep:refresh" />
重置
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<ContentWrap>
<el-table
ref="profitTableRef"
v-loading="loading"
:data="list"
highlight-current-row
@current-change="handleCurrentProfitChange"
>
<el-table-column
:index="getProjectRowIndex"
align="center"
label="序号"
type="index"
width="80"
/>
<el-table-column align="center" label="项目名称" min-width="220" prop="projectName" />
<el-table-column align="center" label="是否签约" width="100">
<template #default="scope">
<el-tag :type="scope.row.contractSignedFlag ? 'success' : 'info'">
{{ scope.row.contractSignedFlag ? '已签订' : '未签订' }}
</el-tag>
</template>
</el-table-column>
<el-table-column align="center" label="开始年度" prop="projectStartYear" width="100" />
<el-table-column align="center" label="合同总产值(元)" width="120">
<template #default="scope">
{{ formatAmountText(scope.row.contractAmount) }}
</template>
</el-table-column>
<el-table-column align="center" label="结算合同总产值(元)" width="150">
<template #default="scope">
{{ formatAmountText(scope.row.finalSettlementAmount) }}
</template>
</el-table-column>
<el-table-column align="center" label="项目预算产值总计(元)" width="160">
<template #default="scope">
{{ formatAmountText(scope.row.effectiveSettlementAmount) }}
</template>
</el-table-column>
<el-table-column align="center" label="综合所人工成本(元)" width="150">
<template #default="scope">
{{ formatAmountText(scope.row.comprehensivePlanningAmount) }}
</template>
</el-table-column>
<el-table-column align="center" label="专项分包(专业所成本)(元)" width="210">
<template #default="scope">
{{ formatAmountText(scope.row.specialSubcontractPlanningAmount) }}
</template>
</el-table-column>
<el-table-column align="center" label="专项分包(源头合作成本)(元)" width="240">
<template #default="scope">
{{ formatAmountText(scope.row.sourceCoopSubcontractPlanningAmount) }}
</template>
</el-table-column>
<el-table-column align="center" label="专项分包(综合所成本)(元)" width="220">
<template #default="scope">
{{ formatAmountText(scope.row.comprehensiveSubcontractPlanningAmount) }}
</template>
</el-table-column>
<el-table-column align="center" label="专业所人工成本(元)" width="150">
<template #default="scope">
{{ formatAmountText(scope.row.majorExpectedPerformance) }}
</template>
</el-table-column>
<el-table-column align="center" label="专业所考核产值(元)" width="150">
<template #default="scope">
{{ formatAmountText(scope.row.majorOutputValue) }}
</template>
</el-table-column>
<el-table-column align="center" label="科创产值比例" width="110">
<template #default="scope">
{{ formatPercentText(scope.row.innovationOutputRate) }}
</template>
</el-table-column>
<el-table-column align="center" label="科创产值(元)" width="130">
<template #default="scope">
{{ formatAmountText(scope.row.innovationOutputValue) }}
</template>
</el-table-column>
<el-table-column align="center" label="其他成本(元)" width="130">
<template #default="scope">
{{ formatAmountText(scope.row.otherCost) }}
</template>
</el-table-column>
<el-table-column align="center" label="预算盈亏值(元)" width="130">
<template #default="scope">
<span :class="profitLossClass(scope.row.profitLossValue)">
{{ formatAmountText(scope.row.profitLossValue) }}
</span>
</template>
</el-table-column>
<el-table-column align="center" label="预算盈亏百分比" width="140">
<template #default="scope">
<span :class="profitLossClass(scope.row.profitLossValue)">
{{ formatPercentText(scope.row.profitLossRate) }}
</span>
</template>
</el-table-column>
<el-table-column align="center" label="排序" prop="sortNo" width="80" />
</el-table>
<Pagination
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNo"
:total="total"
@pagination="getList"
/>
</ContentWrap>
<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="text-16px font-600">{{ currentProfit.projectName }}</div>
<el-button plain type="primary" @click="openProfitEditDialog">
<Icon class="mr-5px" icon="ep:edit" />
编辑项目成本参数
</el-button>
</div>
<section class="mb-28px">
<div class="mb-12px flex items-center justify-between gap-16px">
<div>
<div class="text-15px font-600">项目成本预算测算表</div>
<div class="mt-4px flex flex-wrap items-center gap-10px text-13px text-[var(--el-text-color-secondary)]">
<el-tag :type="budgetSnapshot ? 'success' : 'info'">
{{ budgetSnapshot ? '已锁定' : '动态测算' }}
</el-tag>
<span>{{ snapshotActionText(budgetSnapshot) }}</span>
</div>
</div>
<el-button
:disabled="!!budgetSnapshot"
:loading="actionLoading === 'budget'"
type="primary"
@click="handleLockBudgetSnapshot"
>
目标责任书下达
</el-button>
</div>
<el-alert
v-if="!budgetSnapshot"
class="mb-12px"
:closable="false"
show-icon
title="当前展示实时动态测算值。点击“目标责任书下达”后,本阶段数据会生成快照并锁定。"
type="info"
/>
<el-descriptions v-if="budgetDisplay" :column="3" border>
<el-descriptions-item label="合同总产值(元)">
{{ formatAmountText(budgetDisplay.contractAmount) }}
</el-descriptions-item>
<el-descriptions-item label="结算合同总产值(元)">
{{ formatAmountText(budgetDisplay.finalSettlementAmount) }}
</el-descriptions-item>
<el-descriptions-item label="项目预算产值总计(元)">
{{ formatAmountText(budgetDisplay.effectiveSettlementAmount) }}
</el-descriptions-item>
<el-descriptions-item label="项目开始年度">
{{ currentProfit.projectStartYear || '-' }}
</el-descriptions-item>
<el-descriptions-item label="综合所人工成本(元)">
{{ formatAmountText(budgetDisplay.comprehensivePlanningAmount) }}
</el-descriptions-item>
<el-descriptions-item label="专项分包(专业所成本)(元)">
{{ formatAmountText(budgetDisplay.specialSubcontractPlanningAmount) }}
</el-descriptions-item>
<el-descriptions-item label="专项分包(源头合作成本)(元)">
{{ formatAmountText(budgetDisplay.sourceCoopSubcontractPlanningAmount) }}
</el-descriptions-item>
<el-descriptions-item label="专项分包(综合所成本)(元)">
{{ formatAmountText(budgetDisplay.comprehensiveSubcontractPlanningAmount) }}
</el-descriptions-item>
<el-descriptions-item label="专业所人工成本(元)">
{{ formatAmountText(budgetDisplay.majorExpectedPerformance) }}
</el-descriptions-item>
<el-descriptions-item label="专业所考核产值(元)">
{{ formatAmountText(budgetDisplay.majorOutputValue) }}
</el-descriptions-item>
<el-descriptions-item label="科创产值比例">
{{ formatPercentText(budgetDisplay.innovationOutputRate) }}
</el-descriptions-item>
<el-descriptions-item label="科创产值(元)">
{{ formatAmountText(budgetDisplay.innovationOutputValue) }}
</el-descriptions-item>
<el-descriptions-item label="其他成本(元)">
{{ formatAmountText(budgetDisplay.otherCost) }}
</el-descriptions-item>
<el-descriptions-item label="预算盈亏值(元)">
<span :class="profitLossClass(budgetDisplay.profitLossValue)">
{{ formatAmountText(budgetDisplay.profitLossValue) }}
</span>
</el-descriptions-item>
<el-descriptions-item label="预算盈亏百分比">
<span :class="profitLossClass(budgetDisplay.profitLossValue)">
{{ formatPercentText(budgetDisplay.profitLossRate) }}
</span>
</el-descriptions-item>
</el-descriptions>
</section>
<section class="mb-28px">
<div class="mb-12px flex items-center justify-between gap-16px">
<div>
<div class="text-15px font-600">项目成本核算测算表</div>
<div class="mt-4px flex flex-wrap items-center gap-10px text-13px text-[var(--el-text-color-secondary)]">
<el-tag :type="accountingSnapshot ? 'success' : 'info'">
{{ accountingSnapshot ? '已锁定' : '动态测算' }}
</el-tag>
<span>{{ snapshotActionText(accountingSnapshot) }}</span>
</div>
</div>
<el-button
:disabled="!budgetSnapshot || !!accountingSnapshot"
:loading="actionLoading === 'accounting'"
type="primary"
@click="handleLockAccountingSnapshot"
>
竣工验收完成
</el-button>
</div>
<el-alert
v-if="!budgetSnapshot"
class="mb-12px"
:closable="false"
show-icon
title="请先下达目标责任书,锁定项目成本预算测算后,才能完成竣工验收。"
type="warning"
/>
<el-alert
v-else-if="!accountingSnapshot"
class="mb-12px"
:closable="false"
show-icon
title="当前展示实时动态测算值。点击“竣工验收完成”后,本阶段数据会生成快照并锁定。"
type="info"
/>
<el-descriptions v-if="accountingDisplay" :column="3" border>
<el-descriptions-item label="合同总产值(元)">
{{ formatAmountText(accountingDisplay.contractAmount) }}
</el-descriptions-item>
<el-descriptions-item label="结算合同总产值(元)">
{{ formatAmountText(accountingDisplay.finalSettlementAmount) }}
</el-descriptions-item>
<el-descriptions-item label="项目预算产值总计(元)">
{{ formatAmountText(accountingDisplay.effectiveSettlementAmount) }}
</el-descriptions-item>
<el-descriptions-item label="项目开始年度">
{{ currentProfit.projectStartYear || '-' }}
</el-descriptions-item>
<el-descriptions-item label="综合所人工成本(元)">
{{ formatAmountText(accountingDisplay.comprehensivePlanningAmount) }}
</el-descriptions-item>
<el-descriptions-item label="专项分包(专业所成本)(元)">
{{ formatAmountText(accountingDisplay.specialSubcontractPlanningAmount) }}
</el-descriptions-item>
<el-descriptions-item label="专项分包(源头合作成本)(元)">
{{ formatAmountText(accountingDisplay.sourceCoopSubcontractPlanningAmount) }}
</el-descriptions-item>
<el-descriptions-item label="专项分包(综合所成本)(元)">
{{ formatAmountText(accountingDisplay.comprehensiveSubcontractPlanningAmount) }}
</el-descriptions-item>
<el-descriptions-item label="专业所人工成本(元)">
{{ formatAmountText(accountingDisplay.majorExpectedPerformance) }}
</el-descriptions-item>
<el-descriptions-item label="专业所考核产值(元)">
{{ formatAmountText(accountingDisplay.majorOutputValue) }}
</el-descriptions-item>
<el-descriptions-item label="科创产值比例">
{{ formatPercentText(accountingDisplay.innovationOutputRate) }}
</el-descriptions-item>
<el-descriptions-item label="科创产值(元)">
{{ formatAmountText(accountingDisplay.innovationOutputValue) }}
</el-descriptions-item>
<el-descriptions-item label="其他成本(元)">
{{ formatAmountText(accountingDisplay.otherCost) }}
</el-descriptions-item>
<el-descriptions-item label="预算盈亏值(元)">
<span :class="profitLossClass(accountingDisplay.profitLossValue)">
{{ formatAmountText(accountingDisplay.profitLossValue) }}
</span>
</el-descriptions-item>
<el-descriptions-item label="预算盈亏百分比">
<span :class="profitLossClass(accountingDisplay.profitLossValue)">
{{ formatPercentText(accountingDisplay.profitLossRate) }}
</span>
</el-descriptions-item>
</el-descriptions>
</section>
<section>
<div class="mb-12px flex items-center justify-between gap-16px">
<div>
<div class="text-15px font-600">项目成本结算测算表</div>
<div class="mt-4px flex flex-wrap items-center gap-10px text-13px text-[var(--el-text-color-secondary)]">
<el-tag :type="settlementSnapshot ? 'success' : 'info'">
{{ settlementSnapshot ? '已保存' : '未保存' }}
</el-tag>
<span>{{ snapshotActionText(settlementSnapshot, '保存结算测算后会记录操作人和操作时间') }}</span>
</div>
</div>
</div>
<el-alert
v-if="!accountingSnapshot"
class="mb-12px"
:closable="false"
show-icon
title="请先点击“竣工验收完成”锁定项目成本核算测算,再维护结算测算。"
type="warning"
/>
<el-descriptions :column="2" border>
<el-descriptions-item label="综合所考核产值核算值(元)">
{{ formatAmountText(settlementComprehensiveAccountingValue) }}
</el-descriptions-item>
<el-descriptions-item label="综合所考核产值结算值(元)">
{{ formatAmountText(settlementComprehensiveSettlementValue) }}
</el-descriptions-item>
<el-descriptions-item label="专业所考核产值核算值(元)">
{{ formatAmountText(settlementMajorAccountingValue) }}
</el-descriptions-item>
<el-descriptions-item label="专业所考核产值结算值(元)">
{{ formatAmountText(settlementMajorSettlementValue) }}
</el-descriptions-item>
</el-descriptions>
<el-form
ref="settlementFormRef"
:disabled="!accountingSnapshot"
:model="settlementForm"
:rules="settlementRules"
class="mt-16px"
label-width="110px"
>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="考核结果" prop="assessmentResult">
<el-select
v-model="settlementForm.assessmentResult"
class="!w-1/1"
placeholder="请选择考核结果"
>
<el-option label="优秀" value="优秀" />
<el-option label="合格" value="合格" />
<el-option label="待改进" value="待改进" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="考核系数" prop="assessmentCoefficient">
<el-input :model-value="formatCoefficientText(settlementCoefficient)" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="操作" prop="action">
<el-button
:disabled="!accountingSnapshot"
:loading="actionLoading === 'settlement'"
type="primary"
@click="handleSaveSettlementSnapshot"
>
保存结算测算
</el-button>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input
v-model="settlementForm.remark"
:rows="2"
maxlength="500"
placeholder="请输入备注"
show-word-limit
type="textarea"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</section>
</template>
<el-empty v-else-if="!detailLoading" description="请选择项目后查看项目成本详情" />
</div>
</ContentWrap>
<Dialog v-model="dialogVisible" title="编辑项目成本参数" width="520">
<el-form ref="formRef" v-loading="dialogLoading" :model="formData" label-width="140px">
<el-form-item label="结算合同总产值(元)" prop="finalSettlementAmount">
<el-input-number
v-model="formData.finalSettlementAmount"
:min="0"
:precision="2"
:step="1000"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
<el-form-item label="科创产值比例(%)" prop="innovationOutputRate">
<el-input-number
v-model="innovationOutputRatePercent"
:min="0"
:max="100"
:precision="2"
:step="0.01"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
<el-form-item label="其他成本(元)" prop="otherCost">
<el-input-number
v-model="formData.otherCost"
:min="0"
:precision="2"
:step="1000"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button :disabled="dialogLoading" type="primary" @click="submitProfitForm">保存</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</template>
</Dialog>
</template>
<script lang="ts" setup>
import * as ProfitApi from '@/api/tjt/profit'
import * as ProjectApi from '@/api/tjt/project'
import {
CONTRACT_SIGN_OPTIONS,
DEFAULT_INNOVATION_OUTPUT_RATE,
formatAmountText,
formatPercentText,
fromPercentValue,
toPercentValue
} from '@/views/tjt/shared/planning'
import { formatDate } from '@/utils/formatTime'
defineOptions({ name: 'TjtProfit' })
const message = useMessage()
const { t } = useI18n()
const loading = ref(false)
const detailLoading = ref(false)
const actionLoading = ref<'budget' | 'accounting' | 'settlement' | ''>('')
const total = ref(0)
const list = ref<ProfitApi.ProjectProfitVO[]>([])
const currentProfit = ref<ProfitApi.ProjectProfitVO>()
const queryFormRef = ref()
const profitTableRef = ref()
const settlementFormRef = ref()
const settlementForm = reactive<ProfitApi.ProjectProfitSettlementSaveReqVO>({
projectId: 0,
assessmentResult: '合格',
remark: ''
})
const settlementRules = {
assessmentResult: [{ required: true, message: '请选择考核结果', trigger: 'change' }]
}
const dialogVisible = ref(false)
const dialogLoading = ref(false)
const formRef = ref()
const formData = ref<ProjectApi.ProjectVO>({
projectName: '',
contractSignedFlag: true,
innovationOutputRate: DEFAULT_INNOVATION_OUTPUT_RATE,
otherCost: 0,
rolePersons: []
})
const innovationOutputRatePercent = computed({
get: () => toPercentValue(formData.value.innovationOutputRate),
set: (value) => {
formData.value.innovationOutputRate = fromPercentValue(value)
}
})
const normalizeProjectFormData = (data: ProjectApi.ProjectVO): ProjectApi.ProjectVO => ({
...data,
innovationOutputRate: data.innovationOutputRate ?? DEFAULT_INNOVATION_OUTPUT_RATE,
otherCost: data.otherCost ?? 0,
rolePersons: data.rolePersons || []
})
const queryParams = reactive<ProfitApi.ProjectProfitPageReqVO>({
pageNo: 1,
pageSize: 10,
projectName: undefined,
contractSignedFlag: undefined,
projectStartYear: undefined
})
const getProjectRowIndex = (index: number) =>
(queryParams.pageNo - 1) * queryParams.pageSize + index + 1
const queryProjectStartYearValue = computed({
get: () => (queryParams.projectStartYear ? String(queryParams.projectStartYear) : undefined),
set: (value?: string) => {
queryParams.projectStartYear = value ? Number(value) : undefined
}
})
const budgetSnapshot = computed(() => currentProfit.value?.budgetSnapshot)
const accountingSnapshot = computed(() => currentProfit.value?.accountingSnapshot)
const settlementSnapshot = computed(() => currentProfit.value?.settlementSnapshot)
const budgetDisplay = computed(() => budgetSnapshot.value || currentProfit.value)
const accountingDisplay = computed(() => accountingSnapshot.value || currentProfit.value)
const settlementCoefficient = computed(() => getAssessmentCoefficient(settlementForm.assessmentResult))
const settlementComprehensiveAccountingValue = computed(() =>
Number(
settlementSnapshot.value?.comprehensiveAccountingOutputValue ??
accountingSnapshot.value?.comprehensivePlanningAmount ??
0
)
)
const settlementMajorAccountingValue = computed(() =>
Number(settlementSnapshot.value?.majorAccountingOutputValue ?? accountingSnapshot.value?.majorOutputValue ?? 0)
)
const settlementComprehensiveSettlementValue = computed(() =>
roundAmount(settlementComprehensiveAccountingValue.value * settlementCoefficient.value)
)
const settlementMajorSettlementValue = computed(() =>
roundAmount(settlementMajorAccountingValue.value * settlementCoefficient.value)
)
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
} else {
const targetProjectId = currentProfit.value?.projectId || list.value[0].projectId
targetProfit = list.value.find((item) => item.projectId === targetProjectId) || list.value[0]
}
} finally {
loading.value = false
}
if (targetProfit) {
await nextTick()
profitTableRef.value?.setCurrentRow(targetProfit)
}
}
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
const resetQuery = () => {
queryFormRef.value?.resetFields()
handleQuery()
}
const handleCurrentProfitChange = async (row?: ProfitApi.ProjectProfitVO) => {
if (!row?.projectId) {
currentProfit.value = undefined
return
}
detailLoading.value = true
try {
currentProfit.value = await ProfitApi.getProjectProfit(row.projectId)
} finally {
detailLoading.value = false
}
}
const refreshCurrentProfit = async () => {
if (!currentProfit.value?.projectId) {
return
}
detailLoading.value = true
try {
currentProfit.value = await ProfitApi.getProjectProfit(currentProfit.value.projectId)
} finally {
detailLoading.value = false
}
await getList()
}
const handleLockBudgetSnapshot = async () => {
if (!currentProfit.value?.projectId) {
return
}
await message.confirm('确认下达目标责任书并锁定当前项目成本预算测算吗?锁定后不能重复操作。')
actionLoading.value = 'budget'
try {
currentProfit.value = await ProfitApi.lockBudgetSnapshot(currentProfit.value.projectId)
message.success('目标责任书已下达')
await getList()
} finally {
actionLoading.value = ''
}
}
const handleLockAccountingSnapshot = async () => {
if (!currentProfit.value?.projectId) {
return
}
if (!budgetSnapshot.value) {
message.warning('请先下达目标责任书,再完成竣工验收')
return
}
await message.confirm('确认竣工验收完成并锁定当前项目成本核算测算吗?锁定后不能重复操作。')
actionLoading.value = 'accounting'
try {
currentProfit.value = await ProfitApi.lockAccountingSnapshot(currentProfit.value.projectId)
message.success('竣工验收已完成')
await getList()
} finally {
actionLoading.value = ''
}
}
const handleSaveSettlementSnapshot = async () => {
if (!currentProfit.value?.projectId || !accountingSnapshot.value) {
message.warning('请先完成竣工验收,再维护结算测算')
return
}
await settlementFormRef.value?.validate()
actionLoading.value = 'settlement'
try {
currentProfit.value = await ProfitApi.saveSettlementSnapshot({
projectId: currentProfit.value.projectId,
assessmentResult: settlementForm.assessmentResult,
remark: settlementForm.remark
})
message.success('结算测算已保存')
await getList()
} finally {
actionLoading.value = ''
}
}
const openProfitEditDialog = async () => {
if (!currentProfit.value?.projectId) {
return
}
dialogVisible.value = true
dialogLoading.value = true
try {
formData.value = normalizeProjectFormData(await ProjectApi.getProject(currentProfit.value.projectId))
} finally {
dialogLoading.value = false
}
}
const buildProjectSavePayload = (): ProjectApi.ProjectSaveVO => ({
id: formData.value.id,
projectName: formData.value.projectName,
contractSignedFlag: formData.value.contractSignedFlag,
contractAmount: formData.value.contractAmount,
totalConstructionArea: formData.value.totalConstructionArea,
constructionUnitName: formData.value.constructionUnitName,
contactName: formData.value.contactName,
contactPhone: formData.value.contactPhone,
contractSigningDate: formData.value.contractSigningDate,
projectType: formData.value.projectType,
projectCategory: formData.value.projectCategory,
projectStartYear: formData.value.projectStartYear,
projectStatus: formData.value.projectStatus,
pauseReason: formData.value.pauseReason,
terminateReason: formData.value.terminateReason,
finalSettlementAmount: formData.value.finalSettlementAmount,
innovationOutputRate: formData.value.innovationOutputRate,
otherCost: formData.value.otherCost,
rolePersons: formData.value.rolePersons || []
})
const submitProfitForm = async () => {
dialogLoading.value = true
try {
await ProjectApi.updateProject(buildProjectSavePayload())
message.success(t('common.updateSuccess'))
dialogVisible.value = false
await refreshCurrentProfit()
} finally {
dialogLoading.value = false
}
}
const profitLossClass = (value?: number) => {
if ((value || 0) > 0) {
return 'text-[var(--el-color-success)] font-600'
}
if ((value || 0) < 0) {
return 'text-[var(--el-color-danger)] font-600'
}
return 'text-[var(--el-text-color-primary)]'
}
const snapshotActionText = (
snapshot?: ProfitApi.ProjectProfitSnapshotVO,
emptyText = '当前为实时动态测算值,尚未锁定'
) => {
if (!snapshot) {
return emptyText
}
const actionName = snapshot.actionUserName || '未知操作人'
const actionTime = snapshot.actionTime ? formatDate(snapshot.actionTime as any) : '未知时间'
return `${actionName}${actionTime} 操作`
}
const roundAmount = (value: number) => Math.round((Number(value) || 0) * 100) / 100
const getAssessmentCoefficient = (assessmentResult?: string) => {
if (assessmentResult === '优秀') {
return 1.02
}
if (assessmentResult === '待改进') {
return 0.95
}
return 1
}
const formatCoefficientText = (value?: number) => Number(value ?? 1).toFixed(2)
const syncSettlementForm = () => {
if (!currentProfit.value?.projectId) {
settlementForm.projectId = 0
settlementForm.assessmentResult = '合格'
settlementForm.remark = ''
return
}
const snapshot = currentProfit.value.settlementSnapshot
settlementForm.projectId = currentProfit.value.projectId
settlementForm.assessmentResult = snapshot?.assessmentResult || '合格'
settlementForm.remark = snapshot?.remark || ''
}
watch(currentProfit, syncSettlementForm)
let activatedOnce = false
onMounted(() => {
getList()
})
onActivated(() => {
// KeepAlive 首次挂载也会触发 onActivated跳过首轮避免重复请求列表。
if (!activatedOnce) {
activatedOnce = true
return
}
getList()
})
</script>