修改代码

This commit is contained in:
lzm
2026-04-17 18:17:42 +08:00
parent a770170871
commit 8f9205a6a1
20 changed files with 5205 additions and 6 deletions

View File

@@ -0,0 +1,600 @@
<template>
<Dialog v-model="dialogVisible" title="合约规划编辑" width="1120">
<el-form
ref="formRef"
v-loading="formLoading"
:model="formData"
:rules="formRules"
label-width="150px"
>
<el-divider content-position="left">规划头信息</el-divider>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="归属类型">
<el-input :model-value="formData.ownershipType" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="产值计算方式">
<el-input :model-value="formData.calculationMethod" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="规划内容">
<el-input :model-value="formData.planningContent" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="规划金额(元)">
<el-input :model-value="formatAmountText(formData.planningAmount)" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="管理费费率(%)">
<el-input :model-value="formatPercentText(formData.managementFeeRate)" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="实施团队">
<el-input :model-value="formData.implementationTeam || '-'" disabled />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">测算参数</el-divider>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="开始年度" prop="planningStartYear">
<el-date-picker
v-model="planningStartYearValue"
class="!w-1/1"
placeholder="请选择开始年度"
type="year"
value-format="YYYY"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="面积(㎡)" prop="planningArea">
<el-input-number
v-model="formData.planningArea"
:min="0"
:precision="2"
:step="100"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="合同单价(元/㎡)">
<el-input :model-value="contractUnitPricePreview" disabled />
</el-form-item>
</el-col>
</el-row>
<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-option
v-for="item in DESIGN_STAGE_OPTIONS"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</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
v-model="currentDesignStageRatioPercent"
:min="0"
:precision="2"
:step="0.01"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="审核审定是否外包" prop="reviewOutsourceFlag">
<el-switch
v-model="formData.reviewOutsourceFlag"
active-text=""
inactive-text=""
@change="handleReviewOutsourceFlagChange"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="审核审定占比(%)" prop="reviewOutsourceRatio">
<el-input-number
v-model="reviewOutsourceRatioPercent"
:min="0"
:precision="2"
:step="0.01"
class="!w-1/1"
controls-position="right"
/>
</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
v-model="calculationRatioPercent"
:min="0"
:precision="2"
:step="0.01"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :span="showCalculationRatioField ? 8 : 12">
<el-form-item label="总分配(%)" prop="totalDistributionAmount">
<el-input-number
v-model="totalDistributionAmountPercent"
:min="0"
:precision="2"
:step="0.01"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
</el-row>
<!-- <el-row :gutter="16">
<el-col :span="24">
<el-form-item label="提取进度备注" prop="progressRemark">
<el-input
v-model="formData.progressRemark"
:rows="3"
maxlength="500"
placeholder="请输入合约规划层级的提取进度备注"
show-word-limit
type="textarea"
/>
</el-form-item>
</el-col>
</el-row> -->
<template v-if="showMajorFactorFields">
<el-divider content-position="left">专业所测算参数</el-divider>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="楼栋数/户型数" prop="buildingOrUnitCount">
<el-input-number
v-model="formData.buildingOrUnitCount"
:min="0"
:precision="0"
:step="1"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="套图系数" prop="drawingSetFactor">
<el-input-number
v-model="formData.drawingSetFactor"
:min="0"
:precision="2"
:step="0.01"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="规模系数" prop="scaleFactor">
<el-input-number
v-model="formData.scaleFactor"
:min="0"
:precision="2"
:step="0.01"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="修改系数" prop="modificationFactor">
<el-input-number
v-model="formData.modificationFactor"
:min="0"
:precision="2"
:step="0.01"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="复杂系数/复杂等级(%)" prop="complexityFactor">
<el-input-number
v-model="complexityFactorPercent"
:min="0"
:precision="2"
:step="0.01"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
</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="内部指导单价(元/㎡)" prop="internalGuidanceUnitPrice">
<el-input-number
v-model="formData.internalGuidanceUnitPrice"
:min="0"
:precision="2"
:step="1"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
</el-row>
</template>
<template v-if="showVirtualOutputSection">
<el-divider content-position="left">虚拟产值法参数</el-divider>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="虚拟产值计算方式" prop="virtualCalculationMethod">
<el-select
v-model="formData.virtualCalculationMethod"
class="!w-1/1"
placeholder="请选择虚拟产值计算方式"
>
<el-option
v-for="item in VIRTUAL_CALCULATION_METHOD_OPTIONS"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col v-if="showWorkingDayFields" :span="8">
<el-form-item label="工日" prop="workingDayCount">
<el-input-number
v-model="formData.workingDayCount"
:min="0"
:precision="2"
:step="1"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col v-if="showWorkingDayFields" :span="8">
<el-form-item label="工日单价(元)" prop="workingDayUnitPrice">
<el-input-number
v-model="formData.workingDayUnitPrice"
:min="0"
:precision="2"
:step="100"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="showVirtualGuidanceFields" :gutter="16">
<el-col :span="8">
<el-form-item label="指导单价(元)" prop="guidanceUnitPrice">
<el-input-number
v-model="formData.guidanceUnitPrice"
:min="0"
:precision="2"
:step="1"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="指导总价(元)" prop="guidanceTotalPrice">
<el-input-number
v-model="formData.guidanceTotalPrice"
:min="0"
:precision="2"
:step="1000"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="showVirtualTotalPriceFields" :gutter="16">
<el-col :span="8">
<el-form-item label="虚拟总价(元)" prop="virtualTotalPrice">
<el-input-number
v-model="formData.virtualTotalPrice"
:min="0"
:precision="2"
:step="1000"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
</el-row>
</template>
</el-form>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm">保存</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</template>
</Dialog>
</template>
<script lang="ts" setup>
import type { FormRules } from 'element-plus'
import * as PlanningApi from '@/api/tjt/planning'
import {
DESIGN_STAGE_OPTIONS,
VIRTUAL_CALCULATION_METHOD_OPTIONS,
formatAmountText,
formatPercentText,
fromPercentValue,
getCalculationRatioDefaultPercent,
getCalculationRatioLabel,
getReviewOutsourceDefaultPercent,
isComprehensiveOwnership,
isContractPriceMethod,
isGuidancePriceMethod,
isMajorOwnership,
isSubcontractOwnership,
isVirtualGuidanceMethod,
isVirtualOutputMethod,
isVirtualTotalPriceMethod,
isWorkingDayMethod,
toPercentValue
} from '@/views/tjt/shared/planning'
defineOptions({ name: 'TjtPlanningOutputForm' })
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>({
projectId: 0,
ownershipType: '',
calculationMethod: '',
planningContent: ''
})
const normalizeFormData = (data: PlanningApi.ProjectPlanningVO): PlanningApi.ProjectPlanningVO => ({
...data,
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
})
const planningStartYearValue = computed({
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),
set: (value) => {
formData.value[field] = fromPercentValue(value, 4) as never
}
})
const currentDesignStageRatioPercent = createPercentModel('currentDesignStageRatio')
const reviewOutsourceRatioPercent = createPercentModel('reviewOutsourceRatio')
const calculationRatioPercent = createPercentModel('calculationRatio')
const totalDistributionAmountPercent = createPercentModel('totalDistributionAmount')
const complexityFactorPercent = createPercentModel('complexityFactor')
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(
() =>
isMajorOwnership(formData.value.ownershipType) &&
isGuidancePriceMethod(formData.value.calculationMethod)
)
const showVirtualOutputSection = computed(
() =>
isMajorOwnership(formData.value.ownershipType) &&
isVirtualOutputMethod(formData.value.calculationMethod)
)
const showWorkingDayFields = computed(() => isWorkingDayMethod(formData.value.virtualCalculationMethod))
const showVirtualGuidanceFields = computed(
() => isVirtualGuidanceMethod(formData.value.virtualCalculationMethod)
)
const showVirtualTotalPriceFields = computed(
() => isVirtualTotalPriceMethod(formData.value.virtualCalculationMethod)
)
const formRules = reactive<FormRules>({
planningStartYear: [{ required: true, message: '开始年度不能为空', trigger: 'change' }],
planningArea: [{ required: true, message: '面积不能为空', trigger: 'blur' }],
designStage: [{ required: true, message: '设计阶段不能为空', trigger: 'change' }],
currentDesignStageRatio: [
{ required: true, message: '本次设计阶段比例不能为空', trigger: 'blur' }
],
totalDistributionAmount: [{ required: true, message: '总分配不能为空', trigger: 'blur' }],
calculationRatio: [
{
validator: (_rule, value, callback) => {
if (showCalculationRatioField.value && (value === undefined || value === null || value === '')) {
callback(new Error(`${calculationRatioLabel.value}不能为空`))
return
}
callback()
},
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) => {
if (showVirtualOutputSection.value && !value) {
callback(new Error('请选择虚拟产值计算方式'))
return
}
callback()
},
trigger: 'change'
}
]
})
const applyReviewOutsourceDefault = () => {
formData.value.reviewOutsourceRatio = fromPercentValue(
getReviewOutsourceDefaultPercent(
formData.value.ownershipType,
formData.value.reviewOutsourceFlag
)
)
}
const applyCalculationRatioDefault = () => {
const defaultPercent = getCalculationRatioDefaultPercent(formData.value.ownershipType)
if (defaultPercent === undefined) {
return
}
if (formData.value.calculationRatio === undefined || formData.value.calculationRatio === null) {
formData.value.calculationRatio = fromPercentValue(defaultPercent)
}
}
const handleReviewOutsourceFlagChange = () => {
applyReviewOutsourceDefault()
}
const buildSavePayload = (): PlanningApi.ProjectPlanningSaveVO => ({
id: formData.value.id,
projectId: formData.value.projectId,
ownershipType: formData.value.ownershipType,
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,
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,
virtualCalculationMethod: formData.value.virtualCalculationMethod,
workingDayCount: formData.value.workingDayCount,
workingDayUnitPrice: formData.value.workingDayUnitPrice,
guidanceUnitPrice: formData.value.guidanceUnitPrice,
guidanceTotalPrice: formData.value.guidanceTotalPrice,
virtualTotalPrice: formData.value.virtualTotalPrice,
calculationRatio: formData.value.calculationRatio
})
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)
applyCalculationRatioDefault()
if (formData.value.reviewOutsourceRatio === undefined || formData.value.reviewOutsourceRatio === null) {
applyReviewOutsourceDefault()
}
} finally {
formLoading.value = false
}
}
defineExpose({ open })
const emit = defineEmits(['success'])
const submitForm = async () => {
if (!formRef.value) {
return
}
const valid = await formRef.value.validate()
if (!valid) {
return
}
formLoading.value = true
try {
await PlanningApi.updateProjectPlanning(buildSavePayload())
message.success(t('common.updateSuccess'))
dialogVisible.value = false
emit('success')
} finally {
formLoading.value = false
}
}
</script>