功能概述
项目资金计划表组件是一个基于 Vue 3 和 Element Plus 的表格组件,用于展示和管理项目的资金计划。该组件支持多个项目的资金计划展示,包括各类款项和月度资金分配的详细信息。
主要特性
-
项目信息展示
- 项目基本信息(名称、装机容量、开工/竣工日期)
- 固定左侧关键信息列
- 合并相同项目的信息单元格
-
资金计划管理
- 显示合同金额、变更金额、审定金额
- 自动计算项目小计
- 自动汇总所有项目总计
-
月度计划展示
- 按月展示资金使用计划
- 支持跨年度计划(2025-2026年)
- 自动计算月度汇总数据
技术实现
1. 数据结构
项目选择接口
interface Project {
value: string // 项目的唯一标识值
label: string // 项目的显示名称
}
表格行数据接口
interface TableRowData {
index: number // 项目序号
projectName: string // 项目名称
capacity: string // 装机容量(kwp)
startDate: string // 开工日期
endDate: string // 竣工日期
paymentType: string // 款项类型(设计、EPC、组件等)
contractAmount: string // 合同金额
changeAmount: string // 变更金额
approvedAmount: string // 审定金额
[key: string]: string | number // 动态属性,用于存储月度计划金额
}
小计数据接口
interface SubtotalData {
contractAmount: number // 合同金额小计
changeAmount: number // 变更金额小计
approvedAmount: number // 审定金额小计
[key: string]: number // 动态属性,用于存储月度计划金额小计
}
2. 核心功能实现
2.1 单元格合并处理
/**
* 处理单元格合并
* @param {object} param0 - 合并参数对象
* @param {number} param0.rowIndex - 当前行的索引,用于计算是否需要合并行
* @param {number} param0.columnIndex - 当前列的索引,用于判断是否是需要合并的列
* @returns {object | undefined} 返回合并配置对象或undefined
*/
function objectSpanMethod({ rowIndex, columnIndex }: SpanMethodProps) {
if (columnIndex < 5) { // 序号、项目名称、装机容量、开工日期、竣工日期需要合并
if (rowIndex % 6 === 0) {
return {
rowspan: 6,
colspan: 1,
}
}
return {
rowspan: 0,
colspan: 0,
}
}
return undefined
}
2.2 小计计算
function calculateSubtotal(projectData: TableRowData[]): SubtotalData {
const subtotal: SubtotalData = {
contractAmount: 0,
changeAmount: 0,
approvedAmount: 0,
}
projectData.forEach((row) => {
if (row.paymentType !== '小计') {
// 累加基本金额
subtotal.contractAmount += Number(row.contractAmount) || 0
subtotal.changeAmount += Number(row.changeAmount) || 0
subtotal.approvedAmount += Number(row.approvedAmount) || 0
// 计算月度金额
for (let month = 1; month <= 12; month++) {
const monthKey = `month2025${month}`
subtotal[monthKey] = (subtotal[monthKey] || 0) + (Number(row[monthKey]) || 0)
}
for (let month = 1; month <= 3; month++) {
const monthKey = `month2026${month}`
subtotal[monthKey] = (subtotal[monthKey] || 0) + (Number(row[monthKey]) || 0)
}
}
})
return subtotal
}
3. 组件布局
<template>
<div class="project-funding-plan">
<!-- 操作区域 -->
<div class="header-actions">
<el-select v-model="selectedProject" placeholder="请选择项目">
<el-option
v-for="item in projects"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-button type="primary" @click="handleQuery">
查询
</el-button>
<el-button type="success" @click="handleExport">
导出
</el-button>
</div>
<!-- 表格区域 -->
<el-table
:data="[...tableData, totalRow]"
border
style="width: 100%;"
:span-method="objectSpanMethod"
:fixed="true"
>
<!-- 基本信息列 -->
<el-table-column label="序号" width="60" align="center" fixed="left">
<template #default="scope">
{{ scope.row.index }}
</template>
</el-table-column>
<!-- 其他列配置... -->
</el-table>
</div>
</template>
4. 样式设置
.project-funding-plan {
padding: 20px;
.header-actions {
margin-bottom: 20px;
display: flex;
gap: 10px;
}
}
:deep(.el-table__fixed) {
height: 100% !important;
}
:deep(.el-table__fixed-right) {
right: 0;
height: 100% !important;
}
:deep(.el-table .fixed-right-patch) {
background-color: #fff;
}
使用示例
基本使用
<template>
<project-funding-plan />
</template>
<script setup lang="ts">
import ProjectFundingPlan from './components/ProjectFundingPlan.vue'
</script>
数据格式示例
// 项目数据示例
const projects = [
{ value: '1', label: '光伏发电项目A' },
{ value: '2', label: '风电项目B' },
]
// 表格行数据示例
const tableData = [
{
index: 1,
projectName: '光伏发电项目A',
capacity: '100000',
startDate: '2025-03-01',
endDate: '2025-12-31',
paymentType: '设计',
contractAmount: '2500000',
changeAmount: '150000',
approvedAmount: '2650000',
month20251: '200000',
// ... 其他月度数据
},
// ... 其他行数据
]
注意事项
-
数据格式要求
- 金额类数据必须为字符串类型
- 日期格式为 'YYYY-MM-DD'
- 装机容量单位为 kwp
-
性能考虑
- 大量数据时注意表格渲染性能
- 合并单元格可能影响滚动性能
-
样式调整
- 固定列宽度需要合理设置
- 注意表格整体宽度的控制
后续优化建议
-
功能增强
- 添加数据导入功能
- 支持更多的数据筛选条件
- 添加数据编辑功能
-
性能优化
- 实现虚拟滚动
- 优化大数据量渲染
-
交互优化
- 添加更多的数据可视化图表
- 优化移动端适配