2026-04-17 18:17:42 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<ContentWrap>
|
|
|
|
|
|
<el-form
|
|
|
|
|
|
ref="queryFormRef"
|
|
|
|
|
|
:inline="true"
|
|
|
|
|
|
:model="queryParams"
|
|
|
|
|
|
class="-mb-15px"
|
|
|
|
|
|
label-width="88px"
|
|
|
|
|
|
>
|
2026-05-08 17:38:50 +08:00
|
|
|
|
<el-form-item label="项目名称" prop="projectName">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="queryParams.projectName"
|
|
|
|
|
|
class="!w-240px"
|
|
|
|
|
|
clearable
|
2026-05-08 17:38:50 +08:00
|
|
|
|
placeholder="请输入项目名称"
|
2026-04-17 18:17:42 +08:00
|
|
|
|
@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="projectTableRef"
|
|
|
|
|
|
v-loading="loading"
|
|
|
|
|
|
:data="projectList"
|
|
|
|
|
|
highlight-current-row
|
|
|
|
|
|
@current-change="handleCurrentProjectChange"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-table-column
|
2026-05-08 17:38:50 +08:00
|
|
|
|
:index="getProjectRowIndex"
|
2026-04-17 18:17:42 +08:00
|
|
|
|
align="center"
|
2026-05-08 17:38:50 +08:00
|
|
|
|
label="序号"
|
|
|
|
|
|
type="index"
|
|
|
|
|
|
width="80"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-table-column
|
|
|
|
|
|
align="center"
|
|
|
|
|
|
label="项目名称"
|
2026-04-17 18:17:42 +08:00
|
|
|
|
min-width="220"
|
|
|
|
|
|
prop="projectName"
|
|
|
|
|
|
show-overflow-tooltip
|
|
|
|
|
|
/>
|
|
|
|
|
|
<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="120" />
|
2026-05-15 17:57:24 +08:00
|
|
|
|
<el-table-column align="center" label="合同总产值(元)" width="130">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ formatAmountText(scope.row.contractAmount) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
2026-05-15 17:57:24 +08:00
|
|
|
|
<el-table-column align="center" label="建筑面积(㎡)" width="140">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ formatAreaText(scope.row.totalConstructionArea) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column
|
|
|
|
|
|
:formatter="dateFormatter"
|
|
|
|
|
|
align="center"
|
|
|
|
|
|
label="创建时间"
|
|
|
|
|
|
prop="createTime"
|
|
|
|
|
|
width="180"
|
|
|
|
|
|
/>
|
2026-05-08 17:38:50 +08:00
|
|
|
|
<el-table-column align="center" label="排序" prop="sortNo" width="80" />
|
2026-04-17 18:17:42 +08:00
|
|
|
|
</el-table>
|
|
|
|
|
|
<Pagination
|
|
|
|
|
|
v-model:limit="queryParams.pageSize"
|
|
|
|
|
|
v-model:page="queryParams.pageNo"
|
|
|
|
|
|
:total="total"
|
|
|
|
|
|
@pagination="getProjectList"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</ContentWrap>
|
|
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="16">
|
|
|
|
|
|
<el-col :span="9">
|
|
|
|
|
|
<ContentWrap>
|
|
|
|
|
|
<div class="mb-12px flex items-center justify-between">
|
|
|
|
|
|
<div class="text-14px font-600">
|
|
|
|
|
|
{{ currentProject?.projectName || '合约规划列表' }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-button v-if="currentProject" size="small" @click="getPlanningList">刷新</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
ref="planningTableRef"
|
|
|
|
|
|
v-loading="planningLoading"
|
|
|
|
|
|
:data="planningList"
|
|
|
|
|
|
highlight-current-row
|
|
|
|
|
|
@current-change="handleCurrentPlanningChange"
|
|
|
|
|
|
>
|
2026-05-08 17:38:50 +08:00
|
|
|
|
<el-table-column align="center" label="序号" type="index" width="70" />
|
2026-04-17 18:17:42 +08:00
|
|
|
|
<el-table-column
|
|
|
|
|
|
align="center"
|
2026-05-08 17:38:50 +08:00
|
|
|
|
label="项目任务包"
|
2026-04-17 18:17:42 +08:00
|
|
|
|
min-width="170"
|
|
|
|
|
|
prop="planningContent"
|
|
|
|
|
|
show-overflow-tooltip
|
|
|
|
|
|
/>
|
2026-04-25 18:10:45 +08:00
|
|
|
|
<el-table-column align="center" label="归属类型" width="100">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ getOwnershipTypeLabel(scope.row.ownershipType) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column align="center" label="计算方式" width="110">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ getCalculationMethodLabel(scope.row.calculationMethod) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
2026-05-08 17:38:50 +08:00
|
|
|
|
<el-table-column align="center" label="分项合同产值(元)" width="120">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ formatAmountText(scope.row.planningAmount) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column align="center" label="总分配" width="100">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ formatPercentText(scope.row.totalDistributionAmount) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column align="center" label="考核产值(元)" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ formatAmountText(scope.row.assessmentOutputValue) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
2026-05-08 17:38:50 +08:00
|
|
|
|
<el-table-column align="center" label="排序" prop="sortNo" width="80" />
|
2026-04-17 18:17:42 +08:00
|
|
|
|
</el-table>
|
|
|
|
|
|
</ContentWrap>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
|
|
<el-col :span="15">
|
2026-05-13 11:41:30 +08:00
|
|
|
|
<div v-loading="quarterLoading" class="min-h-320px">
|
|
|
|
|
|
<template v-if="currentPlanning">
|
|
|
|
|
|
<ContentWrap>
|
2026-04-17 18:17:42 +08:00
|
|
|
|
<div class="mb-16px flex items-center justify-between gap-16px">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
|
|
|
|
|
|
<div class="mt-4px text-13px text-[var(--el-text-color-secondary)]">
|
2026-04-25 18:10:45 +08:00
|
|
|
|
{{ getOwnershipTypeLabel(currentPlanning.ownershipType) }} /
|
|
|
|
|
|
{{ getCalculationMethodLabel(currentPlanning.calculationMethod) }}
|
2026-04-17 18:17:42 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="flex items-center gap-12px">
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
v-hasPermi="['tjt:planning:update']"
|
|
|
|
|
|
plain
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
@click="openPlanningOutputForm"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Icon class="mr-5px" icon="ep:edit" />
|
|
|
|
|
|
编辑测算参数
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
v-hasPermi="['tjt:planning:update', 'tjt:planning-quarter:update', 'tjt:planning-quarter:create']"
|
|
|
|
|
|
v-if="false"
|
|
|
|
|
|
plain
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
@click="openQuarterDistributionForm"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Icon class="mr-5px" icon="ep:edit-pen" />
|
|
|
|
|
|
编辑季度分配
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<el-descriptions :column="2" border title="测算参数">
|
2026-05-08 17:38:50 +08:00
|
|
|
|
<el-descriptions-item label="分项合同产值(元)">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
{{ formatAmountText(currentPlanning.planningAmount) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="管理费费率">
|
|
|
|
|
|
{{ formatPercentText(currentPlanning.managementFeeRate) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="管理费(元)">
|
|
|
|
|
|
{{ formatAmountText(currentPlanning.managementFee) }}
|
|
|
|
|
|
</el-descriptions-item>
|
2026-05-08 17:38:50 +08:00
|
|
|
|
<el-descriptions-item label="意向实施团队">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
{{ currentPlanning.implementationTeam || '-' }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="开始年度">
|
|
|
|
|
|
{{ currentPlanning.planningStartYear || '-' }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="面积(㎡)">
|
|
|
|
|
|
{{ formatAreaText(currentPlanning.planningArea) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="合同单价(元/㎡)">
|
|
|
|
|
|
{{ formatAmountText(currentPlanning.contractUnitPrice) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="设计阶段">
|
2026-04-25 18:10:45 +08:00
|
|
|
|
{{ getDesignStageLabel(currentPlanning.designStage) }}
|
2026-04-17 18:17:42 +08:00
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="本次设计阶段比例">
|
|
|
|
|
|
{{ formatPercentText(currentPlanning.currentDesignStageRatio) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="审核审定是否外包">
|
|
|
|
|
|
{{ currentPlanning.reviewOutsourceFlag ? '是' : '否' }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="审核审定占比">
|
|
|
|
|
|
{{ formatPercentText(currentPlanning.reviewOutsourceRatio) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item v-if="showCalculationRatioField" :label="calculationRatioLabel">
|
|
|
|
|
|
{{ formatPercentText(currentPlanning.calculationRatio) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item
|
2026-04-29 15:44:00 +08:00
|
|
|
|
v-if="showParentBuildingOrUnitCount"
|
2026-04-17 18:17:42 +08:00
|
|
|
|
label="楼栋数/户型数"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ currentPlanning.buildingOrUnitCount }}
|
|
|
|
|
|
</el-descriptions-item>
|
2026-04-29 15:44:00 +08:00
|
|
|
|
<el-descriptions-item v-if="showParentMajorFactorFields" label="套图系数">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
{{ formatFactorText(currentPlanning.drawingSetFactor, 2) }}
|
|
|
|
|
|
</el-descriptions-item>
|
2026-04-29 15:44:00 +08:00
|
|
|
|
<el-descriptions-item v-if="showParentMajorFactorFields" label="规模系数">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
{{ formatFactorText(currentPlanning.scaleFactor, 2) }}
|
|
|
|
|
|
</el-descriptions-item>
|
2026-04-29 15:44:00 +08:00
|
|
|
|
<el-descriptions-item v-if="showParentMajorFactorFields" label="修改系数">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
{{ formatFactorText(currentPlanning.modificationFactor, 2) }}
|
|
|
|
|
|
</el-descriptions-item>
|
2026-04-29 15:44:00 +08:00
|
|
|
|
<el-descriptions-item v-if="showParentMajorFactorFields" label="复杂系数/复杂等级">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
{{ formatPercentText(currentPlanning.complexityFactor) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item
|
2026-04-29 15:44:00 +08:00
|
|
|
|
v-if="showParentInternalGuidanceUnitPrice"
|
2026-04-17 18:17:42 +08:00
|
|
|
|
label="内部指导单价(元/㎡)"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ formatAmountText(currentPlanning.internalGuidanceUnitPrice) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item
|
|
|
|
|
|
v-if="currentPlanning.virtualCalculationMethod"
|
|
|
|
|
|
label="虚拟产值计算方式"
|
|
|
|
|
|
>
|
2026-04-25 18:10:45 +08:00
|
|
|
|
{{ getVirtualCalculationMethodLabel(currentPlanning.virtualCalculationMethod) }}
|
2026-04-17 18:17:42 +08:00
|
|
|
|
</el-descriptions-item>
|
2026-04-25 18:10:45 +08:00
|
|
|
|
<el-descriptions-item
|
|
|
|
|
|
v-if="currentPlanning.guidanceUnitPrice"
|
|
|
|
|
|
label="指导单价(元/㎡)"
|
|
|
|
|
|
>
|
2026-04-17 18:17:42 +08:00
|
|
|
|
{{ formatAmountText(currentPlanning.guidanceUnitPrice) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item v-if="currentPlanning.guidanceTotalPrice" label="指导总价(元)">
|
|
|
|
|
|
{{ formatAmountText(currentPlanning.guidanceTotalPrice) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item v-if="currentPlanning.workingDayCount" label="工日">
|
|
|
|
|
|
{{ formatAmountText(currentPlanning.workingDayCount) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item v-if="currentPlanning.workingDayUnitPrice" label="工日单价(元)">
|
|
|
|
|
|
{{ formatAmountText(currentPlanning.workingDayUnitPrice) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
|
|
|
|
|
|
<el-descriptions :column="2" border class="mt-16px" title="计算结果">
|
2026-04-29 15:44:00 +08:00
|
|
|
|
<el-descriptions-item v-if="!showGuideDetailScene" label="合计调整系数">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
{{ formatFactorText(currentPlanning.totalAdjustmentFactor) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="考核面积(㎡)">
|
|
|
|
|
|
{{ formatAreaText(currentPlanning.assessmentArea) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="虚拟产值(元)">
|
|
|
|
|
|
{{ formatAmountText(currentPlanning.virtualOutputValue) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="考核产值(元)">
|
|
|
|
|
|
{{ formatAmountText(currentPlanning.assessmentOutputValue) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
</ContentWrap>
|
|
|
|
|
|
|
2026-05-13 11:41:30 +08:00
|
|
|
|
<ContentWrap>
|
2026-04-17 18:17:42 +08:00
|
|
|
|
<div class="mb-16px flex items-center justify-between gap-16px">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="text-14px font-600">季度分配</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
v-hasPermi="['tjt:planning:update', 'tjt:planning-quarter:update', 'tjt:planning-quarter:create']"
|
|
|
|
|
|
plain
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
@click="openQuarterDistributionForm"
|
|
|
|
|
|
>
|
|
|
|
|
|
编辑季度分配
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="16" class="mb-16px">
|
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
|
<div class="rounded-8px bg-[var(--el-fill-color-light)] px-16px py-12px">
|
|
|
|
|
|
<div class="text-12px text-[var(--el-text-color-secondary)]">总分配</div>
|
|
|
|
|
|
<div class="mt-6px text-18px font-600">
|
|
|
|
|
|
{{ formatPercentText(currentPlanning.totalDistributionAmount) }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
|
<div class="rounded-8px bg-[var(--el-fill-color-light)] px-16px py-12px">
|
|
|
|
|
|
<div class="text-12px text-[var(--el-text-color-secondary)]">已分配</div>
|
|
|
|
|
|
<div class="mt-6px text-18px font-600">
|
|
|
|
|
|
{{ formatPercentText(currentPlanning.allocatedAmount) }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
|
<div class="rounded-8px bg-[var(--el-fill-color-light)] px-16px py-12px">
|
|
|
|
|
|
<div class="text-12px text-[var(--el-text-color-secondary)]">待分配</div>
|
|
|
|
|
|
<div class="mt-6px text-18px font-600">
|
|
|
|
|
|
{{ formatPercentText(currentPlanning.pendingAmount) }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
|
<div class="rounded-8px bg-[var(--el-fill-color-light)] px-16px py-12px">
|
|
|
|
|
|
<div class="text-12px text-[var(--el-text-color-secondary)]">提取进度备注</div>
|
|
|
|
|
|
<div class="mt-6px min-h-44px text-13px leading-20px">
|
|
|
|
|
|
{{ currentPlanning.progressRemark || '-' }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
2026-05-13 11:41:30 +08:00
|
|
|
|
<el-table :data="quarterRows" border>
|
2026-04-17 18:17:42 +08:00
|
|
|
|
<el-table-column align="center" label="分配年度" width="150" prop="distributionYear" />
|
|
|
|
|
|
<el-table-column
|
|
|
|
|
|
v-for="quarter in QUARTER_OPTIONS"
|
|
|
|
|
|
:key="quarter.value"
|
|
|
|
|
|
:label="quarter.label"
|
|
|
|
|
|
min-width="220"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<div class="flex flex-col gap-8px">
|
|
|
|
|
|
<div class="rounded-6px bg-[var(--el-fill-color-light)] px-10px py-8px text-12px">
|
|
|
|
|
|
分配比例:{{ formatQuarterRatio(scope.row, quarter.value) }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</ContentWrap>
|
2026-05-13 11:41:30 +08:00
|
|
|
|
</template>
|
2026-04-17 18:17:42 +08:00
|
|
|
|
|
2026-05-13 11:41:30 +08:00
|
|
|
|
<ContentWrap v-else-if="!quarterLoading">
|
2026-04-17 18:17:42 +08:00
|
|
|
|
<el-empty description="请选择合约规划后查看测算结果和季度分配" />
|
|
|
|
|
|
</ContentWrap>
|
2026-05-13 11:41:30 +08:00
|
|
|
|
</div>
|
2026-04-17 18:17:42 +08:00
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<PlanningOutputForm ref="planningOutputFormRef" @success="handlePlanningOutputFormSuccess" />
|
|
|
|
|
|
<QuarterDistributionForm
|
|
|
|
|
|
ref="quarterDistributionFormRef"
|
|
|
|
|
|
@success="handlePlanningOutputFormSuccess"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
|
import { dateFormatter } from '@/utils/formatTime'
|
|
|
|
|
|
import * as ProjectApi from '@/api/tjt/project'
|
|
|
|
|
|
import * as PlanningApi from '@/api/tjt/planning'
|
|
|
|
|
|
import * as PlanningQuarterApi from '@/api/tjt/planningQuarter'
|
|
|
|
|
|
import PlanningOutputForm from './PlanningOutputForm.vue'
|
|
|
|
|
|
import QuarterDistributionForm from './QuarterDistributionForm.vue'
|
|
|
|
|
|
import {
|
|
|
|
|
|
CONTRACT_SIGN_OPTIONS,
|
|
|
|
|
|
QUARTER_OPTIONS,
|
|
|
|
|
|
formatAmountText,
|
|
|
|
|
|
formatAreaText,
|
|
|
|
|
|
formatPercentText,
|
2026-04-25 18:10:45 +08:00
|
|
|
|
getCalculationMethodLabel,
|
2026-04-17 18:17:42 +08:00
|
|
|
|
getCalculationRatioLabel,
|
2026-04-25 18:10:45 +08:00
|
|
|
|
getDesignStageLabel,
|
|
|
|
|
|
getOwnershipTypeLabel,
|
|
|
|
|
|
getVirtualCalculationMethodLabel,
|
2026-04-17 18:17:42 +08:00
|
|
|
|
isComprehensiveOwnership,
|
|
|
|
|
|
isContractPriceMethod,
|
|
|
|
|
|
isGuidancePriceMethod,
|
|
|
|
|
|
isMajorOwnership,
|
|
|
|
|
|
isSubcontractOwnership
|
|
|
|
|
|
} from '@/views/tjt/shared/planning'
|
|
|
|
|
|
|
|
|
|
|
|
defineOptions({ name: 'TjtOutput' })
|
|
|
|
|
|
|
|
|
|
|
|
interface QuarterYearRow {
|
|
|
|
|
|
distributionYear: number
|
|
|
|
|
|
quarters: PlanningQuarterApi.ProjectPlanningQuarterVO[]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const message = useMessage()
|
|
|
|
|
|
|
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
const planningLoading = ref(false)
|
|
|
|
|
|
const quarterLoading = ref(false)
|
|
|
|
|
|
const total = ref(0)
|
|
|
|
|
|
const projectList = ref<ProjectApi.ProjectVO[]>([])
|
|
|
|
|
|
const planningList = ref<PlanningApi.ProjectPlanningVO[]>([])
|
|
|
|
|
|
const currentProject = ref<ProjectApi.ProjectVO>()
|
|
|
|
|
|
const currentPlanning = ref<PlanningApi.ProjectPlanningVO>()
|
|
|
|
|
|
const quarterRows = ref<QuarterYearRow[]>([])
|
|
|
|
|
|
const queryFormRef = ref()
|
|
|
|
|
|
const projectTableRef = ref()
|
|
|
|
|
|
const planningTableRef = ref()
|
|
|
|
|
|
|
|
|
|
|
|
const queryParams = reactive<ProjectApi.ProjectPageReqVO>({
|
|
|
|
|
|
pageNo: 1,
|
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
|
projectName: undefined,
|
|
|
|
|
|
contractSignedFlag: undefined,
|
|
|
|
|
|
projectStartYear: undefined
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2026-05-08 17:38:50 +08:00
|
|
|
|
const getProjectRowIndex = (index: number) =>
|
|
|
|
|
|
(queryParams.pageNo - 1) * queryParams.pageSize + index + 1
|
|
|
|
|
|
|
2026-04-17 18:17:42 +08:00
|
|
|
|
const queryProjectStartYearValue = computed({
|
|
|
|
|
|
get: () => (queryParams.projectStartYear ? String(queryParams.projectStartYear) : undefined),
|
|
|
|
|
|
set: (value?: string) => {
|
|
|
|
|
|
queryParams.projectStartYear = value ? Number(value) : undefined
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const calculationRatioLabel = computed(() =>
|
|
|
|
|
|
getCalculationRatioLabel(currentPlanning.value?.ownershipType)
|
|
|
|
|
|
)
|
|
|
|
|
|
const showCalculationRatioField = computed(
|
|
|
|
|
|
() =>
|
|
|
|
|
|
isComprehensiveOwnership(currentPlanning.value?.ownershipType) ||
|
|
|
|
|
|
isSubcontractOwnership(currentPlanning.value?.ownershipType)
|
|
|
|
|
|
)
|
2026-04-29 15:44:00 +08:00
|
|
|
|
const showGuideDetailScene = computed(
|
2026-04-17 18:17:42 +08:00
|
|
|
|
() =>
|
|
|
|
|
|
isMajorOwnership(currentPlanning.value?.ownershipType) &&
|
2026-04-29 15:44:00 +08:00
|
|
|
|
isGuidancePriceMethod(currentPlanning.value?.calculationMethod)
|
|
|
|
|
|
)
|
|
|
|
|
|
const showParentMajorFactorFields = computed(
|
|
|
|
|
|
() =>
|
|
|
|
|
|
isMajorOwnership(currentPlanning.value?.ownershipType) &&
|
|
|
|
|
|
isContractPriceMethod(currentPlanning.value?.calculationMethod)
|
|
|
|
|
|
)
|
|
|
|
|
|
const showParentBuildingOrUnitCount = computed(
|
|
|
|
|
|
() =>
|
|
|
|
|
|
showParentMajorFactorFields.value &&
|
|
|
|
|
|
currentPlanning.value?.buildingOrUnitCount !== undefined &&
|
|
|
|
|
|
currentPlanning.value?.buildingOrUnitCount !== null
|
|
|
|
|
|
)
|
|
|
|
|
|
const showParentInternalGuidanceUnitPrice = computed(
|
|
|
|
|
|
() =>
|
|
|
|
|
|
!showGuideDetailScene.value &&
|
|
|
|
|
|
currentPlanning.value?.internalGuidanceUnitPrice !== undefined &&
|
|
|
|
|
|
currentPlanning.value?.internalGuidanceUnitPrice !== null
|
2026-04-17 18:17:42 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
const formatFactorText = (value?: number, digits = 4) => {
|
|
|
|
|
|
if (value === undefined || value === null) {
|
2026-04-29 15:44:00 +08:00
|
|
|
|
return '-'
|
2026-04-17 18:17:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
return Number(value).toFixed(digits)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-25 18:10:45 +08:00
|
|
|
|
const getQuarterCell = (row: QuarterYearRow, quarterNo: number) => {
|
|
|
|
|
|
return row.quarters.find((item) => Number(item.quarterNo) === Number(quarterNo))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-17 18:17:42 +08:00
|
|
|
|
const formatQuarterRatio = (row: QuarterYearRow, quarterNo: number) => {
|
2026-04-25 18:10:45 +08:00
|
|
|
|
return formatPercentText(getQuarterCell(row, quarterNo)?.distributionRatio)
|
2026-04-17 18:17:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const buildQuarterRows = (
|
|
|
|
|
|
planning: PlanningApi.ProjectPlanningVO,
|
|
|
|
|
|
quarters: PlanningQuarterApi.ProjectPlanningQuarterVO[]
|
|
|
|
|
|
) => {
|
|
|
|
|
|
const yearSet = new Set<number>()
|
|
|
|
|
|
if (planning.planningStartYear) {
|
|
|
|
|
|
yearSet.add(planning.planningStartYear)
|
|
|
|
|
|
}
|
2026-04-25 18:10:45 +08:00
|
|
|
|
quarters.forEach((item) => {
|
|
|
|
|
|
const distributionYear = Number(item.distributionYear)
|
|
|
|
|
|
if (!Number.isNaN(distributionYear)) {
|
|
|
|
|
|
yearSet.add(distributionYear)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2026-04-17 18:17:42 +08:00
|
|
|
|
if (yearSet.size === 0) {
|
|
|
|
|
|
yearSet.add(new Date().getFullYear())
|
|
|
|
|
|
}
|
|
|
|
|
|
return Array.from(yearSet)
|
|
|
|
|
|
.sort((a, b) => a - b)
|
|
|
|
|
|
.map((distributionYear) => ({
|
|
|
|
|
|
distributionYear,
|
|
|
|
|
|
quarters: QUARTER_OPTIONS.map((option) => {
|
2026-04-25 18:10:45 +08:00
|
|
|
|
const quarterNo = Number(option.value)
|
2026-04-17 18:17:42 +08:00
|
|
|
|
const match = quarters.find(
|
|
|
|
|
|
(item) =>
|
2026-04-25 18:10:45 +08:00
|
|
|
|
Number(item.distributionYear) === distributionYear &&
|
|
|
|
|
|
Number(item.quarterNo) === quarterNo
|
2026-04-17 18:17:42 +08:00
|
|
|
|
)
|
|
|
|
|
|
return (
|
|
|
|
|
|
match || {
|
|
|
|
|
|
planningId: planning.id!,
|
|
|
|
|
|
distributionYear,
|
2026-04-25 18:10:45 +08:00
|
|
|
|
quarterNo,
|
2026-04-17 18:17:42 +08:00
|
|
|
|
distributionRatio: undefined,
|
|
|
|
|
|
distributionAmount: undefined
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
})
|
|
|
|
|
|
}))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getProjectList = async () => {
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
const data = await ProjectApi.getProjectPage(queryParams)
|
|
|
|
|
|
projectList.value = data.list
|
|
|
|
|
|
total.value = data.total
|
|
|
|
|
|
if (!projectList.value.length) {
|
|
|
|
|
|
currentProject.value = undefined
|
|
|
|
|
|
planningList.value = []
|
|
|
|
|
|
currentPlanning.value = undefined
|
|
|
|
|
|
quarterRows.value = []
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const targetProjectId = currentProject.value?.id || projectList.value[0].id
|
|
|
|
|
|
const targetProject =
|
|
|
|
|
|
projectList.value.find((item) => item.id === targetProjectId) || projectList.value[0]
|
|
|
|
|
|
await nextTick()
|
|
|
|
|
|
projectTableRef.value?.setCurrentRow(targetProject)
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getPlanningList = async () => {
|
|
|
|
|
|
if (!currentProject.value?.id) {
|
|
|
|
|
|
planningList.value = []
|
|
|
|
|
|
currentPlanning.value = undefined
|
|
|
|
|
|
quarterRows.value = []
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
planningLoading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
planningList.value = await PlanningApi.getProjectPlanningListByProjectId(currentProject.value.id)
|
|
|
|
|
|
if (!planningList.value.length) {
|
|
|
|
|
|
currentPlanning.value = undefined
|
|
|
|
|
|
quarterRows.value = []
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const targetPlanningId = currentPlanning.value?.id || planningList.value[0].id
|
|
|
|
|
|
const targetPlanning =
|
|
|
|
|
|
planningList.value.find((item) => item.id === targetPlanningId) || planningList.value[0]
|
|
|
|
|
|
await nextTick()
|
|
|
|
|
|
planningTableRef.value?.setCurrentRow(targetPlanning)
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
planningLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const loadPlanningDetail = async (planningId: number) => {
|
|
|
|
|
|
quarterLoading.value = true
|
|
|
|
|
|
try {
|
2026-05-13 11:41:30 +08:00
|
|
|
|
const detail = await PlanningQuarterApi.getProjectPlanningQuarterPlanningDetail(planningId)
|
|
|
|
|
|
currentPlanning.value = detail?.planning
|
|
|
|
|
|
quarterRows.value = detail?.planning ? buildQuarterRows(detail.planning, detail.quarters || []) : []
|
2026-04-17 18:17:42 +08:00
|
|
|
|
} finally {
|
|
|
|
|
|
quarterLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleQuery = () => {
|
|
|
|
|
|
queryParams.pageNo = 1
|
|
|
|
|
|
getProjectList()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const resetQuery = () => {
|
|
|
|
|
|
queryFormRef.value?.resetFields()
|
|
|
|
|
|
handleQuery()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleCurrentProjectChange = async (row?: ProjectApi.ProjectVO) => {
|
|
|
|
|
|
currentProject.value = row || undefined
|
|
|
|
|
|
await getPlanningList()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleCurrentPlanningChange = async (row?: PlanningApi.ProjectPlanningVO) => {
|
|
|
|
|
|
if (!row?.id) {
|
|
|
|
|
|
currentPlanning.value = undefined
|
|
|
|
|
|
quarterRows.value = []
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
await loadPlanningDetail(row.id)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const planningOutputFormRef = ref()
|
|
|
|
|
|
const quarterDistributionFormRef = ref()
|
|
|
|
|
|
|
|
|
|
|
|
const openPlanningOutputForm = () => {
|
|
|
|
|
|
if (!currentPlanning.value?.id) {
|
|
|
|
|
|
message.warning('请先选择合约规划')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
planningOutputFormRef.value.open(currentPlanning.value.id)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const openQuarterDistributionForm = () => {
|
|
|
|
|
|
if (!currentPlanning.value?.id) {
|
|
|
|
|
|
message.warning('请先选择合约规划')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
quarterDistributionFormRef.value.open(currentPlanning.value.id)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handlePlanningOutputFormSuccess = async () => {
|
|
|
|
|
|
const currentPlanningId = currentPlanning.value?.id
|
|
|
|
|
|
await getPlanningList()
|
|
|
|
|
|
if (currentPlanningId) {
|
|
|
|
|
|
await loadPlanningDetail(currentPlanningId)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-13 11:41:30 +08:00
|
|
|
|
let activatedOnce = false
|
|
|
|
|
|
|
2026-04-17 18:17:42 +08:00
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
getProjectList()
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
onActivated(() => {
|
2026-05-13 11:41:30 +08:00
|
|
|
|
// KeepAlive 首次挂载也会触发 onActivated,跳过首轮避免重复请求项目与合约规划列表。
|
|
|
|
|
|
if (!activatedOnce) {
|
|
|
|
|
|
activatedOnce = true
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-04-17 18:17:42 +08:00
|
|
|
|
getProjectList()
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|