Files
hzdyjs/web/src/views/cw/application/form.vue
T
2025-08-01 09:03:43 +08:00

1210 lines
36 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="p-2 page-container">
<!-- 页面头部 -->
<el-card shadow="never" class="header-card">
<div class="header-content">
<div class="header-info">
<h2 class="page-title">
<el-icon><Document /></el-icon>
{{ form.id ? '修改' : '新增' }}项目预算申报
</h2>
<p class="page-desc">填写项目预算申报信息,提交审批流程</p>
</div>
<div class="header-actions">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSaveDraft" :loading="savingDraft">保存草稿</el-button>
<el-button type="success" @click="handleSubmit" :loading="submitting" v-if="canSubmit">提交申报</el-button>
</div>
</div>
</el-card>
<!-- 进度步骤 -->
<el-card shadow="never" class="steps-card mb-[10px]">
<el-steps :active="currentStep" finish-status="success" align-center>
<el-step title="基本信息" description="填写项目基本信息">
<template #icon>
<el-icon><User /></el-icon>
</template>
</el-step>
<el-step title="项目内容" description="填写项目详细内容">
<template #icon>
<el-icon><Document /></el-icon>
</template>
</el-step>
<el-step title="资金预算" description="填写各项资金预算">
<template #icon>
<el-icon><Money /></el-icon>
</template>
</el-step>
<el-step title="绩效指标" description="填写绩效目标指标">
<template #icon>
<el-icon><TrendCharts /></el-icon>
</template>
</el-step>
<el-step title="提交确认" description="确认信息并提交">
<template #icon>
<el-icon><Check /></el-icon>
</template>
</el-step>
</el-steps>
</el-card>
<!-- 表单内容区域 -->
<div class="form-content">
<!-- 第一步:基本信息 -->
<el-card shadow="never" class="form-card" v-show="currentStep === 0">
<template #header>
<div class="card-header">
<el-icon><User /></el-icon>
<span>项目基本信息</span>
</div>
</template>
<el-form ref="basicFormRef" :model="form" :rules="rules" label-width="120px" label-position="top">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目名称" prop="projectName">
<el-input
v-model="form.projectName"
placeholder="请输入项目名称"
size="large"
:prefix-icon="Document"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目负责人" prop="principal">
<el-input
v-model="form.principal"
placeholder="请输入项目负责人"
size="large"
:prefix-icon="User"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="联系电话" prop="contactPhone">
<el-input
v-model="form.contactPhone"
placeholder="请输入联系电话"
size="large"
:prefix-icon="Phone"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预算年度" prop="year">
<el-date-picker
v-model="form.year"
type="year"
placeholder="选择年份"
value-format="YYYY"
size="large"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目开始日期" prop="startDate">
<el-date-picker
v-model="form.startDate"
type="date"
placeholder="选择开始日期"
value-format="YYYY-MM-DD"
size="large"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目结束日期" prop="endDate">
<el-date-picker
v-model="form.endDate"
type="date"
placeholder="选择结束日期"
value-format="YYYY-MM-DD"
size="large"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 项目特征选项 -->
<div class="feature-section">
<h4 class="section-title">项目特征</h4>
<el-row :gutter="20">
<el-col :span="8">
<div class="feature-item">
<el-switch
v-model="form.targetSme"
size="large"
active-text="面向中小企业"
inactive-text="不面向中小企业"
/>
</div>
</el-col>
<el-col :span="8">
<div class="feature-item">
<el-switch
v-model="form.targetMicroSme"
size="large"
active-text="面向小微企业"
inactive-text="不面向小微企业"
/>
</div>
</el-col>
<el-col :span="8">
<div class="feature-item">
<el-switch
v-model="form.importEquipment"
size="large"
active-text="采购进口设备"
inactive-text="不采购进口设备"
/>
</div>
</el-col>
</el-row>
</div>
</el-form>
</el-card>
<!-- 第二步:项目内容 -->
<el-card shadow="never" class="form-card" v-show="currentStep === 1">
<template #header>
<div class="card-header">
<el-icon><Document /></el-icon>
<span>项目详细内容</span>
</div>
</template>
<el-form ref="contentFormRef" :model="form" :rules="rules" label-width="120px" label-position="top">
<el-form-item label="项目申请原因" prop="applicationReason">
<el-input
v-model="form.applicationReason"
type="textarea"
:rows="5"
placeholder="请详细说明项目申请原因,包括设立依据、可行性及必要性"
maxlength="1000"
show-word-limit
/>
</el-form-item>
<el-form-item label="项目建设内容" prop="constructionContent">
<el-input
v-model="form.constructionContent"
type="textarea"
:rows="5"
placeholder="请详细描述项目建设内容"
maxlength="1000"
show-word-limit
/>
</el-form-item>
<el-form-item label="绩效总目标" prop="totalPerformanceGoal">
<el-input
v-model="form.totalPerformanceGoal"
type="textarea"
:rows="4"
placeholder="请描述项目的总体绩效目标"
maxlength="500"
show-word-limit
/>
</el-form-item>
<el-form-item label="当年绩效目标" prop="currentYearGoal">
<el-input
v-model="form.currentYearGoal"
type="textarea"
:rows="4"
placeholder="请描述当年需要达成的绩效目标"
maxlength="500"
show-word-limit
/>
</el-form-item>
</el-form>
</el-card>
<!-- 第三步:资金预算 -->
<el-card shadow="never" class="form-card" v-show="currentStep === 2">
<template #header>
<div class="card-header">
<el-icon><Money /></el-icon>
<span>资金预算明细</span>
<el-tag type="warning" size="small">单位:万元</el-tag>
</div>
</template>
<el-form ref="budgetFormRef" :model="form" :rules="rules" label-width="120px" label-position="top">
<!-- 总投资情况 -->
<div class="budget-section">
<h4 class="section-title">
<el-icon><TrendCharts /></el-icon>
总投资情况
</h4>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="项目总投资" prop="totalInvestment">
<el-input-number
v-model="form.totalInvestment"
:precision="2"
:min="0"
:max="99999999"
placeholder="万元"
size="large"
style="width: 100%"
@change="calculateTotalInvestment"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="市财政资金" prop="totalMunicipalFiscal">
<el-input-number
v-model="form.totalMunicipalFiscal"
:precision="2"
:min="0"
placeholder="万元"
size="large"
style="width: 100%"
@change="calculateTotalInvestment"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="单位自筹" prop="totalSelfFunding">
<el-input-number
v-model="form.totalSelfFunding"
:precision="2"
:min="0"
placeholder="万元"
size="large"
style="width: 100%"
@change="calculateTotalInvestment"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="其他资金" prop="totalOtherFunding">
<el-input-number
v-model="form.totalOtherFunding"
:precision="2"
:min="0"
placeholder="万元"
size="large"
style="width: 100%"
@change="calculateTotalInvestment"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 年度执行预算 -->
<div class="budget-section">
<h4 class="section-title">
<el-icon><Calendar /></el-icon>
年度预计执行数
</h4>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="年度执行合计" prop="yearlyTotal">
<el-input-number
v-model="form.yearlyTotal"
:precision="2"
:min="0"
placeholder="万元"
size="large"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年度财政资金" prop="yearlyMunicipalFiscal">
<el-input-number
v-model="form.yearlyMunicipalFiscal"
:precision="2"
:min="0"
placeholder="万元"
size="large"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年度自筹资金" prop="yearlySelfFunding">
<el-input-number
v-model="form.yearlySelfFunding"
:precision="2"
:min="0"
placeholder="万元"
size="large"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年度其他资金" prop="yearlyOtherFunding">
<el-input-number
v-model="form.yearlyOtherFunding"
:precision="2"
:min="0"
placeholder="万元"
size="large"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 资金分配图表 -->
<div class="budget-chart" v-if="hasBudgetData">
<h4 class="section-title">资金分配可视化</h4>
<div ref="budgetChart" style="height: 300px;"></div>
</div>
</el-form>
</el-card>
<!-- 第四步:绩效指标 -->
<el-card shadow="never" class="form-card" v-show="currentStep === 3">
<template #header>
<div class="card-header">
<el-icon><TrendCharts /></el-icon>
<span>绩效指标设置</span>
</div>
</template>
<el-form ref="performanceFormRef" :model="form" label-width="120px" label-position="top">
<PerformanceIndicators
ref="performanceIndicatorsRef"
v-model="form.performanceIndicators"
@change="handlePerformanceIndicatorsChange"
/>
</el-form>
</el-card>
<!-- 第五步:确认提交 -->
<el-card shadow="never" class="form-card" v-show="currentStep === 4">
<template #header>
<div class="card-header">
<el-icon><Check /></el-icon>
<span>信息确认</span>
</div>
</template>
<!-- 信息预览 -->
<div class="confirmation-content">
<div class="confirmation-section">
<h4>基本信息</h4>
<el-descriptions :column="2" border>
<el-descriptions-item label="项目名称">{{ form.projectName }}</el-descriptions-item>
<el-descriptions-item label="项目负责人">{{ form.principal }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ form.contactPhone }}</el-descriptions-item>
<el-descriptions-item label="预算年度">{{ form.year }}</el-descriptions-item>
<el-descriptions-item label="项目周期">{{ form.startDate }} 至 {{ form.endDate }}</el-descriptions-item>
<el-descriptions-item label="总投资">{{ formatAmount(form.totalInvestment) }} 万元</el-descriptions-item>
</el-descriptions>
</div>
<div class="confirmation-actions">
<el-alert
title="提交确认"
description="请仔细核对上述信息,提交后将进入审批流程,无法直接修改。"
type="warning"
show-icon
:closable="false"
/>
</div>
</div>
</el-card>
</div>
<!-- 底部操作按钮 -->
<el-card shadow="never" class="footer-card">
<div class="footer-actions">
<el-button @click="handlePrevStep" v-if="currentStep > 0">
<el-icon><ArrowLeft /></el-icon>
上一步
</el-button>
<div class="action-group">
<el-button @click="handleCancel">取消</el-button>
<el-button type="info" @click="handleSaveDraft" :loading="savingDraft">保存草稿</el-button>
<el-button type="primary" @click="handleNextStep" v-if="currentStep < 4">
下一步
<el-icon><ArrowRight /></el-icon>
</el-button>
<el-button type="success" @click="handleSubmit" :loading="submitting" v-if="currentStep === 4">
<el-icon><Check /></el-icon>
提交申报
</el-button>
</div>
</div>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, nextTick, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus'
import {
Document, User, Phone, Money, TrendCharts, Check, Calendar,
ArrowLeft, ArrowRight
} from '@element-plus/icons-vue'
import * as echarts from 'echarts'
import {
getProjectApplication,
addProjectApplication,
updateProjectApplication,
submitApplication,
saveDraft
} from '@/api/cw/projectApplication'
import PerformanceIndicators from './components/PerformanceIndicators.vue'
// 接收父组件传递的数据
const props = defineProps<{
formData?: any
}>()
const router = useRouter()
const route = useRoute()
// 表单引用
const basicFormRef = ref()
const contentFormRef = ref()
const budgetFormRef = ref()
const performanceFormRef = ref()
const performanceIndicatorsRef = ref()
// 当前步骤
const currentStep = ref(0)
const activeTab = ref('quantity')
// 加载状态
const savingDraft = ref(false)
const submitting = ref(false)
// 图表引用
const budgetChart = ref()
let budgetChartInstance: echarts.ECharts | null = null
// 表单数据
const form = reactive({
id: undefined,
applicationNo: '',
projectName: '',
principal: '',
contactPhone: '',
year: new Date().getFullYear().toString(),
startDate: '',
endDate: '',
targetSme: false,
targetMicroSme: false,
importEquipment: false,
applicationReason: '',
constructionContent: '',
totalPerformanceGoal: '',
currentYearGoal: '',
// 项目总投资
totalInvestment: 0,
totalMunicipalFiscal: 0,
totalSelfFunding: 0,
totalOtherFunding: 0,
// 年度预计执行数
currentYearTotal: 0,
currentYearMunicipal: 0,
currentYearSelf: 0,
currentYearOther: 0,
// 下年度申请资金
nextYearTotal: 0,
nextYearMunicipal: 0,
nextYearSelf: 0,
nextYearOther: 0,
// 以后年度安排
futureYearTotal: 0,
futureYearMunicipal: 0,
futureYearSelf: 0,
futureYearOther: 0,
// 绩效指标
performanceIndicators: [],
approvalStatus: 'draft'
})
// 监听父组件传递的数据变化
watch(() => props.formData, (newData) => {
if (newData && typeof newData === 'object' && Object.keys(newData).length > 0) {
console.log('接收到父组件传递的数据:', newData)
// 安全地更新form数据
Object.keys(form).forEach(key => {
if (newData.hasOwnProperty(key) && newData[key] !== null && newData[key] !== undefined) {
// 特殊处理不同类型的字段
if (key === 'year' && newData[key]) {
form[key] = newData[key].toString()
} else if (key === 'startDate' || key === 'endDate') {
form[key] = newData[key] ? formatDateString(newData[key]) : ''
} else if (key.includes('Investment') || key.includes('Fiscal') || key.includes('Funding') ||
key.includes('Total') || key.includes('Municipal') || key.includes('Self') || key.includes('Other')) {
// 金额字段
form[key] = Number(newData[key]) || 0
} else {
form[key] = newData[key]
}
}
})
console.log('form数据更新完成:', form)
}
}, { deep: true, immediate: true })
// 日期格式化函数
const formatDateString = (dateValue: any): string => {
if (!dateValue) return ''
let date: Date
if (typeof dateValue === 'string') {
date = new Date(dateValue)
} else if (dateValue instanceof Date) {
date = dateValue
} else {
return ''
}
if (isNaN(date.getTime())) return ''
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
// 表单验证规则
const rules = {
projectName: [
{ required: true, message: '请输入项目名称', trigger: 'blur' },
{ min: 2, max: 100, message: '项目名称长度在 2 到 100 个字符', trigger: 'blur' }
],
principal: [
{ required: true, message: '请输入项目负责人', trigger: 'blur' }
],
contactPhone: [
{ required: true, message: '请输入联系电话', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
],
year: [
{ required: true, message: '请选择预算年度', trigger: 'change' }
],
startDate: [
{ required: true, message: '请选择项目开始日期', trigger: 'change' }
],
endDate: [
{ required: true, message: '请选择项目结束日期', trigger: 'change' }
],
totalInvestment: [
{ required: true, message: '请填写项目总投资', trigger: 'blur' },
{ type: 'number', min: 0.01, message: '投资金额必须大于0', trigger: 'blur' }
]
}
// 计算属性
const canSubmit = computed(() => {
return form.projectName && form.principal && form.totalInvestment > 0
})
const hasBudgetData = computed(() => {
return form.totalMunicipalFiscal > 0 || form.totalSelfFunding > 0 || form.totalOtherFunding > 0
})
// 格式化金额
const formatAmount = (amount: number): string => {
return amount ? amount.toFixed(2) : '0.00'
}
// 计算总投资
const calculateTotalInvestment = () => {
form.totalInvestment = (form.totalMunicipalFiscal || 0) +
(form.totalSelfFunding || 0) +
(form.totalOtherFunding || 0)
// 更新图表
if (budgetChartInstance && hasBudgetData.value) {
renderBudgetChart()
}
}
// 渲染预算图表
const renderBudgetChart = () => {
if (!budgetChartInstance) return
const option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} 万元 ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '资金构成',
type: 'pie',
radius: ['50%', '70%'],
data: [
{
value: form.totalMunicipalFiscal,
name: '市财政资金',
itemStyle: { color: '#409EFF' }
},
{
value: form.totalSelfFunding,
name: '单位自筹',
itemStyle: { color: '#67C23A' }
},
{
value: form.totalOtherFunding,
name: '其他资金',
itemStyle: { color: '#E6A23C' }
}
].filter(item => item.value > 0),
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
budgetChartInstance.setOption(option)
}
// 初始化图表
const initBudgetChart = async () => {
await nextTick()
if (budgetChart.value) {
budgetChartInstance = echarts.init(budgetChart.value)
if (hasBudgetData.value) {
renderBudgetChart()
}
}
}
// 验证绩效指标分值占比总和
const validatePerformanceIndicators = () => {
console.log('=== 校验绩效指标 ===')
// 直接使用绩效指标组件的校验方法
if (performanceIndicatorsRef?.value && typeof performanceIndicatorsRef.value.validate === 'function') {
const validationResult = performanceIndicatorsRef.value.validate()
console.log('绩效指标校验结果:', validationResult)
return validationResult
}
// 回退方案:检查form中的数据
if (!form.performanceIndicators || form.performanceIndicators.length === 0) {
return { valid: false, message: '请至少添加一个绩效指标' }
}
const totalWeight = form.performanceIndicators.reduce((sum, item) => {
return sum + (Number(item.weightPercentage) || 0)
}, 0)
if (Math.abs(totalWeight - 100) > 0.1) {
return {
valid: false,
message: `绩效指标分值占比总和必须等于100%,当前为${totalWeight}%`
}
}
return { valid: true }
}
// 步骤操作
const handleNextStep = async () => {
const formRefs = [basicFormRef, contentFormRef, budgetFormRef, performanceFormRef]
const currentFormRef = formRefs[currentStep.value]
if (currentFormRef?.value) {
try {
await currentFormRef.value.validate()
// 如果是绩效指标步骤(第3步),额外校验分值占比
if (currentStep.value === 3) {
const validationResult = validatePerformanceIndicators()
if (!validationResult.valid) {
ElMessage.error(validationResult.message)
return
}
}
currentStep.value++
// 初始化图表
if (currentStep.value === 2) {
setTimeout(initBudgetChart, 100)
}
} catch (error) {
ElMessage.error('请完善当前步骤的必填信息')
}
} else {
// 如果是绩效指标步骤(第3步),即使没有表单ref也要校验分值占比
if (currentStep.value === 3) {
const validationResult = validatePerformanceIndicators()
if (!validationResult.valid) {
ElMessage.error(validationResult.message)
return
}
}
currentStep.value++
// 初始化图表
if (currentStep.value === 2) {
setTimeout(initBudgetChart, 100)
}
}
}
const handlePrevStep = () => {
currentStep.value--
}
// 处理绩效指标变化
const handlePerformanceIndicatorsChange = (indicators) => {
console.log('=== 绩效指标数据变化 ===')
console.log('接收到的indicators:', indicators)
// 为每个指标添加必要的字段
const processedIndicators = indicators.map((item, index) => ({
...item,
applicationId: form.id || null,
applicationNo: form.applicationNo || '',
sortOrder: index,
status: '1',
// 确保weightPercentage是BigDecimal兼容的数字
weightPercentage: Number(item.weightPercentage) || 0,
// 确保必填字段不为空
goalName: item.goalName || '',
targetValue: item.targetValue || '',
indicatorType: item.indicatorType || '',
indicatorTypeName: item.indicatorTypeName || '',
// 可选字段设置默认值
unit: item.unit || '',
description: item.description || '',
measurementMethod: item.measurementMethod || '',
dataSource: item.dataSource || '',
isQuantitative: item.isQuantitative !== undefined ? item.isQuantitative : true
}))
form.performanceIndicators = processedIndicators
console.log('处理后的绩效指标数据:', form.performanceIndicators)
// 自动生成总绩效目标和当年目标(如果有目标值)
const totalGoals = processedIndicators
.filter(item => item.targetValue && !isNaN(Number(item.targetValue)))
.reduce((sum, item) => sum + Number(item.targetValue), 0)
if (totalGoals > 0) {
form.totalPerformanceGoal = totalGoals
form.currentYearGoal = totalGoals
console.log('自动生成总绩效目标:', form.totalPerformanceGoal)
}
}
// 保存草稿
const handleSaveDraft = async () => {
try {
savingDraft.value = true
// 如果当前在绩效指标步骤(第3步),校验分值占比总和
if (currentStep.value === 3 && form.performanceIndicators && form.performanceIndicators.length > 0) {
const validationResult = validatePerformanceIndicators()
if (!validationResult.valid) {
ElMessage.warning(`保存提醒:${validationResult.message}`)
// 注意:这里只是警告,不阻止保存草稿
}
}
// 详细调试信息
console.log('=== 前端保存草稿调试信息 ===')
console.log('form.performanceIndicators 是否存在:', !!form.performanceIndicators)
console.log('form.performanceIndicators 长度:', form.performanceIndicators ? form.performanceIndicators.length : 'undefined')
console.log('form.performanceIndicators 数据:', form.performanceIndicators)
console.log('完整的form数据:', form)
const result = form.id
? await updateProjectApplication(form as any)
: await saveDraft(form as any)
if (result.code === 200) {
// 如果是新建草稿,获取生成的ID和申报编号
if (!form.id && result.data?.id) {
form.id = result.data.id
form.applicationNo = result.data.applicationNo
console.log('草稿保存成功,获得ID:', form.id, '申报编号:', form.applicationNo)
}
// 绩效指标数据已经作为form的一部分传递给后端,无需单独处理
console.log('绩效指标数据已随草稿数据一起保存,数量:', form.performanceIndicators ? form.performanceIndicators.length : 0)
ElMessage.success('草稿保存成功')
}
} catch (error) {
console.error('保存草稿失败:', error)
ElMessage.error('保存草稿失败')
} finally {
savingDraft.value = false
}
}
// 提交申报
const handleSubmit = async () => {
try {
submitting.value = true
console.log('开始提交申报流程,form.id:', form.id)
// 先保存数据
if (!form.id) {
console.log('新增申报,调用addProjectApplication')
const saveResult = await addProjectApplication(form as any)
console.log('新增申报结果:', saveResult)
if (saveResult.code === 200) {
if (saveResult.data && saveResult.data.id) {
form.id = saveResult.data.id
form.applicationNo = saveResult.data.applicationNo
console.log('新增成功,获得ID:', form.id, '申报编号:', form.applicationNo)
} else {
console.error('新增申报返回的数据异常:', saveResult)
ElMessage.error('保存申报数据失败: 返回数据格式异常')
return
}
} else {
console.error('新增申报失败:', saveResult)
ElMessage.error('保存申报数据失败: ' + (saveResult.msg || '未知错误'))
return
}
} else {
console.log('更新申报,调用updateProjectApplication,ID:', form.id)
const updateResult = await updateProjectApplication(form as any)
console.log('更新申报结果:', updateResult)
if (updateResult.code !== 200) {
console.error('更新申报失败:', updateResult)
ElMessage.error('更新申报数据失败: ' + (updateResult.msg || '未知错误'))
return
}
}
// 绩效指标数据会作为form的一部分自动传递给后端,无需单独保存
console.log('绩效指标数据将随申报数据一起提交,数量:', form.performanceIndicators ? form.performanceIndicators.length : 0)
// 再提交审批
if (!form.id) {
console.error('申报ID为空,无法提交审批')
ElMessage.error('申报ID为空,无法提交审批')
return
}
console.log('开始提交审批,ID:', form.id)
const submitResult = await submitApplication(form.id)
console.log('提交审批结果:', submitResult)
if (submitResult.code === 200) {
ElMessage.success('申报提交成功')
router.push('/cw/application')
} else {
console.error('提交审批失败:', submitResult)
ElMessage.error('提交申报失败: ' + (submitResult.msg || '未知错误'))
}
} catch (error) {
console.error('提交申报失败详细错误:', error)
// 解析错误信息
let errorMessage = '提交申报失败'
if (error?.response?.data?.msg) {
errorMessage += ': ' + error.response.data.msg
} else if (error?.message) {
errorMessage += ': ' + error.message
} else if (typeof error === 'string') {
errorMessage += ': ' + error
}
console.error('最终错误信息:', errorMessage)
ElMessage.error(errorMessage)
} finally {
submitting.value = false
}
}
// 取消操作
const handleCancel = () => {
ElMessageBox.confirm('确认取消吗?未保存的数据将丢失。', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
router.push('/cw/application')
})
}
// 加载数据
const loadData = async () => {
const id = route.params.id as string
if (id && id !== 'add') {
try {
console.log('开始加载申报数据,ID:', id)
const response = await getProjectApplication(id)
if (response.code === 200) {
console.log('申报基础数据加载成功:', response.data)
Object.assign(form, response.data)
// 检查是否有绩效指标数据
if (response.data.performanceIndicators && response.data.performanceIndicators.length > 0) {
console.log('发现绩效指标数据,数量:', response.data.performanceIndicators.length)
form.performanceIndicators = response.data.performanceIndicators
console.log('绩效指标数据已加载到form.performanceIndicators:', form.performanceIndicators)
} else {
console.log('没有绩效指标数据')
form.performanceIndicators = []
}
}
} catch (error) {
console.error('加载数据失败:', error)
ElMessage.error('加载数据失败')
}
}
}
// 暴露给父组件的方法
const validate = (callback: (valid: boolean) => void) => {
// 简单的验证逻辑,检查必填字段
const isValid = !!(form.projectName && form.principal && form.totalInvestment > 0)
callback(isValid)
}
// 暴露方法给父组件
defineExpose({
validate
})
// 组件挂载
onMounted(() => {
loadData()
})
</script>
<style lang="scss" scoped>
.page-container {
min-height: calc(100vh - 84px);
}
// 页面头部
.header-card {
border-radius: 8px;
border: 1px solid #e4e7ed;
margin-bottom: 10px;
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
.header-info {
.page-title {
margin: 0 0 8px 0;
font-size: 20px;
font-weight: 600;
color: #2c3e50;
display: flex;
align-items: center;
gap: 8px;
}
.page-desc {
margin: 0;
color: #909399;
font-size: 14px;
}
}
.header-actions {
display: flex;
gap: 12px;
}
}
}
// 步骤卡片
.steps-card {
border-radius: 8px;
border: 1px solid #e4e7ed;
:deep(.el-steps) {
.el-step__title {
font-weight: 600;
}
}
}
// 表单卡片
.form-card {
border-radius: 8px;
border: 1px solid #e4e7ed;
margin-bottom: 10px;
.card-header {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
color: #2c3e50;
}
// 表单项样式
:deep(.el-form-item) {
margin-bottom: 24px;
.el-form-item__label {
font-weight: 600;
color: #2c3e50;
margin-bottom: 8px;
}
}
// 特征选项
.feature-section {
margin-top: 24px;
padding-top: 24px;
border-top: 1px solid #f0f0f0;
.section-title {
margin: 0 0 16px 0;
font-size: 16px;
font-weight: 600;
color: #2c3e50;
}
.feature-item {
text-align: center;
padding: 16px;
border: 1px solid #e4e7ed;
border-radius: 6px;
background: #fafafa;
:deep(.el-switch) {
.el-switch__label {
font-weight: 500;
}
}
}
}
// 预算部分
.budget-section {
margin-bottom: 32px;
padding: 20px;
background: #fafbfc;
border-radius: 6px;
border: 1px solid #e1e8ed;
.section-title {
margin: 0 0 20px 0;
font-size: 16px;
font-weight: 600;
color: #2c3e50;
display: flex;
align-items: center;
gap: 8px;
}
}
.budget-chart {
margin-top: 24px;
padding: 20px;
background: white;
border-radius: 6px;
border: 1px solid #e4e7ed;
.section-title {
margin: 0 0 16px 0;
font-size: 16px;
font-weight: 600;
color: #2c3e50;
}
}
// 绩效指标部分
.performance-section {
:deep(.el-tabs) {
.el-tabs__header {
margin-bottom: 20px;
}
.el-tab-pane {
padding: 0;
}
}
}
// 确认信息
.confirmation-content {
.confirmation-section {
margin-bottom: 24px;
h4 {
margin: 0 0 16px 0;
font-size: 16px;
font-weight: 600;
color: #2c3e50;
}
}
.confirmation-actions {
margin-top: 24px;
}
}
}
// 底部操作
.footer-card {
border-radius: 8px;
border: 1px solid #e4e7ed;
.footer-actions {
display: flex;
justify-content: space-between;
align-items: center;
.action-group {
display: flex;
gap: 12px;
}
}
}
// 响应式设计
@media (max-width: 768px) {
.header-content {
flex-direction: column;
align-items: flex-start;
gap: 16px;
}
.footer-actions {
flex-direction: column;
gap: 16px;
.action-group {
width: 100%;
justify-content: center;
}
}
}
</style>