| | |
| | | <TitleBox> |
| | | <template #title>项目风险趋势 </template> |
| | | <template #right> |
| | | <div @click="handleClick" class="risk-picker"> |
| | | <el-date-picker v-model="dateRange" ref="datePicker" type="monthrange" range-separator="" |
| | | start-placeholder="" end-placeholder=""> |
| | | </el-date-picker> |
| | | <div class="risk-picker"> |
| | | <div class="risk-ab"> |
| | | <img src="../../assets/img/home/Shape@2x (6).png" class="pick-img" /> |
| | | |
| | |
| | | {{ dateTxt }} |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | </template> |
| | | <template #content> |
| | |
| | | deviceTypes, |
| | | getProjectPersonInfo, |
| | | getProjectSource, |
| | | getDangerTrend |
| | | getDangerTrend, |
| | | getProjectDangerousTrend |
| | | } from './service.js' |
| | | import { |
| | | transformRiskSourceData |
| | |
| | | return { |
| | | mapView: null, |
| | | mapPromise: null, |
| | | dateRange: [moment().startOf("month"), moment().endOf("month")], //默认本月 |
| | | dateRange: [moment().subtract(5, 'months').startOf("month"), moment().endOf("month")], //默认近6个月 |
| | | markers: [], |
| | | projectId: '', |
| | | projectName: '', |
| | |
| | | { riskScale: '一般', content: '项目风险源内容3', status: '已完成' }, |
| | | { riskScale: '重大', content: '项目风险源内容4', status: '未开始' }, |
| | | { riskScale: '重大', content: '项目风险源内容5', status: '进行中' }, |
| | | ] |
| | | ], |
| | | // 项目风险趋势数据 |
| | | riskTrendData: { |
| | | xAxisData: [], |
| | | seriesData: [] |
| | | } |
| | | }; |
| | | }, |
| | | computed: { |
| | |
| | | moment(newVal[0]).format("YYYY -MM") + |
| | | " - " + |
| | | moment(newVal[1]).format("YYYY -MM"); |
| | | // 当日期范围改变时,重新获取风险趋势数据 |
| | | if (this.projectId) { |
| | | this.getProjectRiskTrend(); |
| | | } |
| | | } |
| | | }, |
| | | immediate: true, |
| | |
| | | }) |
| | | this.getDetail() |
| | | this.getDangerTrendList() |
| | | this.getProjectRiskTrend() |
| | | } |
| | | }, |
| | | mounted() { |
| | |
| | | // mapStyle: "amap://styles/darkblue", |
| | | layers: [satellite], |
| | | }); |
| | | |
| | | // 在地图中心添加marker |
| | | const marker = new AMap.Marker({ |
| | | position: [104.065617, 30.65695], // 使用地图中心点坐标 |
| | | icon: new AMap.Icon({ |
| | | image: require('../../assets/img/project/mark.png'), |
| | | size: new AMap.Size(30, 30), |
| | | imageSize: new AMap.Size(30, 30) |
| | | }), |
| | | offset: new AMap.Pixel(-15, -15) // 设置偏移量,使图标中心对准坐标点 |
| | | }); |
| | | |
| | | // 将marker添加到地图 |
| | | this.mapView.add(marker); |
| | | |
| | | // this.initCategoryMarkers(AMap); |
| | | }) |
| | | .catch((e) => { |
| | |
| | | // }); |
| | | return series; |
| | | }, |
| | | handleClick() { |
| | | this.$refs.datePicker.focus(); |
| | | // 风险等级转换为数值 (A->3, B->2, C->1) |
| | | levelToValue(level) { |
| | | if (!level) return null; |
| | | const levelStr = String(level).toUpperCase().trim(); |
| | | |
| | | // 处理 A、B、C 或 A类、B类、C类 |
| | | if (levelStr === 'A' || levelStr === 'A类') return 3; |
| | | if (levelStr === 'B' || levelStr === 'B类') return 2; |
| | | if (levelStr === 'C' || levelStr === 'C类') return 1; |
| | | |
| | | return null; |
| | | }, |
| | | // 数值转换为风险等级显示 (3->A类, 2->B类, 1->C类) |
| | | valueToLevel(value) { |
| | | if (value === 3) return 'A类'; |
| | | if (value === 2) return 'B类'; |
| | | if (value === 1) return 'C类'; |
| | | return ''; |
| | | }, |
| | | // 获取项目风险趋势数据 |
| | | async getProjectRiskTrend() { |
| | | if (!this.dateRange || this.dateRange.length !== 2) { |
| | | return; |
| | | } |
| | | |
| | | const params = { |
| | | projectId: this.projectId, |
| | | startTime: moment(this.dateRange[0]).format('YYYY-MM'), |
| | | endTime: moment(this.dateRange[1]).format('YYYY-MM') |
| | | }; |
| | | |
| | | try { |
| | | const res = await getProjectDangerousTrend(params); |
| | | console.log('项目风险趋势数据:', res); |
| | | |
| | | if (res && Array.isArray(res)) { |
| | | // 处理接口返回的数据 |
| | | this.riskTrendData.xAxisData = res.map(item => item.time || ''); |
| | | // 将A、B、C转换为数值 3、2、1 |
| | | this.riskTrendData.seriesData = res.map(item => { |
| | | const value = this.levelToValue(item.level); |
| | | console.log(`level: ${item.level} -> value: ${value}`); |
| | | return value; |
| | | }); |
| | | |
| | | console.log('转换后的数据:', { |
| | | xAxisData: this.riskTrendData.xAxisData, |
| | | seriesData: this.riskTrendData.seriesData |
| | | }); |
| | | |
| | | // 更新图表 |
| | | this.updateRiskChart(); |
| | | } |
| | | } catch (error) { |
| | | console.error('获取项目风险趋势失败:', error); |
| | | } |
| | | }, |
| | | // 更新风险趋势图表 |
| | | updateRiskChart() { |
| | | const riskChart = echarts.getInstanceByDom(document.getElementById('riskTrendChart')); |
| | | if (!riskChart) { |
| | | return; |
| | | } |
| | | |
| | | // 文本换行处理函数 |
| | | const formatLabel = (text, maxWidth = 4) => { |
| | | if (!text) return '' |
| | | const textStr = String(text) |
| | | // 如果文本长度超过最大宽度,进行换行 |
| | | if (textStr.length > maxWidth) { |
| | | let result = '' |
| | | for (let i = 0; i < textStr.length; i += maxWidth) { |
| | | result += textStr.substring(i, i + maxWidth) + '\n' |
| | | } |
| | | return result.trim() |
| | | } |
| | | return textStr |
| | | } |
| | | |
| | | const self = this; |
| | | |
| | | const option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | show: true, |
| | | backgroundColor: 'rgba(0, 0, 0, 0.7)', |
| | | borderColor: '#32C5FF', |
| | | borderWidth: 1, |
| | | textStyle: { |
| | | color: '#fff', |
| | | fontSize: 12 |
| | | }, |
| | | formatter: function(params) { |
| | | if (params && params.length > 0) { |
| | | const param = params[0]; |
| | | const levelText = self.valueToLevel(param.value); |
| | | return `${param.name}<br/>${param.seriesName}: ${levelText}`; |
| | | } |
| | | return ''; |
| | | } |
| | | }, |
| | | legend: { |
| | | show: false |
| | | }, |
| | | grid: { |
| | | top: '10%', |
| | | bottom: '10%', |
| | | left: '10%', |
| | | right: '5%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | data: this.riskTrendData.xAxisData, |
| | | axisTick: { show: true, alignWithLabel: true }, |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#666' |
| | | } |
| | | }, |
| | | axisLabel: { |
| | | color: '#fff', |
| | | fontSize: 12, |
| | | interval: 0, |
| | | rotate: 0, |
| | | formatter: function (value) { |
| | | return formatLabel(value, 7) |
| | | }, |
| | | align: 'center', |
| | | verticalAlign: 'top', |
| | | lineHeight: 14, |
| | | width: 60, |
| | | overflow: 'break' |
| | | } |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | min: 1, |
| | | max: 3, |
| | | interval: 1, |
| | | splitLine: { |
| | | show: true, |
| | | lineStyle: { |
| | | type: 'dashed', |
| | | color: 'rgba(255, 255, 255, .2)' |
| | | } |
| | | }, |
| | | axisLine: { |
| | | show: false |
| | | }, |
| | | axisTick: { |
| | | show: false |
| | | }, |
| | | axisLabel: { |
| | | color: '#fff', |
| | | fontSize: 12, |
| | | formatter: function (value) { |
| | | // Y轴自定义显示:1->C类, 2->B类, 3->A类 |
| | | if (value === 1) return 'C类'; |
| | | if (value === 2) return 'B类'; |
| | | if (value === 3) return 'A类'; |
| | | return ''; |
| | | }, |
| | | align: 'right', |
| | | verticalAlign: 'middle', |
| | | lineHeight: 14, |
| | | width: 30 |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '风险等级', |
| | | type: 'line', |
| | | data: this.riskTrendData.seriesData, |
| | | smooth: false, |
| | | showSymbol: true, |
| | | symbol: 'circle', |
| | | symbolSize: 8, |
| | | itemStyle: { |
| | | color: '#32C5FF', |
| | | borderColor: '#32C5FF', |
| | | borderWidth: 2 |
| | | }, |
| | | lineStyle: { |
| | | width: 5, |
| | | color: { |
| | | type: 'linear', |
| | | x: 0, |
| | | y: 0, |
| | | x2: 1, |
| | | y2: 0, |
| | | colorStops: [ |
| | | { offset: 0, color: 'rgba(36, 81, 242, 1)' }, |
| | | { offset: 0.5, color: 'rgba(11, 204, 254, 1)' }, |
| | | { offset: 1, color: 'rgba(199, 160, 254, 1)' } |
| | | ] |
| | | } |
| | | } |
| | | } |
| | | ] |
| | | }; |
| | | |
| | | riskChart.setOption(option); |
| | | }, |
| | | // 初始化折线图 |
| | | initRiskChart() { |
| | |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | data: ['2025年1月检查', '2025年2月检查', '2025年3月检查', '2025年4月检查', '2025年5月检查'], |
| | | data: this.riskTrendData.xAxisData.length > 0 ? this.riskTrendData.xAxisData : ['2025年1月检查', '2025年2月检查', '2025年3月检查', '2025年4月检查', '2025年5月检查'], |
| | | axisTick: { show: true, alignWithLabel: true }, |
| | | axisLine: { |
| | | lineStyle: { |
| | |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | min: 1, |
| | | max: 3, |
| | | interval: 1, |
| | | splitLine: { |
| | | show: true, |
| | | lineStyle: { |
| | |
| | | color: '#fff', |
| | | fontSize: 12, |
| | | formatter: function (value) { |
| | | // Y轴标签格式化,最多3个字符,超出换行 |
| | | const text = String(value) |
| | | return formatLabel(text, 3) |
| | | // Y轴自定义显示:1->C类, 2->B类, 3->A类 |
| | | if (value === 1) return 'C类'; |
| | | if (value === 2) return 'B类'; |
| | | if (value === 3) return 'A类'; |
| | | return ''; |
| | | }, |
| | | // 文本对齐方式 |
| | | align: 'right', |
| | | verticalAlign: 'middle', |
| | | lineHeight: 14, |
| | | // 设置标签的最大宽度 |
| | | width: 30, |
| | | overflow: 'break' // 超出换行 |
| | | width: 30 |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '风险等级', |
| | | type: 'line', |
| | | data: [10, 52, 20, 33, 39], |
| | | data: this.riskTrendData.seriesData.length > 0 ? this.riskTrendData.seriesData : [10, 52, 20, 33, 39], |
| | | smooth: false, // 不使用圆滑过渡 |
| | | showSymbol: false, // 不显示转折点 |
| | | lineStyle: { |
| | |
| | | method: 'get', params |
| | | }) |
| | | } |
| | | |
| | | // 获取项目风险趋势 |
| | | export const getProjectDangerousTrend = async (params) => { |
| | | return request(`/project/getProjectDangerousTrend`, { |
| | | method: 'post', |
| | | data: params |
| | | }) |
| | | } |