import * as echarts from 'echarts' import { getAuditTaskList } from '@/api/auditInitiation.js' import { getAllUnitList } from '@/api/auditEntityManage.js' import { analyzeStatistics } from '@/api/comprehensive' // 综合分析页面的通用mixin export const comprehensiveMixin = { data() { return { // 通用加载状态 loading: false, projectOptions: [], auditedUnitOptions: [], // 指标树基础配置 treeProps: { children: 'children', label: 'label', }, // 图表实例集合 chartInstances: {}, // 组件是否已销毁标志 isDestroyed: false, } }, mounted() { this.getOptions() // 监听窗口大小变化 window.addEventListener('resize', this.handleResize) }, beforeDestroy() { // 标记组件已销毁 this.isDestroyed = true // 销毁所有图表实例 this.destroyCharts() // 移除窗口大小变化监听 window.removeEventListener('resize', this.handleResize) }, methods: { // 根据索引获取颜色 getColorByIndex(index) { const colors = [ '#5470C6', // 蓝色 '#91CC75', // 绿色 '#FAC858', // 黄色 '#EE6666', // 红色 '#73C0DE', // 浅蓝色 '#3BA272', // 深绿色 '#FC8452', // 橙色 '#9A60B4', // 紫色 ] return colors[index % colors.length] }, // 将 costSurveysList 组装为树结构(用于左侧勾选) buildIndicatorTree(costSurveysList = []) { const processNode = (item) => { const node = { ...item, label: this.buildIndicatorLabel(item), children: [], } // 如果有子项,递归处理 if (Array.isArray(item.costSurveysVos) && item.costSurveysVos.length) { node.children = item.costSurveysVos.map(processNode) } return node } return costSurveysList.map(processNode) }, // label 规则:parentId 为 -1 时,用 “number、name”,否则 “number.name” buildIndicatorLabel(item) { const num = item.number || '' const nm = item.name || '' if (!num) return nm const isRoot = !item.parentId || item.parentId === '-1' return isRoot ? `${num}、${nm}` : `${num}.${nm}` }, // 获取树的叶子 id 列表 getLeafIds(tree = []) { const ids = [] const dfs = (node) => { if (!node.children || node.children.length === 0) { ids.push(node.id) } else { node.children.forEach(dfs) } } tree.forEach(dfs) return ids }, // 获取树的父级(拥有子节点)id 列表和节点列表 getParentIds(tree = []) { const ids = [] const items = [] const dfs = (node) => { if (node.parentId == '-1') { ids.push(node.id) items.push(node) node.children.forEach(dfs) } } tree.forEach(dfs) return { ids, items } }, // 去重成本列表:同级内去重,优先按 id,其次 rowId/rowid,再按 parentId+number+name dedupeCostSurveysList(list = []) { const dedupeLevel = (arr = []) => { const seenIds = new Set() const seenRowIds = new Set() const seenCombo = new Set() const result = [] for (const node of arr || []) { if (!node) continue const normId = node.id !== undefined && node.id !== null ? String(node.id).trim() : '' const normRowId = node.rowId !== undefined && node.rowId !== null ? String(node.rowId).trim() : node.rowid !== undefined && node.rowid !== null ? String(node.rowid).trim() : '' const normParent = node.parentId !== undefined && node.parentId !== null ? String(node.parentId).trim() : '' const normNumber = node.number !== undefined && node.number !== null ? String(node.number).trim() : '' const normName = node.name !== undefined && node.name !== null ? String(node.name).trim() : '' const comboKey = `p:${normParent}|num:${normNumber}|name:${normName}` // 先用 id 去重 if (normId && seenIds.has(normId)) { continue } // 其次用 rowId/rowid 去重 if (!normId && normRowId && seenRowIds.has(normRowId)) { continue } // 再用组合字段去重(处理不同 id 但显示相同的重复) if (!normId && !normRowId && seenCombo.has(comboKey)) { continue } if (normId) { seenIds.add(normId) } else if (normRowId) { seenRowIds.add(normRowId) } else { seenCombo.add(comboKey) } const next = { ...node, id: normId || node.id, rowId: normRowId || node.rowId || node.rowid, parentId: normParent || node.parentId, number: normNumber || node.number, name: normName || node.name, } if ( Array.isArray(node.costSurveysVos) && node.costSurveysVos.length > 0 ) { next.costSurveysVos = dedupeLevel(node.costSurveysVos) } result.push(next) } return result } return dedupeLevel(list) }, // 统一请求统计数据(接口失败或无数据时使用mock) async requestStatistics(params = {}) { // 如果组件已销毁,直接返回 mock 数据 if (this.isDestroyed) { return mockStatisticsData } try { const res = await analyzeStatistics(params) // 再次检查组件是否已销毁 if (this.isDestroyed) { return mockStatisticsData } if (res && res.value) return res.value } catch (e) { // 如果是请求中止错误,静默处理 if (e && e.message && e.message.includes('aborted')) { return mockStatisticsData } // 其他错误才打印警告 if (!this.isDestroyed) { console.warn('analyzeStatistics 调用失败,使用 mock 数据', e) } } return mockStatisticsData }, getOptions() { // 获取监审任务列表 getAuditTaskList() .then((res) => { if (!this.isDestroyed && res && res.value) { this.projectOptions = res.value } }) .catch((e) => { // 如果是请求中止错误,静默处理 if (e && e.message && !e.message.includes('aborted')) { console.warn('获取项目列表失败', e) } }) getAllUnitList() .then((res) => { if (!this.isDestroyed && res && res.value) { this.auditedUnitOptions = res.value } }) .catch((e) => { // 如果是请求中止错误,静默处理 if (e && e.message && !e.message.includes('aborted')) { console.warn('获取单位列表失败', e) } }) }, // 根据选中的指标 ID 过滤 costSurveysList filterCostSurveysListBySelectedIds(costSurveysList = [], selectedIds = []) { if (!selectedIds || selectedIds.length === 0) { return [] } const selectedIdSet = new Set(selectedIds) // 递归过滤节点 const filterNode = (node) => { if (!node) return null // 如果当前节点被选中,保留它及其所有子节点 if (selectedIdSet.has(node.id)) { const filteredNode = { ...node } if ( Array.isArray(node.costSurveysVos) && node.costSurveysVos.length ) { // 如果父节点被选中,保留所有子节点 filteredNode.costSurveysVos = node.costSurveysVos.map((child) => ({ ...child, })) } return filteredNode } // 如果当前节点未被选中,检查是否有子节点被选中 if (Array.isArray(node.costSurveysVos) && node.costSurveysVos.length) { const filteredChildren = node.costSurveysVos .map(filterNode) .filter(Boolean) if (filteredChildren.length > 0) { // 如果有子节点被选中,保留父节点和选中的子节点 return { ...node, costSurveysVos: filteredChildren, } } } return null } return costSurveysList.map(filterNode).filter(Boolean) }, // 将 costSurveysList 展平为趋势数据 [{indicatorName, year, value}] // 规则:只展示选中节点对应的年度数据(surveysVos),不追加“合计年”;若无则递归子节点 transformTrendFromCostList(costSurveysList = []) { const trendArr = [] const dfs = (node) => { if (!node) return if (Array.isArray(node.surveysVos) && node.surveysVos.length) { node.surveysVos.forEach((sv) => { const yearKey = String(sv.name || sv.year || '').trim() if (!yearKey) return trendArr.push({ indicatorName: node.name, year: yearKey, value: Number(sv.value) || 0, }) }) } if (Array.isArray(node.costSurveysVos) && node.costSurveysVos.length) { node.costSurveysVos.forEach(dfs) } } costSurveysList.forEach(dfs) return trendArr }, // 将 costSurveysList 汇总为构成数据 [{name, value}](叶子求和) transformCompositionFromCostList(costSurveysList = []) { const result = [] const dfs = (node) => { if (!node) return if (Array.isArray(node.costSurveysVos) && node.costSurveysVos.length) { node.costSurveysVos.forEach(dfs) } else { const total = Array.isArray(node.surveysVos) ? node.surveysVos.reduce( (sum, sv) => sum + (Number(sv.value) || 0), 0 ) : 0 result.push({ name: node.name, value: total, }) } } costSurveysList.forEach(dfs) return result }, // 构建趋势图数据结构(xAxis + series) buildTrendSeries(trendArr = []) { const years = [ ...new Set( trendArr .map((item) => String(item.year || item.name || '').replace('年', '') ) .filter(Boolean) ), ] .sort() .map((y) => `${y}年`) const indicatorMap = {} trendArr.forEach((item) => { const yearKey = String(item.year || item.name || '').replace('年', '') if (!yearKey) return if (!indicatorMap[item.indicatorName]) { indicatorMap[item.indicatorName] = { name: item.indicatorName, data: {}, color: this.getColorByIndex(Object.keys(indicatorMap).length), } } indicatorMap[item.indicatorName].data[yearKey] = Number(item.value) || 0 }) const series = Object.values(indicatorMap).map((indicator) => ({ name: indicator.name, data: years.map((y) => { const key = y.replace('年', '') return indicator.data[key] || 0 }), color: indicator.color, })) return { xAxis: years, series } }, // 初始化图表 initChart(chartId, containerId) { const chartDom = document.getElementById(containerId) if (chartDom) { this.chartInstances[chartId] = echarts.init(chartDom) return this.chartInstances[chartId] } return null }, // 销毁指定图表实例 destroyChart(chartId) { if (this.chartInstances[chartId]) { this.chartInstances[chartId].dispose() delete this.chartInstances[chartId] } }, // 销毁所有图表实例 destroyCharts() { Object.keys(this.chartInstances).forEach((chartId) => { this.destroyChart(chartId) }) }, // 处理窗口大小变化 handleResize() { // 调整所有图表大小 Object.values(this.chartInstances).forEach((chart) => { if (chart) { chart.resize() } }) }, // 更新图表数据 updateChart(chartId, option) { if (this.chartInstances[chartId]) { this.chartInstances[chartId].setOption(option) this.$nextTick(() => { this.chartInstances[chartId].resize() }) } }, // 获取趋势图表基础配置 getBaseTrendChartOption( seriesData = [], xAxisData = ['2022年', '2023年', '2024年'] ) { return { tooltip: { trigger: 'axis', axisPointer: { type: 'cross', }, }, legend: { show: true, data: seriesData.map((item) => item.name), bottom: 0, left: 'center', itemGap: 20, textStyle: { fontSize: 12, color: '#333', }, }, grid: { left: '3%', right: '4%', bottom: '15%', top: '10%', containLabel: true, }, xAxis: { type: 'category', boundaryGap: false, data: xAxisData, show: true, axisLine: { show: true, lineStyle: { color: '#333', }, }, axisTick: { show: true, }, axisLabel: { show: true, fontSize: 12, color: '#333', }, }, yAxis: { type: 'value', show: true, axisLine: { show: true, lineStyle: { color: '#333', }, }, axisTick: { show: false, }, axisLabel: { show: true, fontSize: 12, color: '#333', }, splitLine: { show: true, lineStyle: { type: 'dashed', color: '#e0e0e0', }, }, }, series: seriesData.map((item) => ({ name: item.name, type: 'line', data: item.data, symbol: 'circle', symbolSize: 8, smooth: false, lineStyle: { width: 2, color: item.color || '#37A2DA', }, itemStyle: { color: item.color || '#37A2DA', }, emphasis: { focus: 'series', }, })), } }, // 获取构成图表基础配置(historyAnalysis.vue 使用) getBaseCompositionChartOption(data = []) { return { tooltip: { show: true, trigger: 'item', formatter: (p) => `${p.name}: ${p.value} (${p.percent}%)`, }, legend: { show: true, orient: 'vertical', right: 10, top: 'center', data: data.map((item) => item.name), formatter: function (name) { return name }, itemGap: 10, textStyle: { fontSize: 12, color: '#333', }, itemWidth: 14, itemHeight: 14, }, series: [ { name: '成本构成', type: 'pie', radius: '60%', center: ['35%', '50%'], avoidLabelOverlap: true, itemStyle: { borderRadius: 0, borderColor: '#fff', borderWidth: 1, }, label: { show: true, position: 'outside', formatter: '{b}', fontSize: 12, color: '#333', }, labelLine: { show: true, length: 10, length2: 5, lineStyle: { width: 1, color: 'auto', // 线条跟随扇区颜色 }, }, emphasis: { label: { show: true, fontSize: 12, fontWeight: 'normal', }, itemStyle: { shadowBlur: 0, shadowOffsetX: 0, shadowColor: 'transparent', }, labelLine: { lineStyle: { color: 'auto', }, }, }, data: data, }, ], } }, // 获取构成图表基础配置(industryAnalysis.vue 使用) getIndustryCompositionChartOption(data = []) { const colorPalette = [ '#5470C6', // 蓝色 - 基本工资 '#73C0DE', // 青色/蓝绿色 - 津贴 '#91CC75', // 绿色 - 奖金 '#FAC858', // 黄色 - 福利费 '#FF85C0', // 粉色 - 其他人员支出 '#EE6666', // 红色 '#3BA272', // 深绿色 '#FC8452', // 橙色 '#9A60B4', // 紫色 '#E71D36', // 深红 ] return { color: colorPalette, tooltip: { show: true, trigger: 'item', formatter: (p) => `${p.name}: ${p.value} (${p.percent}%)`, }, legend: { show: true, orient: 'horizontal', bottom: 10, left: 'center', data: data.map((item) => item.name), icon: 'circle', itemGap: 20, textStyle: { fontSize: 12, color: '#333', }, itemWidth: 10, itemHeight: 10, }, series: [ { name: '成本构成', type: 'pie', radius: ['40%', '60%'], // 环形图 center: ['50%', '45%'], avoidLabelOverlap: true, silent: false, itemStyle: { borderRadius: 0, borderColor: '#fff', borderWidth: 1, }, label: { show: true, position: 'outside', formatter: '{b}: {d}%', // 名称: 百分比 fontSize: 12, color: '#333', }, labelLine: { show: true, length: 10, length2: 5, lineStyle: { width: 1, color: 'auto', // 线条跟随扇区颜色 }, }, emphasis: { label: { show: true, fontSize: 12, fontWeight: 'normal', }, itemStyle: { shadowBlur: 0, shadowOffsetX: 0, shadowColor: 'transparent', }, labelLine: { lineStyle: { color: 'auto', }, }, }, data: data, }, ], } }, // 轮播功能基础配置(仅historyAnalysis.vue使用) initCarousel(chartId, totalPages = 1, onPageChange) { // 若已有轮播,先清理旧定时器,避免重复计时导致数据持续跳动 if (this.carouselConfigs && this.carouselConfigs[chartId]) { this.pauseCarousel(chartId) } const carouselConfig = { totalPages, currentPage: 0, timer: null, interval: 5000, onPageChange, } // 保存轮播配置 this.carouselConfigs = this.carouselConfigs || {} this.carouselConfigs[chartId] = carouselConfig // 启动轮播 if (totalPages > 1) { this.startCarousel(chartId) } else { // 单页不需要轮播,但仍确保跳转到第一页 this.goToCarouselPage(chartId, 0) } }, // 启动轮播 startCarousel(chartId) { const config = this.carouselConfigs?.[chartId] if (!config) return // 清除现有定时器 this.pauseCarousel(chartId) // 设置新定时器 config.timer = setInterval(() => { config.currentPage = (config.currentPage + 1) % config.totalPages this.goToCarouselPage(chartId, config.currentPage) }, config.interval) }, // 暂停轮播 pauseCarousel(chartId) { const config = this.carouselConfigs?.[chartId] if (config?.timer) { clearInterval(config.timer) config.timer = null } }, // 恢复轮播 resumeCarousel(chartId) { this.startCarousel(chartId) }, // 跳转到指定轮播页 goToCarouselPage(chartId, pageIndex) { const config = this.carouselConfigs?.[chartId] if (!config) return config.currentPage = pageIndex if (typeof config.onPageChange === 'function') { config.onPageChange(pageIndex) } }, }, } // mock 数据 export const mockStatisticsData = { costSurveysList: [ { id: '1997964654884069376', name: '人数', orderNum: '1', rowid: 'ce2c23fd-0a60-4d98-a27e-d5344c7f2f7b', number: '一', rvalue: '2', taskId: '1995015537499938816', nianfen: null, parentId: '-1', surveysVos: [ { name: '2024', value: '30' }, { name: '2025', value: '35' }, ], costSurveysVos: [ { id: '1997964655014092800', name: '1班', orderNum: '2', rowid: '0a075d08-1805-4ce0-a5e1-c4f264db76bd', number: '1', rvalue: '4', taskId: '1995015537499938816', nianfen: null, parentId: 'ce2c23fd-0a60-4d98-a27e-d5344c7f2f7b', surveysVos: [ { name: '2024', value: '12' }, { name: '2025', value: '15' }, ], costSurveysVos: null, }, { id: '1997964655131533312', name: '2班', orderNum: '3', rowid: 'ab3efd32-9a10-4355-8d6e-19d99ebdbe4a', number: '2', rvalue: '7', taskId: '1995015537499938816', nianfen: null, parentId: 'ce2c23fd-0a60-4d98-a27e-d5344c7f2f7b', surveysVos: [ { name: '2024', value: '18' }, { name: '2025', value: '20' }, ], costSurveysVos: null, }, ], }, { id: '1997964655244779520', name: '1班费用', orderNum: '4', rowid: '6a81c1d3-ea8b-48d5-bd11-27e5b150cea1', number: '二', rvalue: '53', taskId: '1995015537499938816', nianfen: null, parentId: '-1', surveysVos: [ { name: '2024', value: '120' }, { name: '2025', value: '140' }, ], costSurveysVos: [ { id: '1997964655387385856', name: '押金', orderNum: '5', rowid: 'bf17169e-9d03-49f0-b7c7-7502879a935b', number: '1', rvalue: '124', taskId: '1995015537499938816', nianfen: null, parentId: '6a81c1d3-ea8b-48d5-bd11-27e5b150cea1', surveysVos: [ { name: '2024', value: '50' }, { name: '2025', value: '60' }, ], costSurveysVos: null, }, { id: '1997964655559352320', name: '缴纳', orderNum: '6', rowid: 'e130564b-dc73-4fa9-a004-01c3af418021', number: '2', rvalue: '146', taskId: '1995015537499938816', nianfen: null, parentId: '6a81c1d3-ea8b-48d5-bd11-27e5b150cea1', surveysVos: [ { name: '2024', value: '70' }, { name: '2025', value: '80' }, ], costSurveysVos: null, }, ], }, { id: '1997964655680987136', name: '班级乘法', orderNum: '7', rowid: 'aec785e0-86fa-436e-be7b-bb9d2d9eaf32', number: '三', rvalue: '246', taskId: '1995015537499938816', nianfen: null, parentId: '-1', surveysVos: [ { name: '2024', value: '300' }, { name: '2025', value: '320' }, ], costSurveysVos: [], }, { id: '1997964655794233344', name: '人均费用', orderNum: '8', rowid: '857ba697-aaf0-4e26-97a6-4bd97d8ff6f7', number: '四', rvalue: '246', taskId: '1995015537499938816', nianfen: null, parentId: '-1', surveysVos: [ { name: '2024', value: '15' }, { name: '2025', value: '16' }, ], costSurveysVos: [], }, { id: '1997964655903279104', name: '材料成本', orderNum: '9', rowid: 'f3a8b2c1-5d6e-4f7a-8b9c-0d1e2f3a4b5c', number: '五', rvalue: '580', taskId: '1995015537499938816', nianfen: null, parentId: '-1', surveysVos: [ { name: '2022', value: '450' }, { name: '2023', value: '520' }, { name: '2024', value: '580' }, { name: '2025', value: '620' }, ], costSurveysVos: [ { id: '1997964656012324864', name: '原材料', orderNum: '10', rowid: 'a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d', number: '1', rvalue: '320', taskId: '1995015537499938816', nianfen: null, parentId: 'f3a8b2c1-5d6e-4f7a-8b9c-0d1e2f3a4b5c', surveysVos: [ { name: '2022', value: '250' }, { name: '2023', value: '290' }, { name: '2024', value: '320' }, { name: '2025', value: '350' }, ], costSurveysVos: null, }, { id: '1997964656121370624', name: '辅助材料', orderNum: '11', rowid: 'b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e', number: '2', rvalue: '180', taskId: '1995015537499938816', nianfen: null, parentId: 'f3a8b2c1-5d6e-4f7a-8b9c-0d1e2f3a4b5c', surveysVos: [ { name: '2022', value: '140' }, { name: '2023', value: '160' }, { name: '2024', value: '180' }, { name: '2025', value: '200' }, ], costSurveysVos: null, }, { id: '1997964656230416384', name: '包装材料', orderNum: '12', rowid: 'c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f', number: '3', rvalue: '80', taskId: '1995015537499938816', nianfen: null, parentId: 'f3a8b2c1-5d6e-4f7a-8b9c-0d1e2f3a4b5c', surveysVos: [ { name: '2022', value: '60' }, { name: '2023', value: '70' }, { name: '2024', value: '80' }, { name: '2025', value: '70' }, ], costSurveysVos: null, }, ], }, { id: '1997964656339462144', name: '人工成本', orderNum: '13', rowid: 'd4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f8a', number: '六', rvalue: '850', taskId: '1995015537499938816', nianfen: null, parentId: '-1', surveysVos: [ { name: '2022', value: '680' }, { name: '2023', value: '750' }, { name: '2024', value: '850' }, { name: '2025', value: '920' }, ], costSurveysVos: [ { id: '1997964656448507904', name: '基本工资', orderNum: '14', rowid: 'e5f6a7b8-c9d0-4e1f-2a3b-4c5d6e7f8a9b', number: '1', rvalue: '520', taskId: '1995015537499938816', nianfen: null, parentId: 'd4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f8a', surveysVos: [ { name: '2022', value: '420' }, { name: '2023', value: '460' }, { name: '2024', value: '520' }, { name: '2025', value: '580' }, ], costSurveysVos: null, }, { id: '1997964656557553664', name: '绩效奖金', orderNum: '15', rowid: 'f6a7b8c9-d0e1-4f2a-3b4c-5d6e7f8a9b0c', number: '2', rvalue: '200', taskId: '1995015537499938816', nianfen: null, parentId: 'd4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f8a', surveysVos: [ { name: '2022', value: '150' }, { name: '2023', value: '180' }, { name: '2024', value: '200' }, { name: '2025', value: '220' }, ], costSurveysVos: null, }, { id: '1997964656666599424', name: '社保公积金', orderNum: '16', rowid: 'a7b8c9d0-e1f2-4a3b-4c5d-6e7f8a9b0c1d', number: '3', rvalue: '130', taskId: '1995015537499938816', nianfen: null, parentId: 'd4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f8a', surveysVos: [ { name: '2022', value: '110' }, { name: '2023', value: '120' }, { name: '2024', value: '130' }, { name: '2025', value: '120' }, ], costSurveysVos: null, }, ], }, { id: '1997964656775645184', name: '设备成本', orderNum: '17', rowid: 'b8c9d0e1-f2a3-4b4c-5d6e-7f8a9b0c1d2e', number: '七', rvalue: '420', taskId: '1995015537499938816', nianfen: null, parentId: '-1', surveysVos: [ { name: '2022', value: '380' }, { name: '2023', value: '400' }, { name: '2024', value: '420' }, { name: '2025', value: '450' }, ], costSurveysVos: [ { id: '1997964656884690944', name: '设备折旧', orderNum: '18', rowid: 'c9d0e1f2-a3b4-4c5d-6e7f-8a9b0c1d2e3f', number: '1', rvalue: '280', taskId: '1995015537499938816', nianfen: null, parentId: 'b8c9d0e1-f2a3-4b4c-5d6e-7f8a9b0c1d2e', surveysVos: [ { name: '2022', value: '260' }, { name: '2023', value: '270' }, { name: '2024', value: '280' }, { name: '2025', value: '300' }, ], costSurveysVos: null, }, { id: '1997964656993736704', name: '设备维护', orderNum: '19', rowid: 'd0e1f2a3-b4c5-4d6e-7f8a-9b0c1d2e3f4a', number: '2', rvalue: '90', taskId: '1995015537499938816', nianfen: null, parentId: 'b8c9d0e1-f2a3-4b4c-5d6e-7f8a9b0c1d2e', surveysVos: [ { name: '2022', value: '80' }, { name: '2023', value: '85' }, { name: '2024', value: '90' }, { name: '2025', value: '100' }, ], costSurveysVos: null, }, { id: '1997964657102782464', name: '设备租赁', orderNum: '20', rowid: 'e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b', number: '3', rvalue: '50', taskId: '1995015537499938816', nianfen: null, parentId: 'b8c9d0e1-f2a3-4b4c-5d6e-7f8a9b0c1d2e', surveysVos: [ { name: '2022', value: '40' }, { name: '2023', value: '45' }, { name: '2024', value: '50' }, { name: '2025', value: '50' }, ], costSurveysVos: null, }, ], }, { id: '1997964657211828224', name: '管理费用', orderNum: '21', rowid: 'f2a3b4c5-d6e7-4f8a-9b0c-1d2e3f4a5b6c', number: '八', rvalue: '360', taskId: '1995015537499938816', nianfen: null, parentId: '-1', surveysVos: [ { name: '2022', value: '320' }, { name: '2023', value: '340' }, { name: '2024', value: '360' }, { name: '2025', value: '380' }, ], costSurveysVos: [ { id: '1997964657320873984', name: '办公费用', orderNum: '22', rowid: 'a3b4c5d6-e7f8-4a9b-0c1d-2e3f4a5b6c7d', number: '1', rvalue: '150', taskId: '1995015537499938816', nianfen: null, parentId: 'f2a3b4c5-d6e7-4f8a-9b0c-1d2e3f4a5b6c', surveysVos: [ { name: '2022', value: '130' }, { name: '2023', value: '140' }, { name: '2024', value: '150' }, { name: '2025', value: '160' }, ], costSurveysVos: null, }, { id: '1997964657429919744', name: '差旅费用', orderNum: '23', rowid: 'b4c5d6e7-f8a9-4b0c-1d2e-3f4a5b6c7d8e', number: '2', rvalue: '120', taskId: '1995015537499938816', nianfen: null, parentId: 'f2a3b4c5-d6e7-4f8a-9b0c-1d2e3f4a5b6c', surveysVos: [ { name: '2022', value: '110' }, { name: '2023', value: '115' }, { name: '2024', value: '120' }, { name: '2025', value: '130' }, ], costSurveysVos: null, }, { id: '1997964657538965504', name: '培训费用', orderNum: '24', rowid: 'c5d6e7f8-a9b0-4c1d-2e3f-4a5b6c7d8e9f', number: '3', rvalue: '90', taskId: '1995015537499938816', nianfen: null, parentId: 'f2a3b4c5-d6e7-4f8a-9b0c-1d2e3f4a5b6c', surveysVos: [ { name: '2022', value: '80' }, { name: '2023', value: '85' }, { name: '2024', value: '90' }, { name: '2025', value: '90' }, ], costSurveysVos: null, }, ], }, { id: '1997964657648011264', name: '能源成本', orderNum: '25', rowid: 'd6e7f8a9-b0c1-4d2e-3f4a-5b6c7d8e9f0a', number: '九', rvalue: '280', taskId: '1995015537499938816', nianfen: null, parentId: '-1', surveysVos: [ { name: '2022', value: '250' }, { name: '2023', value: '270' }, { name: '2024', value: '280' }, { name: '2025', value: '290' }, ], costSurveysVos: [ { id: '1997964657757057024', name: '电费', orderNum: '26', rowid: 'e7f8a9b0-c1d2-4e3f-4a5b-6c7d8e9f0a1b', number: '1', rvalue: '180', taskId: '1995015537499938816', nianfen: null, parentId: 'd6e7f8a9-b0c1-4d2e-3f4a-5b6c7d8e9f0a', surveysVos: [ { name: '2022', value: '160' }, { name: '2023', value: '170' }, { name: '2024', value: '180' }, { name: '2025', value: '190' }, ], costSurveysVos: null, }, { id: '1997964657866102784', name: '水费', orderNum: '27', rowid: 'f8a9b0c1-d2e3-4f4a-5b6c-7d8e9f0a1b2c', number: '2', rvalue: '60', taskId: '1995015537499938816', nianfen: null, parentId: 'd6e7f8a9-b0c1-4d2e-3f4a-5b6c7d8e9f0a', surveysVos: [ { name: '2022', value: '55' }, { name: '2023', value: '58' }, { name: '2024', value: '60' }, { name: '2025', value: '62' }, ], costSurveysVos: null, }, { id: '1997964657975148544', name: '燃气费', orderNum: '28', rowid: 'a9b0c1d2-e3f4-4a5b-6c7d-8e9f0a1b2c3d', number: '3', rvalue: '40', taskId: '1995015537499938816', nianfen: null, parentId: 'd6e7f8a9-b0c1-4d2e-3f4a-5b6c7d8e9f0a', surveysVos: [ { name: '2022', value: '35' }, { name: '2023', value: '38' }, { name: '2024', value: '40' }, { name: '2025', value: '38' }, ], costSurveysVos: null, }, ], }, ], }