| | |
| | | <div slot="header" class="clearfix row"> |
| | | <div style="flex: 1">项目进度统计</div> |
| | | <div style="flex: 3;display: flex;justify-content: flex-end"> |
| | | <el-select |
| | | <el-date-picker |
| | | v-model="selectedMonth" |
| | | type="month" |
| | | placeholder="选择月份" |
| | | style="width: 120px; margin-right: 10px;" |
| | | style="width: 180px; margin-right: 10px;" |
| | | @change="updateProgressChart" |
| | | > |
| | | <el-option |
| | | v-for="month in months" |
| | | :key="month.value" |
| | | :label="month.label" |
| | | :value="month.value" |
| | | ></el-option> |
| | | </el-select> |
| | | format="yyyy-MM" |
| | | value-format="yyyy-MM" |
| | | ></el-date-picker> |
| | | <el-select |
| | | v-model="selectedProjects" |
| | | multiple |
| | |
| | | :value="project.id" |
| | | ></el-option> |
| | | </el-select> |
| | | <el-button type="text" @click="showDetail">详情</el-button> |
| | | <!-- <el-button type="text" @click="showDetail">详情</el-button>--> |
| | | </div> |
| | | </div> |
| | | <div class="chart-container" ref="progressChart" style="height: 400px;"></div> |
| | |
| | | <div slot="header" class="clearfix row"> |
| | | <div style="flex: 1">推进卡点</div> |
| | | <div style="flex: 3; display: flex; justify-content: flex-end"> |
| | | <el-button type="text">全部</el-button> |
| | | <!-- <el-button type="text">全部</el-button>--> |
| | | </div> |
| | | </div> |
| | | <el-table :data="blockingTasks" style="width: 100%" height="250"> |
| | | <el-table-column prop="taskName" label="任务名称" width="180"></el-table-column> |
| | | <el-table-column prop="project" label="所属项目"></el-table-column> |
| | | <el-table-column prop="owner" label="负责人" width="100"></el-table-column> |
| | | <el-table-column prop="checkPointInfo.projectName" label="所属项目"></el-table-column> |
| | | <el-table-column prop="customerTaskInfo.promoterName" label="负责人" width="100"></el-table-column> |
| | | <el-table-column prop="startTime" label="开始时间" width="120"></el-table-column> |
| | | <el-table-column prop="deadline" label="截止日期" width="120"></el-table-column> |
| | | <el-table-column prop="overTime" label="已超时" width="120"></el-table-column> |
| | | <el-table-column prop="totalOverTimes" label="累计超时次数" width="120" align="center"></el-table-column> |
| | | <el-table-column prop="endTime" label="截止日期" width="120"></el-table-column> |
| | | <el-table-column prop="totalOverTime" label="已超时" width="120"></el-table-column> |
| | | <el-table-column prop="overTimeCount" label="累计超时次数" width="120" align="center"></el-table-column> |
| | | <el-table-column label="操作" width="80"> |
| | | <template slot-scope="scope"> |
| | | <el-button size="mini" @click="handleTaskDetail(scope.row)">查看</el-button> |
| | |
| | | :value="project.id" |
| | | ></el-option> |
| | | </el-select> |
| | | <el-button type="text" @click="showFundDetail">详情</el-button> |
| | | <!-- <el-button type="text" @click="showFundDetail">详情</el-button>--> |
| | | </div> |
| | | </div> |
| | | <div class="chart-container" ref="fundChart" style="height: 400px;"></div> |
| | |
| | | <div slot="header" class="clearfix row"> |
| | | <div style="flex:1">项目阶段统计</div> |
| | | <div style="flex:3;display: flex;justify-content: flex-end"> |
| | | <el-button type="text">详情</el-button> |
| | | <!-- <el-button type="text">详情</el-button>--> |
| | | </div> |
| | | </div> |
| | | <div class="chart-container" ref="stageChart" style="height: 250px;"></div> |
| | |
| | | |
| | | <script> |
| | | import * as echarts from 'echarts'; |
| | | import {getCodingCount ,getFundingStatus } from '@/api/index/index.js' |
| | | import { |
| | | getCodingCount, |
| | | getFundingStatus, |
| | | getTaskStatus, |
| | | getProjectSelectList, |
| | | getStageCount, |
| | | getProjectAdvanceCheckPoint |
| | | } from '@/api/index/index.js' |
| | | export default { |
| | | name: 'ProjectManagement', |
| | | data() { |
| | | return { |
| | | pathMap:{ |
| | | '在库': { path: '/projectEngineering/project/projectLibrary' }, |
| | | '储备': { |
| | | path: '/projectEngineering/project/reserveProjects', |
| | | query: { projectPhase: 1 } |
| | | }, |
| | | '前期': { |
| | | path:'/projectEngineering/project/previousProjects', |
| | | query: { projectPhase: 2 } |
| | | }, |
| | | '实施': { |
| | | path:'/projectEngineering/project/implementationProject', |
| | | query: { projectPhase: 3 } |
| | | }, |
| | | '竣工': { |
| | | path:'/projectEngineering/project/completedProjects', |
| | | query: { projectPhase: 4 } |
| | | } |
| | | }, |
| | | userName: '张经理', |
| | | userAvatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png', |
| | | overviewData: { |
| | | totalProjects: 42, |
| | | inProgress: 28, |
| | | atRisk: 7, |
| | | delayed: 5 |
| | | totalProjects: 0, |
| | | inProgress: 0, |
| | | atRisk: 0, |
| | | delayed: 0 |
| | | }, |
| | | blockingTasks: [ |
| | | { |
| | | taskName: '取得土地权属', |
| | | project: '射洪市酒粮基地建设项目', |
| | | owner: '李四', |
| | | startTime: '2025-05-15', |
| | | overTime: '10天06小时', |
| | | deadline: '2025-06-05', |
| | | totalOverTimes: 4, |
| | | status: '紧急' |
| | | }, |
| | | { |
| | | taskName: '可行性研究报告申请', |
| | | project: '射洪市酒粮基地建设项目', |
| | | owner: '王五', |
| | | startTime: '2025-05-21', |
| | | overTime: '8天', |
| | | deadline: '2025-05-30', |
| | | totalOverTimes: '5', |
| | | status: '高风险' |
| | | }, |
| | | { |
| | | taskName: '建设工程竣工验收申请', |
| | | project: '射洪市宜居宜业和美乡村建设项目', |
| | | owner: '赵六', |
| | | startTime: '2025-05-24', |
| | | overTime: '4天14小时', |
| | | deadline: '2025-06-04', |
| | | totalOverTimes: '4', |
| | | status: '延期' |
| | | }, |
| | | { |
| | | taskName: '生产建设项目水土保持方案编制', |
| | | project: '射洪市宜居宜业和美乡村建设项目', |
| | | owner: '钱七', |
| | | startTime: '2025-06-01', |
| | | overTime: '4天', |
| | | deadline: '2025-06-07', |
| | | totalOverTimes: '6', |
| | | status: '进行中' |
| | | }, |
| | | ], |
| | | progressChart: null, |
| | | fundChart: null, |
| | | stageChart: null, |
| | | // 筛选数据 |
| | | selectedMonth: '2025-06', |
| | | selectedMonth: this.getCurrentMonth(), |
| | | months: [ |
| | | { value: '2025-05', label: '2025年5月' }, |
| | | { value: '2025-06', label: '2025年6月' }, |
| | |
| | | selectedProjects: [], |
| | | fundSelectedProjects: [], |
| | | allProjects: [ |
| | | { id: 'p1', name: '射洪市国家储备林建设项目(一期)' }, |
| | | { id: 'p2', name: '射洪市白羽肉鸡产业建设项目' }, |
| | | { id: 'p3', name: '遂宁市射洪2024—2027年度东北片区高标准农田建设项目' }, |
| | | { id: 'p4', name: '射洪市现代种业示范基地建设项目' }, |
| | | { id: 'p5', name: '射洪市宜居宜业和美乡村建设项目' }, |
| | | { id: 'p6', name: '射洪市沱牌镇综合水利设施建设项目' } |
| | | ], |
| | | // 项目进度模拟数据 |
| | | progressData: { |
| | | '2025-05': { |
| | | 'p1': { completed: 30, inProgress: 50, notStarted: 20 }, |
| | | 'p2': { completed: 40, inProgress: 40, notStarted: 20 }, |
| | | 'p3': { completed: 10, inProgress: 60, notStarted: 30 }, |
| | | 'p4': { completed: 60, inProgress: 30, notStarted: 10 }, |
| | | 'p5': { completed: 25, inProgress: 45, notStarted: 30 }, |
| | | 'p6': { completed: 35, inProgress: 35, notStarted: 30 } |
| | | }, |
| | | '2025-06': { |
| | | 'p1': { completed: 50, inProgress: 40, notStarted: 10 }, |
| | | 'p2': { completed: 60, inProgress: 30, notStarted: 10 }, |
| | | 'p3': { completed: 30, inProgress: 50, notStarted: 20 }, |
| | | 'p4': { completed: 80, inProgress: 15, notStarted: 5 }, |
| | | 'p5': { completed: 45, inProgress: 35, notStarted: 20 }, |
| | | 'p6': { completed: 55, inProgress: 25, notStarted: 20 } |
| | | }, |
| | | '2025-07': { |
| | | 'p1': { completed: 70, inProgress: 25, notStarted: 5 }, |
| | | 'p2': { completed: 80, inProgress: 15, notStarted: 5 }, |
| | | 'p3': { completed: 50, inProgress: 40, notStarted: 10 }, |
| | | 'p4': { completed: 90, inProgress: 10, notStarted: 0 }, |
| | | 'p5': { completed: 65, inProgress: 25, notStarted: 10 }, |
| | | 'p6': { completed: 75, inProgress: 15, notStarted: 10 } |
| | | }, |
| | | '2025-08': { |
| | | 'p1': { completed: 90, inProgress: 10, notStarted: 0 }, |
| | | 'p2': { completed: 95, inProgress: 5, notStarted: 0 }, |
| | | 'p3': { completed: 70, inProgress: 25, notStarted: 5 }, |
| | | 'p4': { completed: 100, inProgress: 0, notStarted: 0 }, |
| | | 'p5': { completed: 85, inProgress: 10, notStarted: 5 }, |
| | | 'p6': { completed: 90, inProgress: 5, notStarted: 5 } |
| | | } |
| | | }, |
| | | // 资金使用模拟数据 |
| | | fundData: { |
| | | 'p1': { |
| | | total: 5000, |
| | | allocated: 3500, |
| | | remaining: 1500, |
| | | completed: 2800, |
| | | sources: { |
| | | projectCapital: 2000, |
| | | countyInvestment: 1500, |
| | | otherInvestment: 1000, |
| | | governmentInvestment: 500 |
| | | } |
| | | }, |
| | | 'p2': { |
| | | total: 3200, |
| | | allocated: 2500, |
| | | remaining: 700, |
| | | completed: 1800, |
| | | sources: { |
| | | projectCapital: 1200, |
| | | countyInvestment: 1000, |
| | | governmentInvestment: 1000 |
| | | } |
| | | }, |
| | | 'p3': { |
| | | total: 4200, |
| | | allocated: 3000, |
| | | remaining: 1200, |
| | | completed: 2200, |
| | | sources: { |
| | | projectCapital: 1500, |
| | | otherInvestment: 1200, |
| | | governmentInvestment: 1500 |
| | | } |
| | | }, |
| | | 'p4': { |
| | | total: 2800, |
| | | allocated: 2000, |
| | | remaining: 800, |
| | | completed: 1500, |
| | | sources: { |
| | | projectCapital: 1000, |
| | | countyInvestment: 800, |
| | | otherInvestment: 500, |
| | | governmentInvestment: 500 |
| | | } |
| | | }, |
| | | 'p5': { |
| | | total: 3800, |
| | | allocated: 3000, |
| | | remaining: 800, |
| | | completed: 2500, |
| | | sources: { |
| | | projectCapital: 1500, |
| | | countyInvestment: 1000, |
| | | governmentInvestment: 1300 |
| | | } |
| | | }, |
| | | 'p6': { |
| | | total: 4500, |
| | | allocated: 3500, |
| | | remaining: 1000, |
| | | completed: 3000, |
| | | sources: { |
| | | projectCapital: 2000, |
| | | countyInvestment: 1500, |
| | | otherInvestment: 500, |
| | | governmentInvestment: 500 |
| | | } |
| | | } |
| | | } |
| | | progressData: {}, |
| | | fundData: {} |
| | | }; |
| | | }, |
| | | mounted() { |
| | | getCodingCount().then(res =>{ |
| | | this.initData(); |
| | | |
| | | }) |
| | | getFundingStatus().then(res=>{ |
| | | |
| | | }) |
| | | |
| | | this.selectedProjects = this.allProjects.map(p => p.id); // 默认全选 |
| | | this.fundSelectedProjects = this.allProjects.map(p => p.id); // 默认全选 |
| | | this.initCharts(); |
| | | window.addEventListener('resize', this.handleResize); |
| | | }, |
| | | beforeDestroy() { |
| | | window.removeEventListener('resize', this.handleResize); |
| | |
| | | } |
| | | }, |
| | | methods: { |
| | | getCurrentMonth() { |
| | | const now = new Date(); |
| | | const year = now.getFullYear(); |
| | | const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1 |
| | | return `${year}-${month}`; |
| | | }, |
| | | async initData(){ |
| | | |
| | | await this.initSelect(); |
| | | await this.initCodingCount(); |
| | | await this.initCharts(); |
| | | await this.initProjectAdvanceCheckPoint(); |
| | | window.addEventListener('resize', this.handleResize); |
| | | }, |
| | | initProjectAdvanceCheckPoint(){ |
| | | getProjectAdvanceCheckPoint().then(res =>{ |
| | | if (res.code === 200){ |
| | | this.blockingTasks = res.data; |
| | | |
| | | } |
| | | |
| | | }) |
| | | }, |
| | | initCodingCount(){ |
| | | getCodingCount().then(res =>{ |
| | | if(res.code === 200){ |
| | | this.overviewData.totalProjects = res.data.total; |
| | | this.overviewData.inProgress = res.data.green; |
| | | this.overviewData.atRisk = res.data.yellow; |
| | | this.overviewData.delayed = res.data.red; |
| | | } |
| | | }) |
| | | |
| | | }, |
| | | initSelect(){ |
| | | getProjectSelectList().then(res =>{ |
| | | if (res.code === 200){ |
| | | this.allProjects = Object.entries(res.data).map(([id, name]) => ({ |
| | | id: id, // 项目ID(如"151") |
| | | name: name // 项目名称(如"射洪市万林钢厂片区棚户区改造项目") |
| | | })); |
| | | this.selectedProjects = this.allProjects.slice(0, 5).map(p => p.id); |
| | | this.fundSelectedProjects = this.allProjects.slice(0, 5).map(p => p.id); |
| | | } |
| | | }) |
| | | }, |
| | | initCharts() { |
| | | // 初始化项目进度图表 |
| | | this.progressChart = echarts.init(this.$refs.progressChart); |
| | |
| | | |
| | | // 初始化项目阶段统计图表 |
| | | this.stageChart = echarts.init(this.$refs.stageChart); |
| | | this.stageChart.setOption({ |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'shadow' |
| | | } |
| | | }, |
| | | grid: { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: ['在库', '储备', '前期', '实施', '竣工'], |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#409EFF' |
| | | } |
| | | } |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#409EFF' |
| | | } |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | data: [15, 12, 10, 8, 6, 4, 2], |
| | | type: 'line', |
| | | smooth: true, |
| | | lineStyle: { |
| | | width: 3, |
| | | color: '#409EFF' |
| | | }, |
| | | itemStyle: { |
| | | color: '#409EFF' |
| | | }, |
| | | areaStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgba(64, 158, 255, 0.5)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(64, 158, 255, 0.1)' |
| | | } |
| | | ]) |
| | | } |
| | | } |
| | | ] |
| | | }); |
| | | }, |
| | | this.updateStageChart(); |
| | | |
| | | }, |
| | | updateStageChart(){ |
| | | if (!this.stageChart) return; |
| | | getStageCount().then(res =>{ |
| | | if (res.code ===200){ |
| | | const xData = res.data.xData || []; |
| | | const yData = res.data.yData || []; |
| | | this.stageChart.setOption({ |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | triggerOn: 'mousemove', |
| | | axisPointer: { |
| | | type: 'shadow' |
| | | } |
| | | }, |
| | | grid: { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: xData, |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#409EFF' |
| | | } |
| | | } |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#409EFF' |
| | | } |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | data: yData, |
| | | type: 'line', |
| | | smooth: true, |
| | | lineStyle: { |
| | | width: 3, |
| | | color: '#409EFF' |
| | | }, |
| | | itemStyle: { |
| | | color: '#409EFF' |
| | | }, |
| | | emphasis: { |
| | | itemStyle: { |
| | | color: '#1989fa', |
| | | size: 10 |
| | | }, |
| | | lineStyle: { |
| | | width: 4 |
| | | }, |
| | | // 整个系列区域hover都显示手型 |
| | | cursor: 'pointer', |
| | | areaStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: 'rgba(25, 137, 250, 0.6)' }, |
| | | { offset: 1, color: 'rgba(25, 137, 250, 0.2)' } |
| | | ]) |
| | | } |
| | | }, |
| | | areaStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgba(64, 158, 255, 0.5)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(64, 158, 255, 0.1)' |
| | | } |
| | | ]) |
| | | }, |
| | | triggerLineEvent: true, |
| | | triggerAreaEvent: true |
| | | } |
| | | ] |
| | | }); |
| | | |
| | | this.stageChart.off('click'); |
| | | this.stageChart.on('click', (params) => { |
| | | console.log('图表点击参数:', params); |
| | | // 仅点击系列区域时处理 |
| | | if (params.componentType === 'series') { |
| | | // 1. 将点击的像素坐标转换为X轴索引 |
| | | const pointInPixel = [params.event.offsetX, params.event.offsetY]; |
| | | const xAxisIndex = 0; // X轴索引(只有一个X轴,固定为0) |
| | | const xAxisValue = this.stageChart.convertFromPixel({ seriesIndex: 0, axisIndex: xAxisIndex }, pointInPixel)[0]; |
| | | |
| | | // 2. 计算所属的X轴标签索引(取整) |
| | | const targetIndex = Math.max(0, Math.min(xData.length - 1, Math.floor(xAxisValue))); |
| | | // 3. 获取对应标签 |
| | | const targetLabel = xData[targetIndex]; |
| | | |
| | | // 4. 匹配pathMap跳转(无匹配则走默认) |
| | | if (targetLabel && Object.keys(this.pathMap).includes(targetLabel)) { |
| | | console.log(targetLabel) |
| | | const targetRoute = this.pathMap[targetLabel] || { path: '/projectEngineering/project/projectLibrary' }; |
| | | this.$router.push(targetRoute); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | }) |
| | | }, |
| | | // 更新项目进度图表数据 |
| | | updateProgressChart() { |
| | | if (!this.progressChart) return; |
| | | const form ={ |
| | | startTime:this.selectedMonth |
| | | } |
| | | getTaskStatus(form).then(res => { |
| | | if (res.code === 200) { |
| | | // 从响应数据中提取流程统计信息 |
| | | const processStatistics = res.data || []; |
| | | |
| | | const monthData = this.progressData[this.selectedMonth]; |
| | | const filteredProjects = this.allProjects.filter(p => |
| | | this.selectedProjects.includes(p.id) |
| | | ); |
| | | |
| | | const categories = filteredProjects.map(p => p.name); |
| | | const completedData = filteredProjects.map(p => monthData[p.id].completed); |
| | | const inProgressData = filteredProjects.map(p => monthData[p.id].inProgress); |
| | | const notStartedData = filteredProjects.map(p => monthData[p.id].notStarted); |
| | | // 将后端数据转换为前端需要的格式 |
| | | const monthData = {}; |
| | | processStatistics.forEach(item => { |
| | | // 假设后端返回的项目ID字段是 projectId,需要和前端的 allProjects 中的 id 匹配 |
| | | monthData[item.id] = { |
| | | completed: item.completed || 0, |
| | | inProgress: item.inProgress || 0, |
| | | notStarted: item.notStarted || 0 |
| | | }; |
| | | }); |
| | | // 筛选选中的项目 |
| | | const filteredProjects = this.allProjects.filter(p => |
| | | this.selectedProjects.includes(p.id) |
| | | ); |
| | | |
| | | this.progressChart.setOption({ |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'shadow' |
| | | }, |
| | | formatter: function(params) { |
| | | let result = params[0].name + '<br/>'; |
| | | params.forEach(param => { |
| | | result += `${param.seriesName}: ${param.value}%<br/>`; |
| | | }); |
| | | result += `总计: ${params.reduce((sum, param) => sum + param.value, 0)}%`; |
| | | return result; |
| | | } |
| | | }, |
| | | legend: { |
| | | data: ['已完成事项', '进行中事项', '未开始事项'] |
| | | }, |
| | | grid: { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'value', |
| | | max: 100, |
| | | axisLabel: { |
| | | formatter: '{value}%' |
| | | } |
| | | }, |
| | | yAxis: { |
| | | type: 'category', |
| | | data: categories |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '已完成事项', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | emphasis: { |
| | | focus: 'series' |
| | | // 准备图表数据 |
| | | const categories = filteredProjects.map(p => p.name); |
| | | const completedData = filteredProjects.map(p => monthData[p.id]?.completed || 0); |
| | | const inProgressData = filteredProjects.map(p => monthData[p.id]?.inProgress || 0); |
| | | const notStartedData = filteredProjects.map(p => monthData[p.id]?.notStarted || 0); |
| | | |
| | | // 更新图表配置 |
| | | this.progressChart.setOption({ |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'shadow' |
| | | }, |
| | | formatter: function(params) { |
| | | let result = params[0].name + '<br/>'; |
| | | params.forEach(param => { |
| | | result += `${param.seriesName}: ${param.value}%<br/>`; |
| | | }); |
| | | // result += `总计: ${params.reduce((sum, param) => sum + param.value, 0)}%`; |
| | | return result; |
| | | } |
| | | }, |
| | | data: completedData, |
| | | itemStyle: { |
| | | color: '#67C23A' |
| | | legend: { |
| | | data: ['已完成事项', '进行中事项', '未开始事项'] |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'inside', |
| | | formatter: '{c}%' |
| | | } |
| | | }, |
| | | { |
| | | name: '进行中事项', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | emphasis: { |
| | | focus: 'series' |
| | | grid: { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | }, |
| | | data: inProgressData, |
| | | itemStyle: { |
| | | color: '#409EFF' |
| | | xAxis: { |
| | | type: 'value', |
| | | max: 100, |
| | | axisLabel: { |
| | | formatter: '{value}%' |
| | | } |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'inside', |
| | | formatter: '{c}%' |
| | | } |
| | | }, |
| | | { |
| | | name: '未开始事项', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | emphasis: { |
| | | focus: 'series' |
| | | yAxis: { |
| | | type: 'category', |
| | | data: categories |
| | | }, |
| | | data: notStartedData, |
| | | itemStyle: { |
| | | color: '#E6A23C' |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'inside', |
| | | formatter: '{c}%' |
| | | } |
| | | } |
| | | ] |
| | | series: [ |
| | | { |
| | | name: '已完成事项', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: completedData, |
| | | itemStyle: { |
| | | color: '#67C23A' |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'inside', |
| | | formatter: '{c}%' |
| | | } |
| | | }, |
| | | { |
| | | name: '进行中事项', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: inProgressData, |
| | | itemStyle: { |
| | | color: '#409EFF' |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'inside', |
| | | formatter: '{c}%' |
| | | } |
| | | }, |
| | | { |
| | | name: '未开始事项', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: notStartedData, |
| | | itemStyle: { |
| | | color: '#E6A23C' |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'inside', |
| | | formatter: '{c}%' |
| | | } |
| | | } |
| | | ] |
| | | }); |
| | | } |
| | | }).catch(error => { |
| | | // 错误处理 |
| | | this.progressChart.hideLoading(); |
| | | console.error('获取任务状态数据失败:', error); |
| | | // 可以显示错误提示或使用默认数据 |
| | | }); |
| | | }, |
| | | |
| | | // 更新资金使用图表数据 |
| | | updateFundChart() { |
| | | if (!this.fundChart) return; |
| | | getFundingStatus().then(res=> { |
| | | if (res.code === 200) { |
| | | const fundingData = res.data || []; |
| | | const data = {}; |
| | | fundingData.forEach(item => { |
| | | // 仅组装 SQL 查询返回的 9 个字段,字段名与 VO 一致 |
| | | data[item.projectId] = { |
| | | id: item.projectId || '', // 项目ID(关联键) |
| | | totalInvestment: item.totalInvestment || '0', // 项目总投资额 |
| | | principal: item.principal || '0', // 项目本金 |
| | | governmentInvestmentTotal: item.governmentInvestmentTotal || '0', // 政府投资总额 |
| | | centralInvestmentTotal: item.centralInvestmentTotal || '0', // 中央投资总额 |
| | | provincialInvestmentTotal: item.provincialInvestmentTotal || '0', // 省级投资总额 |
| | | cityInvestmentTotal: item.cityInvestmentTotal || '0', // 市(州)投资总额 |
| | | countyInvestmentTotal: item.countyInvestmentTotal || '0', // 县(市、区)投资总额 |
| | | otherInvestmentTotal: item.otherInvestmentTotal || '0', // 其他投资总额 |
| | | enterpriseSelfRaisedTotal: item.enterpriseSelfRaisedTotal || '0', |
| | | foreignInvestmentTotal: item.foreignInvestmentTotal || '0', |
| | | bankLoan: item.bankLoan || '0',//银行贷款 |
| | | domesticLoanTotal: item.domesticLoanTotal || '0', |
| | | }; |
| | | }); |
| | | console.log(data) |
| | | const filteredProjects = this.allProjects.filter(p => |
| | | this.fundSelectedProjects.includes(p.id) |
| | | ); |
| | | const categories = filteredProjects.map(p => p.name); |
| | | // console.log(categories) |
| | | // const allocatedData = filteredProjects.map(p => data[p.id].allocated); |
| | | // console.log(allocatedData) |
| | | // const remainingData = filteredProjects.map(p => data[p.id].remaining); |
| | | // console.log(remainingData) |
| | | |
| | | const filteredProjects = this.allProjects.filter(p => |
| | | this.fundSelectedProjects.includes(p.id) |
| | | ); |
| | | // 资金来源数据 本金 |
| | | const projectCapitalData = filteredProjects.map(p => |
| | | data[p.id].principal || 0 |
| | | ); |
| | | //总投资 |
| | | const totalInvestmentData = filteredProjects.map(p => |
| | | data[p.id].totalInvestment || 0 |
| | | ); |
| | | // 县(市、区)投资总额 |
| | | const countyInvestmentData = filteredProjects.map(p => |
| | | data[p.id].countyInvestmentTotal || 0 |
| | | ); |
| | | // 市(州)投资总额 |
| | | const cityInvestmentTotalData = filteredProjects.map(p => |
| | | data[p.id].cityInvestmentTotal || 0) |
| | | // 省级投资总额 |
| | | const provincialInvestmentTotalData = filteredProjects.map(p => |
| | | data[p.id].provincialInvestmentTotal || 0) |
| | | //政府投资 |
| | | const governmentInvestmentData = filteredProjects.map(p => |
| | | data[p.id].governmentInvestmentTotal || 0 |
| | | ); |
| | | //其他投资 |
| | | const otherInvestmentData = filteredProjects.map(p => |
| | | data[p.id].otherInvestmentTotal || 0 |
| | | ); |
| | | //中央 |
| | | const centralInvestmentTotalData = filteredProjects.map(p => |
| | | data[p.id].centralInvestmentTotal || 0 |
| | | ); |
| | | //企业自筹 |
| | | const enterpriseSelfRaisedTotalData = filteredProjects.map(p => |
| | | data[p.id].enterpriseSelfRaisedTotal || 0 |
| | | ); |
| | | //外商投资 |
| | | const foreignInvestmentTotalData = filteredProjects.map(p => |
| | | data[p.id].foreignInvestmentTotal || 0 |
| | | ); |
| | | const bankLoanData = filteredProjects.map(p => |
| | | data[p.id].bankLoan || 0 |
| | | ); |
| | | const domesticLoanTotalData = filteredProjects.map(p => |
| | | data[p.id].domesticLoanTotal || 0 |
| | | ); |
| | | |
| | | const categories = filteredProjects.map(p => p.name); |
| | | const allocatedData = filteredProjects.map(p => this.fundData[p.id].allocated); |
| | | const remainingData = filteredProjects.map(p => this.fundData[p.id].remaining); |
| | | |
| | | // 资金来源数据 |
| | | const projectCapitalData = filteredProjects.map(p => |
| | | this.fundData[p.id].sources.projectCapital || 0 |
| | | ); |
| | | const countyInvestmentData = filteredProjects.map(p => |
| | | this.fundData[p.id].sources.countyInvestment || 0 |
| | | ); |
| | | const otherInvestmentData = filteredProjects.map(p => |
| | | this.fundData[p.id].sources.otherInvestment || 0 |
| | | ); |
| | | const governmentInvestmentData = filteredProjects.map(p => |
| | | this.fundData[p.id].sources.governmentInvestment || 0 |
| | | ); |
| | | this.fundChart.setOption({ |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | confine: true, |
| | | axisPointer: { |
| | | type: 'shadow' |
| | | }, |
| | | zIndex: 9999, |
| | | |
| | | this.fundChart.setOption({ |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'shadow' |
| | | }, |
| | | formatter: function(params) { |
| | | let result = params[0].name + '<br/>'; |
| | | // 资金拨付和剩余 |
| | | result += `资金拨付: ${params[0].value}万元<br/>`; |
| | | result += `剩余金额: ${params[1].value}万元<br/>`; |
| | | result += `总金额: ${params[0].value + params[1].value}万元<br/>`; |
| | | result += `完成投资: ${params[0].axisValueLabel}万元<br/><br/>`; |
| | | |
| | | // 资金来源 |
| | | result += '<strong>资金来源构成:</strong><br/>'; |
| | | result += `项目本金: ${params[2].value}万元<br/>`; |
| | | result += `县(市、区)投资: ${params[3].value}万元<br/>`; |
| | | result += `其他投资: ${params[4].value}万元<br/>`; |
| | | result += `政府投资: ${params[5].value}万元<br/>`; |
| | | |
| | | return result; |
| | | } |
| | | }, |
| | | legend: { |
| | | data: ['剩余金额', '资金拨付', '项目本金', '县(市、区)投资', '政府投资', '其他投资'] |
| | | }, |
| | | grid: { |
| | | top: '30%', |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '5%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: categories, |
| | | axisLabel: { |
| | | interval: 0, |
| | | rotate: 30 |
| | | } |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | name: '金额(万元)' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '资金拨付', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | emphasis: { |
| | | focus: 'series' |
| | | formatter: function(params) { |
| | | let result = params[0].name + '<br/>'; |
| | | // 资金拨付和剩余 |
| | | // result += `资金拨付: ${params[0].value}万元<br/>`; |
| | | // result += `剩余金额: ${params[1].value}万元<br/>`; |
| | | const value1 = Number(params[0].value) || 0; |
| | | const value2 = Number(params[1].value) || 0; |
| | | result += `总金额: ${value1 + value2}万元<br/>`; |
| | | // result += `完成投资: ${params[0].axisValueLabel}万元<br/><br/>`; |
| | | // |
| | | // // 资金来源 |
| | | result += '<strong>资金来源构成:</strong><br/>'; |
| | | result += `项目本金: ${params[0].value}万元<br/>`; |
| | | result += `县(市、区)投资: ${params[2].value}万元<br/>`; |
| | | result += `市(州)投资: ${params[3].value}万元<br/>`; |
| | | result += `省级投资: ${params[4].value}万元<br/>`; |
| | | result += `中央投资: ${params[5].value}万元<br/>`; |
| | | result += `政府投资: ${params[6].value}万元<br/>`; |
| | | result += `其他投资: ${params[7].value}万元<br/>`; |
| | | result += `企业自筹: ${params[8].value}万元<br/>`; |
| | | result += `外商投资: ${params[9].value}万元<br/>`; |
| | | result += `银行贷款: ${params[10].value}万元<br/>`; |
| | | result += `国内贷款: ${params[11].value}万元<br/>`; |
| | | return result; |
| | | } |
| | | }, |
| | | data: allocatedData, |
| | | itemStyle: { |
| | | color: '#409EFF' |
| | | legend: { |
| | | data: [ |
| | | // '剩余金额', '资金拨付', |
| | | '项目本金','项目总投资', '县(市、区)投资','市(州)投资','省级投资','中央投资', '政府投资', '其他投资', |
| | | '企业自筹', '外商投资', '银行贷款', '国内贷款',] |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'inside', |
| | | formatter: '{c}' |
| | | } |
| | | }, |
| | | { |
| | | name: '剩余金额', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | emphasis: { |
| | | focus: 'series' |
| | | grid: { |
| | | top: '30%', |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '5%', |
| | | containLabel: true |
| | | }, |
| | | data: remainingData, |
| | | itemStyle: { |
| | | color: '#E6A23C' |
| | | xAxis: { |
| | | type: 'category', |
| | | data: categories, |
| | | axisLabel: { |
| | | interval: 0, |
| | | rotate: 30 |
| | | } |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'inside', |
| | | formatter: '{c}' |
| | | } |
| | | }, |
| | | { |
| | | name: '项目本金', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | yAxis: { |
| | | type: 'value', |
| | | name: '金额(万元)' |
| | | }, |
| | | data: projectCapitalData, |
| | | itemStyle: { |
| | | color: '#67C23A' |
| | | } |
| | | }, |
| | | { |
| | | name: '县(市、区)投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: countyInvestmentData, |
| | | itemStyle: { |
| | | color: '#F56C6C' |
| | | } |
| | | }, |
| | | { |
| | | name: '其他投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: otherInvestmentData, |
| | | itemStyle: { |
| | | color: '#909399' |
| | | } |
| | | }, |
| | | { |
| | | name: '政府投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: governmentInvestmentData, |
| | | itemStyle: { |
| | | color: '#8E44AD' |
| | | } |
| | | } |
| | | ] |
| | | series: [ |
| | | { |
| | | name: '项目本金', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: projectCapitalData, |
| | | itemStyle: { |
| | | color: '#42B983' // 主绿色:项目核心自有资金 |
| | | } |
| | | }, |
| | | { |
| | | name: '项目总投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: totalInvestmentData, |
| | | itemStyle: { |
| | | color: '#36CFC9' // 青绿色:总投资汇总数据 |
| | | } |
| | | }, |
| | | { |
| | | name: '县(市、区)投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: countyInvestmentData, |
| | | itemStyle: { |
| | | color: '#A0D911' // 浅黄绿色:县级投资 |
| | | } |
| | | }, |
| | | { |
| | | name: '市(州)投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: cityInvestmentTotalData, |
| | | itemStyle: { |
| | | color: '#7CB305' // 亮绿色:市州级投资 |
| | | } |
| | | }, |
| | | { |
| | | name: '省级投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: provincialInvestmentTotalData, |
| | | itemStyle: { |
| | | color: '#40A9FF' // 中蓝色:省级投资 |
| | | } |
| | | }, |
| | | { |
| | | name: '中央投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: centralInvestmentTotalData, |
| | | itemStyle: { |
| | | color: '#1890FF' // 深蓝色:中央投资(层级最高) |
| | | } |
| | | }, |
| | | { |
| | | name: '政府投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: governmentInvestmentData, |
| | | itemStyle: { |
| | | color: '#8E44AD' // 紫色:政府投资总额(汇总项) |
| | | } |
| | | },{ |
| | | name: '其他投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: otherInvestmentData, |
| | | itemStyle: { |
| | | color: '#909399' // 深灰色:其他投资 |
| | | } |
| | | }, |
| | | { |
| | | name: '企业自筹', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: enterpriseSelfRaisedTotalData, |
| | | itemStyle: { |
| | | color: '#e6cb6d' // 深灰色:其他投资 |
| | | } |
| | | }, |
| | | { |
| | | name: '外商投资', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: foreignInvestmentTotalData, |
| | | itemStyle: { |
| | | color: '#f443b9' // 深灰色:其他投资 |
| | | } |
| | | },{ |
| | | name: '银行贷款', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: bankLoanData, |
| | | itemStyle: { |
| | | color: '#bd5fd8' // 深灰色:其他投资 |
| | | } |
| | | },{ |
| | | name: '国内贷款', |
| | | type: 'bar', |
| | | stack: 'sources', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: domesticLoanTotalData, |
| | | itemStyle: { |
| | | color: '#4373d3' // 深灰色:其他投资 |
| | | } |
| | | } |
| | | ] |
| | | }); |
| | | this.fundChart.on('click', (params) => { // 这里改为箭头函数 |
| | | const clickedProject = filteredProjects[params.dataIndex]; |
| | | const projectId = clickedProject ? clickedProject.id : '无'; |
| | | const audit = 1; |
| | | // 此时 this 指向 Vue 组件,可正常访问 $router |
| | | this.$router.push({ |
| | | path: '/projectEngineering/project/ProjectDetails', |
| | | query: { projectId: projectId, disabled: 'true', audit: audit } |
| | | }); |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | |
| | | }, |
| | | removeStore() { |
| | | localStorage.removeItem("projectForm") |
| | | localStorage.removeItem("investmentForm") |
| | | localStorage.removeItem("investmentFundsForm") |
| | | localStorage.removeItem("legalPersonForm") |
| | | localStorage.removeItem("policyInfoForm") |
| | | localStorage.removeItem("documentsInfoForm") |
| | | }, |
| | | // 更新所有图表 |
| | | updateCharts() { |
| | | this.updateProgressChart(); |
| | |
| | | return map[status] || ''; |
| | | }, |
| | | handleTaskDetail(task) { |
| | | this.$message.info(`查看任务详情: ${task.taskName}`); |
| | | console.log(task) |
| | | const queryParams= { |
| | | taskName: '', |
| | | taskType: 'todo', |
| | | pageSize: 5, |
| | | currentPage: 1, |
| | | projectId: null, |
| | | processDefId: null, |
| | | processInsId: null, |
| | | deployId: null, |
| | | processName: '' // 流程名称 |
| | | } |
| | | this.$router.push({ path: '/flowable/task/myProcess/detail/index', |
| | | query: { |
| | | projectName: task.checkPointInfo.projectName, |
| | | flowName: task.checkPointInfo.processName, |
| | | procInsId: task.checkPointInfo.processInstanceId, |
| | | deployId: task.checkPointInfo.deployId, |
| | | taskId: task.id, |
| | | projectId: task.checkPointInfo.id, |
| | | goBackParams: queryParams |
| | | }}) |
| | | }, |
| | | showDetail() { |
| | | this.$message.info(`查看${this.selectedMonth}月份的项目进度详情`); |