Files
tjt_czjs_ui/src/views/tjt/output/PlanningOutputForm.vue

742 lines
25 KiB
Vue
Raw Normal View History

2026-04-17 18:17:42 +08:00
<template>
2026-04-25 18:10:45 +08:00
<Dialog v-model="dialogVisible" :title="dialogTitle" width="1120">
2026-04-17 18:17:42 +08:00
<el-form
ref="formRef"
v-loading="formLoading"
:model="formData"
:rules="formRules"
label-width="150px"
>
2026-04-25 18:10:45 +08:00
<el-divider content-position="left">规划信息</el-divider>
2026-04-17 18:17:42 +08:00
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="归属类型">
2026-04-25 18:10:45 +08:00
<el-input :model-value="ownershipTypeLabel" disabled />
2026-04-17 18:17:42 +08:00
</el-form-item>
</el-col>
<el-col :span="8">
2026-04-25 18:10:45 +08:00
<el-form-item label="产值计算方式" prop="calculationMethod">
<el-select
v-model="formData.calculationMethod"
class="!w-1/1"
placeholder="请选择产值计算方式"
>
<el-option
v-for="item in calculationMethodOptions"
:key="String(item.value)"
:label="item.label"
:value="item.value"
/>
</el-select>
2026-04-17 18:17:42 +08:00
</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>
2026-04-25 18:10:45 +08:00
2026-04-17 18:17:42 +08:00
<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">
2026-04-25 18:10:45 +08:00
<el-form-item label="管理费率(%)">
2026-04-17 18:17:42 +08:00
<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>
2026-04-25 18:10:45 +08:00
<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>
2026-04-17 18:17:42 +08:00
<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">
2026-04-25 18:10:45 +08:00
<el-form-item label="工程总面积(m²)" prop="planningArea">
2026-04-17 18:17:42 +08:00
<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">
2026-04-25 18:10:45 +08:00
<el-form-item label="合同单价(元/m²)">
2026-04-17 18:17:42 +08:00
<el-input :model-value="contractUnitPricePreview" disabled />
</el-form-item>
</el-col>
</el-row>
2026-04-25 18:10:45 +08:00
2026-04-17 18:17:42 +08:00
<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
2026-04-25 18:10:45 +08:00
v-for="item in designStageOptions"
:key="String(item.value)"
2026-04-17 18:17:42 +08:00
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
2026-04-25 18:10:45 +08:00
2026-04-17 18:17:42 +08:00
<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>
2026-04-25 18:10:45 +08:00
2026-04-17 18:17:42 +08:00
<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>
<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">
2026-04-25 18:10:45 +08:00
<el-form-item label="内部指导单价(元/m²)" prop="internalGuidanceUnitPrice">
2026-04-17 18:17:42 +08:00
<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
2026-04-25 18:10:45 +08:00
v-for="item in virtualCalculationMethodOptions"
:key="String(item.value)"
2026-04-17 18:17:42 +08:00
: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>
2026-04-25 18:10:45 +08:00
<el-row v-if="showGuidanceUnitPriceField" :gutter="16">
2026-04-17 18:17:42 +08:00
<el-col :span="8">
2026-04-25 18:10:45 +08:00
<el-form-item label="指导单价(元/m²)" prop="guidanceUnitPrice">
2026-04-17 18:17:42 +08:00
<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>
2026-04-25 18:10:45 +08:00
</el-row>
<el-row v-if="showGuidanceTotalPriceField" :gutter="16">
2026-04-17 18:17:42 +08:00
<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>
</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 {
2026-04-25 18:10:45 +08:00
CALCULATION_METHOD_OPTIONS,
DEFAULT_WORKING_DAY_UNIT_PRICE,
2026-04-17 18:17:42 +08:00
DESIGN_STAGE_OPTIONS,
2026-04-25 18:10:45 +08:00
OWNERSHIP_TYPE_OPTIONS,
2026-04-17 18:17:42 +08:00
VIRTUAL_CALCULATION_METHOD_OPTIONS,
formatAmountText,
formatPercentText,
fromPercentValue,
getCalculationRatioDefaultPercent,
getCalculationRatioLabel,
getReviewOutsourceDefaultPercent,
isComprehensiveOwnership,
isContractPriceMethod,
isGuidancePriceMethod,
isMajorOwnership,
isSubcontractOwnership,
isVirtualGuidanceMethod,
2026-04-25 18:10:45 +08:00
isVirtualGuidanceTotalPriceMethod,
2026-04-17 18:17:42 +08:00
isVirtualOutputMethod,
isWorkingDayMethod,
2026-04-25 18:10:45 +08:00
normalizeCalculationMethod,
normalizeDesignStage,
normalizeOwnershipType,
normalizeVirtualCalculationMethod,
2026-04-17 18:17:42 +08:00
toPercentValue
} from '@/views/tjt/shared/planning'
defineOptions({ name: 'TjtPlanningOutputForm' })
2026-04-25 18:10:45 +08:00
const DESIGN_PART_OPTIONS = [
{ label: '地上部分', value: '地上部分' },
{ label: '地下部分', value: '地下部分' }
]
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
)
2026-04-17 18:17:42 +08:00
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: ''
})
2026-04-25 18:10:45 +08:00
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)
)
2026-04-17 18:17:42 +08:00
const normalizeFormData = (data: PlanningApi.ProjectPlanningVO): PlanningApi.ProjectPlanningVO => ({
...data,
2026-04-25 18:10:45 +08:00
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),
2026-04-17 18:17:42 +08:00
reviewOutsourceFlag: data.reviewOutsourceFlag ?? false,
totalDistributionAmount: data.totalDistributionAmount ?? 1,
progressRemark: data.progressRemark ?? '',
drawingSetFactor: data.drawingSetFactor ?? 1,
scaleFactor: data.scaleFactor ?? 1,
modificationFactor: data.modificationFactor ?? 1,
2026-04-25 18:10:45 +08:00
complexityFactor: data.complexityFactor ?? 1,
workingDayUnitPrice:
data.workingDayUnitPrice ??
(isWorkingDayMethod(data.virtualCalculationMethod) ? DEFAULT_WORKING_DAY_UNIT_PRICE : undefined),
guidanceTotalPrice: data.guidanceTotalPrice
2026-04-17 18:17:42 +08:00
})
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))
2026-04-25 18:10:45 +08:00
const showGuidanceUnitPriceField = computed(
2026-04-17 18:17:42 +08:00
() => isVirtualGuidanceMethod(formData.value.virtualCalculationMethod)
)
2026-04-25 18:10:45 +08:00
const showGuidanceTotalPriceField = computed(
() => isVirtualGuidanceTotalPriceMethod(formData.value.virtualCalculationMethod)
2026-04-17 18:17:42 +08:00
)
const formRules = reactive<FormRules>({
2026-04-25 18:10:45 +08:00
calculationMethod: [{ required: true, message: '产值计算方式不能为空', trigger: 'change' }],
designPart: [{ required: true, message: '设计部位不能为空', trigger: 'change' }],
buildingType: [{ required: true, message: '建筑类型不能为空', trigger: 'blur' }],
2026-04-17 18:17:42 +08:00
planningStartYear: [{ required: true, message: '开始年度不能为空', trigger: 'change' }],
2026-04-25 18:10:45 +08:00
planningArea: [{ required: true, message: '工程总面积不能为空', trigger: 'blur' }],
2026-04-17 18:17:42 +08:00
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) => {
2026-04-25 18:10:45 +08:00
if (
showInternalGuidanceUnitPriceField.value &&
(value === undefined || value === null || value === '')
) {
2026-04-17 18:17:42 +08:00
callback(new Error('内部指导单价不能为空'))
return
}
callback()
},
trigger: 'blur'
}
],
virtualCalculationMethod: [
{
validator: (_rule, value, callback) => {
if (showVirtualOutputSection.value && !value) {
callback(new Error('请选择虚拟产值计算方式'))
return
}
callback()
},
trigger: 'change'
}
2026-04-25 18:10:45 +08:00
],
workingDayCount: [
{
validator: (_rule, value, callback) => {
if (showWorkingDayFields.value && (value === undefined || value === null || value === '')) {
callback(new Error('工日不能为空'))
return
}
callback()
},
trigger: 'blur'
}
],
workingDayUnitPrice: [
{
validator: (_rule, value, callback) => {
if (showWorkingDayFields.value && (value === undefined || value === null || value === '')) {
callback(new Error('工日单价不能为空'))
return
}
callback()
},
trigger: 'blur'
}
],
guidanceUnitPrice: [
{
validator: (_rule, value, callback) => {
if (
showGuidanceUnitPriceField.value &&
(value === undefined || value === null || value === '')
) {
callback(new Error('指导单价不能为空'))
return
}
callback()
},
trigger: 'blur'
}
],
guidanceTotalPrice: [
{
validator: (_rule, value, callback) => {
if (
showGuidanceTotalPriceField.value &&
(value === undefined || value === null || value === '')
) {
callback(new Error('指导总价不能为空'))
return
}
callback()
},
trigger: 'blur'
}
2026-04-17 18:17:42 +08:00
]
})
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()
}
2026-04-25 18:10:45 +08:00
watch(
() => formData.value.virtualCalculationMethod,
(value) => {
if (
isWorkingDayMethod(value) &&
(formData.value.workingDayUnitPrice === undefined || formData.value.workingDayUnitPrice === null)
) {
formData.value.workingDayUnitPrice = DEFAULT_WORKING_DAY_UNIT_PRICE
}
}
)
2026-04-17 18:17:42 +08:00
const buildSavePayload = (): PlanningApi.ProjectPlanningSaveVO => ({
id: formData.value.id,
projectId: formData.value.projectId,
ownershipType: formData.value.ownershipType,
2026-04-25 18:10:45 +08:00
designPart: formData.value.designPart,
buildingType: formData.value.buildingType,
2026-04-17 18:17:42 +08:00
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,
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>