@@ -1,5 +1,5 @@
< template >
< Dialog v-model = "dialogVisible" : title="dialogTitle " width="1120 " >
< template >
< Dialog v-model = "dialogVisible" title="编辑测算参数 " width="92% " >
< el -form
ref = "formRef"
v-loading = "formLoading"
@@ -11,7 +11,7 @@
< el-row :gutter = "16" >
< el-col :span = "8" >
< el-form-item label = "归属类型" >
< el-input :model-value = "o wnershipTypeLabel" disabled / >
< el-input :model-value = "getO wnershipTypeLabel(formData.ownershipType) " disabled / >
< / el-form-item >
< / el-col >
< el-col :span = "8" >
@@ -22,7 +22,7 @@
placeholder = "请选择产值计算方式"
>
< el-option
v-for = "item in calculationMethodOptions "
v-for = "item in CALCULATION_METHOD_OPTIONS "
:key = "String(item.value)"
:label = "item.label"
:value = "item.value"
@@ -55,35 +55,6 @@
< / el-col >
< / el-row >
< el-row :gutter = "16" >
< el-col :span = "8" >
< el-form-item label = "设计部位" prop = "designPart" >
< el-select
v-model = "formData.designPart"
class = "!w-1/1"
clearable
placeholder = "请选择设计部位"
>
< el-option
v-for = "item in DESIGN_PART_OPTIONS"
:key = "item.value"
:label = "item.label"
:value = "item.value"
/ >
< / el-select >
< / el-form-item >
< / el-col >
< el-col :span = "8" >
< el-form-item label = "建筑类型" prop = "buildingType" >
< el-input
v-model = "formData.buildingType"
maxlength = "100"
placeholder = "请输入建筑类型"
/ >
< / el-form-item >
< / el-col >
< / el-row >
< el-divider content -position = " left " > 测算参数 < / el-divider >
< el-row :gutter = "16" >
< el-col :span = "8" >
@@ -99,7 +70,13 @@
< / el-col >
< el-col :span = "8" >
< el-form-item label = "工程总面积(m²)" prop = "planningArea" >
< el-input
v-if = "showGuideDetailSection"
:model-value = "formatAmountText(guideDetailSummary.designArea)"
disabled
/ >
< el-input-number
v-else
v-model = "formData.planningArea"
:min = "0"
:precision = "2"
@@ -119,13 +96,9 @@
< el-row :gutter = "16" >
< el-col :span = "8" >
< el-form-item label = "设计阶段" prop = "designStage" >
< el-select
v-model = "formData.designStage"
class = "!w-1/1"
placeholder = "请选择设计阶段"
>
< el-select v-model = "formData.designStage" class="!w-1/1" placeholder="请选择设计阶段" >
< el -option
v-for = "item in designStageOptions "
v-for = "item in DESIGN_STAGE_OPTIONS "
:key = "String(item.value)"
:label = "item.label"
:value = "item.value"
@@ -133,9 +106,6 @@
< / el-select >
< / el-form-item >
< / el-col >
< / el-row >
< el-row :gutter = "16" >
< el-col :span = "8" >
< el-form-item label = "本次设计阶段比例(%)" prop = "currentDesignStageRatio" >
< el-input-number
@@ -148,6 +118,9 @@
/ >
< / el-form-item >
< / el-col >
< / el-row >
< el-row :gutter = "16" >
< el-col :span = "8" >
< el-form-item label = "审核审定是否外包" prop = "reviewOutsourceFlag" >
< el-switch
@@ -170,9 +143,6 @@
/ >
< / el-form-item >
< / el-col >
< / el-row >
< el-row :gutter = "16" >
< el-col v-if = "showCalculationRatioField" :span="8" >
< el -form -item :label = "`${calculationRatioLabel}(%)`" prop = "calculationRatio" >
< el-input-number
@@ -185,7 +155,10 @@
/ >
< / el-form-item >
< / el-col >
< el-col : span = "showCalculationRatioField ? 8 : 12" >
< / el-row >
< el-row :gutter = "16" >
< el-col :span = "8" >
< el-form-item label = "总分配(%)" prop = "totalDistributionAmount" >
< el-input-number
v-model = "totalDistributionAmountPercent"
@@ -199,7 +172,7 @@
< / el-col >
< / el-row >
< template v-if = "showMajorFactorFields" >
< template v-if = "showParent MajorFactorFields" >
< el -divider content -position = " left " > 专业所测算参数 < / el-divider >
< el-row :gutter = "16" >
< el-col :span = "8" >
@@ -219,7 +192,7 @@
< el-input-number
v-model = "formData.drawingSetFactor"
:min = "0"
:precision = "2 "
:precision = "4 "
:step = "0.01"
class = "!w-1/1"
controls -position = " right "
@@ -231,7 +204,7 @@
< el-input-number
v-model = "formData.scaleFactor"
:min = "0"
:precision = "2 "
:precision = "4 "
:step = "0.01"
class = "!w-1/1"
controls -position = " right "
@@ -245,7 +218,7 @@
< el-input-number
v-model = "formData.modificationFactor"
:min = "0"
:precision = "2 "
:precision = "4 "
:step = "0.01"
class = "!w-1/1"
controls -position = " right "
@@ -267,18 +240,171 @@
< / el-row >
< / template >
< template v-if = "showInternalGuidanceUnitPriceField" >
< el -divider content -position = " left " > 指导价法参数 < / el-divider >
< el-row :gutter = "16" >
< el-col :span = "8 ">
< el-form-item label = "内部指导单价(元/m²)" prop = "internalGuidanceUnitPrice" >
<!-- 优化后的指导价法明细块 -- >
< template v-if = "showGuideDetailSection" >
< el-divider content -position = " left " > 指导价法明细 < / el-divider >
< div class = "mb-12px flex items-center justify-between gap-12px ">
< el-button p lain type = "primary" @click ="addGuideDetailRow" >
< template # icon > < i class = "el-icon-plus" > < / i > < / template > 新增明细
< / el-button >
< span class = "text-12px text-gray-400" > 💡 提示 : 数字字段已隐藏加减箭头以优化显示 , 支持直接输入或复制粘贴 < / span >
< / div >
< el-table :data = "guideDetails" border max -height = " 460 " class = "optimized-table" >
<!-- 1. 冻结核心上下文列 -- >
< el-table-column align = "center" label = "序号" width = "65" fixed = "left" >
< template # default = "{ row }" >
< el-input-number
v-model = "formData.internalGuidanceUnitPrice "
v-model = "row.sortNo "
:min = "1"
:precision = "0"
:controls = "false"
class = "!w-1/1"
/ >
< / template >
< / el-table-column >
< el-table-column align = "center" label = "设计部位" min -width = " 120 " fixed = "left" >
< template # default = "{ row }" >
< el-select v-model = "row.designPart" class="!w-1/1" placeholder="请选择" >
< el -option
v-for = "item in DESIGN_PART_OPTIONS"
:key = "String(item.value)"
:label = "item.label"
:value = "item.value"
/ >
< / el-select >
< / template >
< / el-table-column >
< el-table-column align = "center" label = "建筑类型" min -width = " 140 " fixed = "left" >
< template # default = "{ row }" >
< el-input v-model = "row.buildingType" maxlength="100" placeholder="建筑类型" / >
< / template >
< / el-table-column >
<!-- 2. 取消 controls 的核心数值列 -- >
< el-table-column align = "center" label = "指导单价(元)" min -width = " 110 " >
< template # default = "{ row }" >
< el-input-number
v-model = "row.internalGuidanceUnitPrice"
:min = "0"
:precision = "2"
:step = "1 "
:controls = "false "
class = "!w-1/1"
controls -position = " right "
/ >
< / template >
< / el-table-column >
< el-table-column align = "center" label = "设计面积(m²)" min -width = " 110 " >
< template # default = "{ row }" >
< el-input-number
v-model = "row.designArea"
:min = "0"
:precision = "2"
:controls = "false"
class = "!w-1/1"
/ >
< / template >
< / el-table-column >
< el-table-column align = "center" label = "楼栋/户型数" min -width = " 100 " >
< template # default = "{ row }" >
< el-input-number
v-model = "row.buildingOrUnitCount"
:min = "0"
:precision = "0"
:controls = "false"
class = "!w-1/1"
/ >
< / template >
< / el-table-column >
<!-- 3. 多级表头折叠系数配置 -- >
< el-table-column label = "调整系数配置" align = "center" >
< el-table-column align = "center" label = "套图" min -width = " 85 " >
< template # default = "{ row }" >
< el-input-number v-model = "row.drawingSetFactor" :min="0" :precision="4" :controls="false" class="!w-1/1" / >
< / template >
< / el-table-column >
< el-table-column align = "center" label = "规模" min -width = " 85 " >
< template # default = "{ row }" >
< el-input-number v-model = "row.scaleFactor" :min="0" :precision="4" :controls="false" class="!w-1/1" / >
< / template >
< / el-table-column >
< el-table-column align = "center" label = "修改" min -width = " 85 " >
< template # default = "{ row }" >
< el-input-number v-model = "row.modificationFactor" :min="0" :precision="4" :controls="false" class="!w-1/1" / >
< / template >
< / el-table-column >
< el-table-column align = "center" label = "复杂(%)" min -width = " 90 " >
< template # default = "{ row }" >
< el-input-number
:model-value = "toPercentValue(row.complexityFactor)"
:min = "0"
:precision = "2"
:controls = "false"
class = "!w-1/1"
@ update : model -value = " setGuideDetailPercentValue ( row , ' complexityFactor ' , $ event ) "
/ >
< / template >
< / el-table-column >
< el-table-column align = "center" label = "合计" min -width = " 80 " >
< template # default = "{ row }" >
< span class = "text-gray-500" > { { formatFactorText ( getGuideDetailTotalAdjustmentFactor ( row ) ) } } < / span >
< / template >
< / el-table-column >
< / el-table-column >
< el-table-column align = "center" label = "设计占比(%)" min -width = " 100 " >
< template # default = "{ row }" >
< el-input-number
:model-value = "toPercentValue(row.designRatio)"
:min = "0"
:precision = "2"
:controls = "false"
class = "!w-1/1"
@ update : model -value = " setGuideDetailPercentValue ( row , ' designRatio ' , $ event ) "
/ >
< / template >
< / el-table-column >
<!-- 4. 结果列靠右显示 , 用浅色背景区分 -- >
< el-table-column align = "right" label = "考核面积(m²)" min -width = " 110 " class -name = " bg -gray -50 " >
< template # default = "{ row }" >
< span class = "font-bold" > { { formatAmountText ( getGuideDetailAssessmentArea ( row ) ) } } < / span >
< / template >
< / el-table-column >
< el-table-column align = "right" label = "考核产值(元)" min -width = " 120 " class -name = " bg -gray -50 " >
< template # default = "{ row }" >
< span class = "font-bold text-primary" > { { formatAmountText ( getGuideDetailAssessmentOutputValue ( row ) ) } } < / span >
< / template >
< / el-table-column >
< el-table-column align = "center" label = "备注" min -width = " 130 " >
< template # default = "{ row }" >
< el-input v-model = "row.remark" maxlength="500" placeholder="备注信息" / >
< / template >
< / el-table-column >
< el-table-column align = "center" fixed = "right" label = "操作" width = "70" >
< template # default = "{ $index }" >
< el-button link type = "danger" @click ="removeGuideDetailRow($index)" > 删除 < / el -button >
< / template >
< / el-table-column >
< / el-table >
< el-row :gutter = "16" class = "mt-16px" >
< el-col :span = "8" >
< el-form-item label = "汇总设计面积(m²)" >
< el-input :model-value = "formatAmountText(guideDetailSummary.designArea)" disabled / >
< / el-form-item >
< / el-col >
< el-col :span = "8" >
< el-form-item label = "汇总考核面积(m²)" >
< el-input :model-value = "formatAmountText(guideDetailSummary.assessmentArea)" disabled / >
< / el-form-item >
< / el-col >
< el-col :span = "8" >
< el-form-item label = "汇总考核产值(元)" >
< el-input
:model-value = "formatAmountText(guideDetailSummary.assessmentOutputValue)"
disabled
/ >
< / el-form-item >
< / el-col >
@@ -296,7 +422,7 @@
placeholder = "请选择虚拟产值计算方式"
>
< el-option
v-for = "item in virtualCalculationMethodOptions "
v-for = "item in VIRTUAL_CALCULATION_METHOD_OPTIONS "
:key = "String(item.value)"
:label = "item.label"
:value = "item.value"
@@ -359,6 +485,7 @@
< / el-row >
< / template >
< / el-form >
< template # footer >
< el-button :disabled = "formLoading" type = "primary" @click ="submitForm" > 保存 < / el -button >
< el-button @click ="dialogVisible = false" > 取消 < / el -button >
@@ -367,19 +494,22 @@
< / template >
< script lang = "ts" setup >
// [原有的 Script 逻辑不变,直接粘贴原本的逻辑即可]
import type { FormRules } from 'element-plus'
import * as PlanningApi from '@/api/tjt/planning'
import * as PlanningGuideDetailApi from '@/api/tjt/planningGuideDetail'
import {
CALCULATION _METHOD _OPTIONS ,
DEFAULT _WORKING _DAY _UNIT _PRICE ,
DESIGN _PART _OPTIONS ,
DESIGN _STAGE _OPTIONS ,
OWNERSHIP _TYPE _OPTIONS ,
VIRTUAL _CALCULATION _METHOD _OPTIONS ,
formatAmountText ,
formatPercentText ,
fromPercentValue ,
getCalculationRatioDefaultPercent ,
getCalculationRatioLabel ,
getOwnershipTypeLabel ,
getReviewOutsourceDefaultPercent ,
isComprehensiveOwnership ,
isContractPriceMethod ,
@@ -399,90 +529,64 @@ import {
defineOptions ( { name : 'TjtPlanningOutputForm' } )
const DESIGN _PART _OPTIONS = [
{ label : '地上部分' , value : '地上部分' } ,
{ label : '地下部分' , value : '地下部分' }
]
type GuideDetailRow = PlanningGuideDetailApi . ProjectPlanningGuideDetailVO
const OWNERSHIP _TYPE _LABELS = [ '专业所' , '综合所' , '专业分包' ]
const CALCULATION _METHOD _LABELS = [ '指导价法' , '合同价法' , '虚拟产值法' ]
const DESIGN _STAGE _LABELS = [ '方案' , '施工图' , '方案+施工图' ]
const VIRTUAL _CALCULATION _METHOD _LABELS = [ '指导单价法' , '指导总价法' , '工日法' ]
const createDisplayOptions = (
source : Array < { label : string ; value : string } > ,
labels : string [ ]
) => source . map ( ( item , index ) => ( { label : labels [ index ] || item . label , value : item . value } ) )
const ownershipTypeOptions = createDisplayOptions ( OWNERSHIP _TYPE _OPTIONS , OWNERSHIP _TYPE _LABELS )
const calculationMethodOptions = createDisplayOptions (
CALCULATION _METHOD _OPTIONS ,
CALCULATION _METHOD _LABELS
)
const designStageOptions = createDisplayOptions ( DESIGN _STAGE _OPTIONS , DESIGN _STAGE _LABELS )
const virtualCalculationMethodOptions = createDisplayOptions (
VIRTUAL _CALCULATION _METHOD _OPTIONS ,
VIRTUAL _CALCULATION _METHOD _LABELS
)
const { t } = useI18n ( )
const message = useMessage ( )
const dialogVisible = ref ( false )
const dialogTitle = ref ( '' )
const formLoading = ref ( false )
const formRef = ref ( )
const formData = ref < PlanningApi .ProjectPlanningVO > ( {
const createFormData = ( ) : PlanningApi . ProjectPlanningVO => ( {
id : undefined ,
projectId : 0 ,
ownershipType : '' ,
calculationMethod : '' ,
planningContent : ''
planningContent : '' ,
planningAmount : undefined ,
managementFeeRate : undefined ,
managementFee : undefined ,
implementationTeam : '' ,
planningStartYear : undefined ,
planningArea : undefined ,
designStage : undefined ,
currentDesignStageRatio : undefined ,
reviewOutsourceFlag : false ,
reviewOutsourceRatio : undefined ,
totalDistributionAmount : 1 ,
progressRemark : '' ,
allocatedAmount : undefined ,
pendingAmount : undefined ,
buildingOrUnitCount : undefined ,
drawingSetFactor : undefined ,
scaleFactor : undefined ,
modificationFactor : undefined ,
complexityFactor : undefined ,
internalGuidanceUnitPrice : undefined ,
virtualCalculationMethod : undefined ,
workingDayCount : undefined ,
workingDayUnitPrice : undefined ,
guidanceUnitPrice : undefined ,
guidanceTotalPrice : undefined ,
calculationRatio : undefined ,
contractUnitPrice : undefined ,
totalAdjustmentFactor : undefined ,
assessmentArea : undefined ,
virtualOutputValue : undefined ,
assessmentOutputValue : undefined ,
createTime : undefined
} )
const getOptionLabel = ( options : Array < { label : string ; value : string } > , value ? : string ) =>
options . find ( ( item ) => item . value === value ) ? . label || value || ''
const ownershipTypeLabel = computed ( ( ) =>
getOptionLabel ( ownershipTypeOptions , formData . value . ownershipType )
)
const normalizeFormData = ( data : PlanningApi . ProjectPlanningVO ) : PlanningApi . ProjectPlanningVO => ( {
... data ,
ownershipType : normalizeOwnershipType ( data . ownershipType ) || data . ownershipType || '' ,
calculationMethod : normalizeCalculationMethod ( data . calculationMethod ) || data . calculationMethod || '' ,
designPart : DESIGN _PART _OPTIONS . find ( ( item ) => item . value === data . designPart ) ? . value || undefined ,
designStage : normalizeDesignStage ( data . designStage ) ,
virtualCalculationMethod : normalizeVirtualCalculationMethod ( data . virtualCalculationMethod ) ,
reviewOutsourceFlag : data . reviewOutsourceFlag ? ? false ,
totalDistributionAmount : data . totalDistributionAmount ? ? 1 ,
progressRemark : data . progressRemark ? ? '' ,
drawingSetFactor : data . drawingSetFactor ? ? 1 ,
scaleFactor : data . scaleFactor ? ? 1 ,
modificationFactor : data . modificationFactor ? ? 1 ,
complexityFactor : data . complexityFactor ? ? 1 ,
workingDayUnitPrice :
data . workingDayUnitPrice ? ?
( isWorkingDayMethod ( data . virtualCalculationMethod ) ? DEFAULT _WORKING _DAY _UNIT _PRICE : undefined ) ,
guidanceTotalPrice : data . guidanceTotalPrice
} )
const formData = ref < PlanningApi .ProjectPlanningVO > ( createFormData ( ) )
const guideDetails = ref < GuideDetailRow [ ] > ( [ ] )
const planningStartYearValue = computed ( {
get : ( ) =>
formData . value . planningStartYear ? String ( formData . value . planningStartYear ) : undefined ,
get : ( ) => ( formData . value . planningStartYear ? String ( formData . value . planningStartYear ) : undefined ) ,
set : ( value ? : string ) => {
formData . value . planningStartYear = value ? Number ( value ) : undefined
}
} )
const contractUnitPricePreview = computed ( ( ) => {
const planningAmount = Number ( formData . value . planningAmount || 0 )
const planningArea = Number ( formData . value . planningArea || 0 )
if ( ! planningArea ) {
return formatAmountText ( 0 )
}
return formatAmountText ( planningAmount / planningArea )
} )
const createPercentModel = ( field : keyof PlanningApi . ProjectPlanningVO , digits = 2 ) =>
computed ( {
get : ( ) => toPercentValue ( formData . value [ field ] as number | undefined , digits ) ,
@@ -502,23 +606,25 @@ const showCalculationRatioField = computed(
isComprehensiveOwnership ( formData . value . ownershipType ) ||
isSubcontractOwnership ( formData . value . ownershipType )
)
const calculationRatioLabel = computed ( ( ) => getCalculationRatioLabel ( formData . value . ownershipType ) )
const showMajorFactorFields = computed (
( ) =>
isMajorOwnership ( formData . value . ownershipType ) &&
( isGuidancePriceMethod ( formData . value . calculationMethod ) ||
isContractPriceMethod ( formData . value . calculationMethod ) )
)
const showInternalGuidanceUnitPriceField = computed (
const showGuideDetailSection = computed (
( ) =>
isMajorOwnership ( formData . value . ownershipType ) &&
isGuidancePriceMethod ( formData . value . calculationMethod )
)
const showParentMajorFactorFields = computed (
( ) =>
isMajorOwnership ( formData . value . ownershipType ) &&
isContractPriceMethod ( formData . value . calculationMethod )
)
const showVirtualOutputSection = computed (
( ) =>
isMajorOwnership ( formData . value . ownershipType ) &&
isVirtualOutputMethod ( formData . value . calculationMethod )
)
const showWorkingDayFields = computed ( ( ) => isWorkingDayMethod ( formData . value . virtualCalculationMethod ) )
const showGuidanceUnitPriceField = computed (
( ) => isVirtualGuidanceMethod ( formData . value . virtualCalculationMethod )
@@ -526,13 +632,188 @@ const showGuidanceUnitPriceField = computed(
const showGuidanceTotalPriceField = computed (
( ) => isVirtualGuidanceTotalPriceMethod ( formData . value . virtualCalculationMethod )
)
const calculationRatioLabel = computed ( ( ) => getCalculationRatioLabel ( formData . value . ownershipType ) )
const normalizeFormData = ( data : PlanningApi . ProjectPlanningVO ) : PlanningApi . ProjectPlanningVO => ( {
... createFormData ( ) ,
... data ,
ownershipType : normalizeOwnershipType ( data . ownershipType ) || data . ownershipType || '' ,
calculationMethod : normalizeCalculationMethod ( data . calculationMethod ) || data . calculationMethod || '' ,
designStage : normalizeDesignStage ( data . designStage ) ,
virtualCalculationMethod : normalizeVirtualCalculationMethod ( data . virtualCalculationMethod ) ,
reviewOutsourceFlag : data . reviewOutsourceFlag ? ? false ,
totalDistributionAmount : data . totalDistributionAmount ? ? 1 ,
progressRemark : data . progressRemark ? ? '' ,
workingDayUnitPrice :
data . workingDayUnitPrice ? ?
( isWorkingDayMethod ( data . virtualCalculationMethod ) ? DEFAULT _WORKING _DAY _UNIT _PRICE : undefined )
} )
const createGuideDetailRow = ( sortNo : number ) : GuideDetailRow => ( {
planningId : formData . value . id || 0 ,
sortNo ,
designPart : undefined ,
buildingType : '' ,
designArea : undefined ,
internalGuidanceUnitPrice : undefined ,
buildingOrUnitCount : undefined ,
drawingSetFactor : undefined ,
scaleFactor : undefined ,
modificationFactor : undefined ,
complexityFactor : undefined ,
totalAdjustmentFactor : undefined ,
designRatio : undefined ,
assessmentArea : undefined ,
assessmentOutputValue : undefined ,
remark : ''
} )
const normalizeGuideDetailList = (
list : PlanningGuideDetailApi . ProjectPlanningGuideDetailVO [ ] | undefined
) : GuideDetailRow [ ] =>
[ ... ( list || [ ] ) ]
. sort (
( a , b ) =>
Number ( a . sortNo ? ? Number . MAX _SAFE _INTEGER ) - Number ( b . sortNo ? ? Number . MAX _SAFE _INTEGER )
)
. map ( ( item , index ) => ( {
... item ,
planningId : item . planningId || formData . value . id || 0 ,
sortNo : item . sortNo ? ? index + 1 ,
buildingType : item . buildingType ? ? '' ,
remark : item . remark ? ? ''
} ) )
const addGuideDetailRow = ( ) => {
guideDetails . value . push ( createGuideDetailRow ( guideDetails . value . length + 1 ) )
}
const removeGuideDetailRow = ( index : number ) => {
guideDetails . value . splice ( index , 1 )
resetGuideDetailSortNo ( )
}
const resetGuideDetailSortNo = ( ) => {
guideDetails . value = guideDetails . value . map ( ( item , index ) => ( {
... item ,
sortNo : index + 1
} ) )
}
const getGuideDetailTotalAdjustmentFactor = ( row : GuideDetailRow ) => {
if (
row . drawingSetFactor === undefined ||
row . scaleFactor === undefined ||
row . modificationFactor === undefined ||
row . complexityFactor === undefined
) {
return undefined
}
return Number (
(
Number ( row . drawingSetFactor ) *
Number ( row . scaleFactor ) *
Number ( row . modificationFactor ) *
Number ( row . complexityFactor )
) . toFixed ( 4 )
)
}
const getGuideDetailAssessmentArea = ( row : GuideDetailRow ) => {
const totalAdjustmentFactor = getGuideDetailTotalAdjustmentFactor ( row )
if ( row . designArea === undefined || totalAdjustmentFactor === undefined ) {
return undefined
}
return Number ( ( Number ( row . designArea ) * totalAdjustmentFactor ) . toFixed ( 2 ) )
}
const getGuideDetailAssessmentOutputValue = ( row : GuideDetailRow ) => {
const assessmentArea = getGuideDetailAssessmentArea ( row )
if (
row . internalGuidanceUnitPrice === undefined ||
row . designRatio === undefined ||
assessmentArea === undefined
) {
return undefined
}
return Number (
(
Number ( row . internalGuidanceUnitPrice ) *
assessmentArea *
Number ( row . designRatio ) *
( 1 - Number ( formData . value . reviewOutsourceRatio || 0 ) )
) . toFixed ( 2 )
)
}
const guideDetailSummary = computed ( ( ) =>
guideDetails . value . reduce (
( summary , row ) => ( {
designArea : Number ( ( summary . designArea + Number ( row . designArea || 0 ) ) . toFixed ( 2 ) ) ,
assessmentArea : Number (
( summary . assessmentArea + Number ( getGuideDetailAssessmentArea ( row ) || 0 ) ) . toFixed ( 2 )
) ,
assessmentOutputValue : Number (
(
summary . assessmentOutputValue + Number ( getGuideDetailAssessmentOutputValue ( row ) || 0 )
) . toFixed ( 2 )
)
} ) ,
{
designArea : 0 ,
assessmentArea : 0 ,
assessmentOutputValue : 0
}
)
)
const contractUnitPricePreview = computed ( ( ) => {
const planningAmount = Number ( formData . value . planningAmount || 0 )
const planningArea = showGuideDetailSection . value
? Number ( guideDetailSummary . value . designArea || 0 )
: Number ( formData . value . planningArea || 0 )
if ( ! planningArea ) {
return formatAmountText ( 0 )
}
return formatAmountText ( planningAmount / planningArea )
} )
const formatFactorText = ( value ? : number , digits = 4 ) => {
if ( value === undefined || value === null ) {
return '-'
}
return Number ( value ) . toFixed ( digits )
}
const setGuideDetailPercentValue = (
row : GuideDetailRow ,
field : 'complexityFactor' | 'designRatio' ,
value ? : number | string | null
) => {
row [ field ] = fromPercentValue ( value , 4 )
}
const hasValue = ( value : unknown ) => value !== undefined && value !== null && value !== ''
const formRules = reactive < FormRules > ( {
calculationMethod : [ { required : true , message : '产值计算方式不能为空' , trigger : 'change' } ] ,
designPart : [ { required : true , message : '设计部位不能为空' , trigger : 'change' } ] ,
buildingType : [ { required : true , message : '建筑类型不能为空' , trigger : 'blur' } ] ,
planningStartYear : [ { required : true , message : '开始年度不能为空' , trigger : 'change' } ] ,
planningArea : [ { required : true , message : '工程总面积不能为空' , trigger : 'blur' } ] ,
planningArea : [
{
validator : ( _rule , value , callback ) => {
if ( showGuideDetailSection . value ) {
callback ( )
return
}
if ( ! hasValue ( value ) ) {
callback ( new Error ( '工程总面积不能为空' ) )
return
}
callback ( )
} ,
trigger : 'blur'
}
] ,
designStage : [ { required : true , message : '设计阶段不能为空' , trigger : 'change' } ] ,
currentDesignStageRatio : [
{ required : true , message : '本次设计阶段比例不能为空' , trigger : 'blur' }
@@ -541,7 +822,7 @@ const formRules = reactive<FormRules>({
calculationRatio : [
{
validator : ( _rule , value , callback ) => {
if ( showCalculationRatioField . value && ( value === undefined || value === null || value === '' ) ) {
if ( showCalculationRatioField . value && ! hasValue ( value ) ) {
callback ( new Error ( ` ${ calculationRatioLabel . value } 不能为空 ` ) )
return
}
@@ -550,21 +831,6 @@ const formRules = reactive<FormRules>({
trigger : 'blur'
}
] ,
internalGuidanceUnitPrice : [
{
validator : ( _rule , value , callback ) => {
if (
showInternalGuidanceUnitPriceField . value &&
( value === undefined || value === null || value === '' )
) {
callback ( new Error ( '内部指导单价不能为空' ) )
return
}
callback ( )
} ,
trigger : 'blur'
}
] ,
virtualCalculationMethod : [
{
validator : ( _rule , value , callback ) => {
@@ -580,7 +846,7 @@ const formRules = reactive<FormRules>({
workingDayCount : [
{
validator : ( _rule , value , callback ) => {
if ( showWorkingDayFields . value && ( value === undefined || value === null || value === '' ) ) {
if ( showWorkingDayFields . value && ! hasValue ( value ) ) {
callback ( new Error ( '工日不能为空' ) )
return
}
@@ -592,7 +858,7 @@ const formRules = reactive<FormRules>({
workingDayUnitPrice : [
{
validator : ( _rule , value , callback ) => {
if ( showWorkingDayFields . value && ( value === undefined || value === null || value === '' ) ) {
if ( showWorkingDayFields . value && ! hasValue ( value ) ) {
callback ( new Error ( '工日单价不能为空' ) )
return
}
@@ -604,10 +870,7 @@ const formRules = reactive<FormRules>({
guidanceUnitPrice : [
{
validator : ( _rule , value , callback ) => {
if (
showGuidanceUnitPriceField . value &&
( value === undefined || value === null || value === '' )
) {
if ( showGuidanceUnitPriceField . value && ! hasValue ( value ) ) {
callback ( new Error ( '指导单价不能为空' ) )
return
}
@@ -619,10 +882,7 @@ const formRules = reactive<FormRules>({
guidanceTotalPrice : [
{
validator : ( _rule , value , callback ) => {
if (
showGuidanceTotalPriceField . value &&
( value === undefined || value === null || value === '' )
) {
if ( showGuidanceTotalPriceField . value && ! hasValue ( value ) ) {
callback ( new Error ( '指导总价不能为空' ) )
return
}
@@ -668,31 +928,39 @@ watch(
}
)
watch ( showGuideDetailSection , ( value ) => {
if ( value && ! guideDetails . value . length ) {
addGuideDetailRow ( )
}
} )
const buildSavePayload = ( ) : PlanningApi . ProjectPlanningSaveVO => ( {
id : formData . value . id ,
projectId : formData . value . projectId ,
ownershipType : formData . value . ownershipType ,
designPart : formData . value . designPart ,
buildingType : formData . value . buildingType ,
calculationMethod : formData . value . calculationMethod ,
planningContent : formData . value . planningContent ,
planningAmount : formData . value . planningAmount ,
managementFeeRate : formData . value . managementFeeRate ,
implementationTeam : formData . value . implementationTeam ,
planningStartYear : formData . value . planningStartYear ,
planningArea : formData . value . planningArea ,
planningArea : showGuideDetailSection . value
? guideDetailSummary . value . designArea
: formData . value . planningArea ,
designStage : formData . value . designStage ,
currentDesignStageRatio : formData . value . currentDesignStageRatio ,
reviewOutsourceFlag : formData . value . reviewOutsourceFlag ,
reviewOutsourceRatio : formData . value . reviewOutsourceRatio ,
totalDistributionAmount : formData . value . totalDistributionAmount ,
progressRemark : formData . value . progressRemark ,
buildingOrUnitCount : formData . value . buildingOrUnitCount ,
drawingSetFactor : formData . value . drawingSetFactor ,
scaleFactor : formData . value . scaleFactor ,
modificationFactor : formData . value . modificationFactor ,
complexityFactor : formData . value . complexityFactor ,
internalGuidanceUnitPrice : formData . value . internalGuidanceUnitPrice ,
buildingOrUnitCount : showGuideDetailSection . value ? undefined : formData . value . buildingOrUnitCount ,
drawingSetFactor : showGuideDetailSection . value ? undefined : formData . value . drawingSetFactor ,
scaleFactor : showGuideDetailSection . value ? undefined : formData . value . scaleFactor ,
modificationFactor : showGuideDetailSection . value ? undefined : formData . value . modificationFactor ,
complexityFactor : showGuideDetailSection . value ? undefined : formData . value . complexityFactor ,
internalGuidanceUnitPrice : showGuideDetailSection . value
? undefined
: formData . value . internalGuidanceUnitPrice ,
virtualCalculationMethod : formData . value . virtualCalculationMethod ,
workingDayCount : formData . value . workingDayCount ,
workingDayUnitPrice : formData . value . workingDayUnitPrice ,
@@ -701,21 +969,98 @@ const buildSavePayload = (): PlanningApi.ProjectPlanningSaveVO => ({
calculationRatio : formData . value . calculationRatio
} )
const buildGuideDetailPayload = ( ) : PlanningGuideDetailApi . ProjectPlanningGuideDetailBatchSaveVO => ( {
planningId : formData . value . id ! ,
details : guideDetails . value
. map ( ( item , index ) => ( {
id : item . id ,
designPart : item . designPart ,
buildingType : item . buildingType ,
designArea : item . designArea ,
internalGuidanceUnitPrice : item . internalGuidanceUnitPrice ,
buildingOrUnitCount : item . buildingOrUnitCount ,
drawingSetFactor : item . drawingSetFactor ,
scaleFactor : item . scaleFactor ,
modificationFactor : item . modificationFactor ,
complexityFactor : item . complexityFactor ,
designRatio : item . designRatio ,
sortNo : item . sortNo ? ? index + 1 ,
remark : item . remark
} ) )
. sort ( ( a , b ) => Number ( a . sortNo || 0 ) - Number ( b . sortNo || 0 ) )
} )
const validateGuideDetails = ( ) => {
if ( ! guideDetails . value . length ) {
message . warning ( '请至少维护一条指导价法明细' )
return false
}
for ( let index = 0 ; index < guideDetails . value . length ; index ++ ) {
const row = guideDetails . value [ index ]
const rowText = ` 第 ${ index + 1 } 行 `
if ( ! row . designPart ) {
message . warning ( ` ${ rowText } 设计部位不能为空 ` )
return false
}
if ( ! row . buildingType ) {
message . warning ( ` ${ rowText } 建筑类型不能为空 ` )
return false
}
if ( ! hasValue ( row . designArea ) ) {
message . warning ( ` ${ rowText } 设计面积不能为空 ` )
return false
}
if ( ! hasValue ( row . internalGuidanceUnitPrice ) ) {
message . warning ( ` ${ rowText } 内部指导单价不能为空 ` )
return false
}
if ( ! hasValue ( row . drawingSetFactor ) ) {
message . warning ( ` ${ rowText } 套图系数不能为空 ` )
return false
}
if ( ! hasValue ( row . scaleFactor ) ) {
message . warning ( ` ${ rowText } 规模系数不能为空 ` )
return false
}
if ( ! hasValue ( row . modificationFactor ) ) {
message . warning ( ` ${ rowText } 修改系数不能为空 ` )
return false
}
if ( ! hasValue ( row . complexityFactor ) ) {
message . warning ( ` ${ rowText } 复杂系数不能为空 ` )
return false
}
if ( ! hasValue ( row . designRatio ) ) {
message . warning ( ` ${ rowText } 设计占比不能为空 ` )
return false
}
}
return true
}
const open = async ( id : number ) => {
dialogVisible . value = true
dialogTitle . value = t ( 'action.update' )
formLoading . value = true
try {
const data = await PlanningApi . getProjectPlanning ( id )
formData . value = normalizeFormData ( data )
guideDetails . value = showGuideDetailSection . value
? normalizeGuideDetailList (
await PlanningGuideDetailApi . getProjectPlanningGuideDetailListByPlanningId ( id )
)
: [ ]
applyCalculationRatioDefault ( )
if ( formData . value . reviewOutsourceRatio === undefined || formData . value . reviewOutsourceRatio === null ) {
applyReviewOutsourceDefault ( )
}
if ( showGuideDetailSection . value && ! guideDetails . value . length ) {
addGuideDetailRow ( )
}
} finally {
formLoading . value = false
}
}
defineExpose ( { open } )
const emit = defineEmits ( [ 'success' ] )
@@ -728,10 +1073,17 @@ const submitForm = async () => {
if ( ! valid ) {
return
}
if ( showGuideDetailSection . value && ! validateGuideDetails ( ) ) {
return
}
formLoading . value = true
try {
await PlanningApi . updateProjectPlanning ( buildSavePayload ( ) )
message . success ( t ( 'common.updateSuccess' ) )
if ( showGuideDetailSection . value && formData . value . id ) {
await PlanningGuideDetailApi . batchSaveProjectPlanningGuideDetail ( buildGuideDetailPayload ( ) )
}
message . success ( '保存成功' )
dialogVisible . value = false
emit ( 'success' )
} finally {
@@ -739,3 +1091,17 @@ const submitForm = async () => {
}
}
< / script >
< style scoped >
/* 优化无控制按钮的 Input Number 显示样式 */
: deep ( . optimized - table . el - input - number . el - input _ _inner ) {
text - align : left ;
}
/* 给只读计算结果列添加淡淡的背景色用于视觉区分 */
: deep ( . bg - gray - 50 ) {
background - color : # f9fafc ! important ;
}
: deep ( . text - primary ) {
color : var ( -- el - color - primary ) ;
}
< / style >