You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

932 lines
27 KiB

4 months ago
<template>
<view class="statistics">
<!-- 行政区划下拉选择卡片 -->
<view class="cc-query-dropdowns">
<picker mode="selector" :range="districts" v-model="selectedDistrict">
<view class="dropdown">
行政区划
<image src="/static/images/icon/down.png" />
</view>
</picker>
</view>
<view class="chart-list">
<!-- <view class="chart-list">
<view class="cc-card card">
<view class="card-header">项目投资统计</view>
<echarts ref="echarts" :option="option" canvasId="echarts"></echarts>
</view> -->
4 months ago
<!-- 项目投资统计柱形图卡片 -->
<view class="cc-card card">
<view class="card-header">项目投资统计</view>
<echarts ref="investmentChart" :option="investmentChartOption" canvasId="investmentChart"></echarts>
<!-- <canvas id="investmentChart"></canvas> -->
4 months ago
</view>
<!-- 项目分类统计柱形图卡片 -->
<view class="cc-card card">
<view class="card-header">项目分类统计</view>
<echarts ref="categoryChart" :option="categoryChartOption" canvasId="categoryChart"></echarts>
<!-- <canvas id="categoryChart"></canvas> -->
4 months ago
</view>
<!-- 项目类型统计饼图卡片 -->
<view class="cc-card card">
<view class="card-header">项目类型统计</view>
<echarts ref="typeChart" :option="typeChartOption" canvasId="typeChart"></echarts>
<!-- <canvas id="typeChart"></canvas> -->
4 months ago
</view>
<!-- 项目状态统计饼图卡片 -->
<view class="cc-card card">
<view class="card-header">项目状态统计</view>
<echarts ref="statusChart" :option="statusChartOption" canvasId="statusChart"></echarts>
<!-- <canvas id="statusChart"></canvas> -->
4 months ago
</view>
<!-- 项目行政区划分布统计饼图卡片 -->
<view class="cc-card card">
<view class="card-header">项目行政区划分布统计</view>
<echarts ref="districtChart" :option="districtChartOption" canvasId="districtChart"></echarts>
<!-- <canvas id="districtChart"></canvas> -->
4 months ago
</view>
<!-- 项目预警统计饼图卡片 -->
<view class="cc-card card">
<view class="card-header">项目预警统计</view>
<echarts ref="warningChart" :option="warningChartOption" canvasId="warningChart"></echarts>
<!-- <canvas id="warningChart"></canvas> -->
4 months ago
</view>
</view>
<!-- 操作按钮 -->
<view class="cc-operation-buttons">
<view class="buttons-group">
<view class="primary-button button" @click="handleGenerateProject()">生成报告</view>
</view>
</view>
</view>
</template>
<script>
// import * as echarts from 'echarts'; // 引入 echarts 库
// import * as echarts from '../../components/echarts-uniapp/echarts.min.js';
4 months ago
import { getSourceFundsNumApi } from '@/api/system/projectStatistics'
4 months ago
export default {
data() {
return {
// 行政区划数据
districts: ['请选择', '北京市', '上海市', '广州市', '深圳市'],
selectedDistrict: 0,
// 图表配置
investmentChartOption: null,
categoryChartOption: null,
typeChartOption: null,
statusChartOption: null,
districtChartOption: null,
warningChartOption: null,
option: {},
// 项目投资统计
projectInvestInfo: [],
sourceFound: {},
adcd: []
4 months ago
};
},
onReady() {
this.option = {
}
},
mounted() {
console.log(123)
this.getProjectInvestData()
},
4 months ago
methods: {
getProjectInvestData() {
getSourceFundsNumApi({ year: '2024' }).then(res => {
this.sourceFound = res.data
this.adcd = Object.keys(this.sourceFound)
this.barInit()
})
},
4 months ago
onDistrictChange(e) {
console.log('选择的行政区划:', this.districts[e.detail.value]);
},
barInit() {
const progressPlanValues = Object.values(this.sourceFound).map(obj => obj.progressPlan);
const actualValues = Object.values(this.sourceFound).map(obj => obj.actual);
const maxProgressPlan = Math.max(...progressPlanValues);
const maxActual = Math.max(...actualValues);
// 过滤掉 undefined 的项,并获取有效数据的索引
const validIndices = this.adcd
.map((item, index) => codeToText[item] ? index : null)
.filter(index => index !== null);
// 根据有效索引过滤 xAxis 数据
const filteredData = this.adcd
.filter((item, index) => validIndices.includes(index))
.map(item => codeToText[item]);
// 根据有效索引过滤 series 数据
const filteredSourceFound = Object.values(this.sourceFound)
.filter((_, index) => validIndices.includes(index));
const indexedSourceFound = filteredSourceFound.map((obj, index) => ({ ...obj, index }));
const indexedActuals = indexedSourceFound.map(obj => obj.actual);
// 根据 actuals 从大到小排序
const sortedByActuals = indexedSourceFound
.map(obj => ({ ...obj, actual: indexedActuals[obj.index] }))
.sort((a, b) => b.actual - a.actual);
// 提取排序后的索引
const sortedIndices = sortedByActuals.map(obj => obj.index);
// 根据排序后的索引重新排列 filteredData 和 filteredSourceFound
const sortedFilteredData = sortedIndices.map(index => filteredData[index]);
const sortedFilteredSourceFound = sortedIndices.map(index => filteredSourceFound[index]);
const progressPlans = sortedFilteredSourceFound.map(obj => obj.progressPlan);
const actuals = sortedFilteredSourceFound.map(obj => obj.actual);
4 months ago
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow', // 使用阴影指示器
},
},
legend: {
data: ['年度计划', '实际完成'],
bottom: '0%', // 将legend显示在下方
itemWidth: 12, // 设置图例正方形的宽度
itemHeight: 12, // 设置图例正方形的高度
itemStyle: {
borderRadius: 0, // 确保图例为正方形
},
},
grid: {
left: '2%',
right: '2%',
top: '13%',
bottom: '15%',
containLabel: true, // 保证标签显示不超出范围
},
xAxis: {
type: 'category',
data: sortedFilteredData,
4 months ago
axisLabel: {
interval: 0, // 确保X轴标签不重叠
rotate: 45, // 旋转X轴标签以适应长文本
},
axisTick: {
alignWithLabel: true,
},
axisLine: {
lineStyle: {
color: '#000',
},
},
boundaryGap: true, // 使得柱状图的起点和终点显示
},
yAxis: {
type: 'value',
name: '金额/万元',
nameLocation: 'end', // 将标题放在轴的起始位置
nameGap: 20, // 设置标题与轴的间距
axisLabel: {
formatter: '{value}',
color: '#8C8C8C', // Y轴字体颜色
fontSize: 12, // Y轴字体大小
},
axisLine: {
lineStyle: {
color: '#8C8C8C',
},
},
splitLine: {
lineStyle: {
color: '#f0f0f0', // 灰色的分割线
},
},
splitNumber: 5, // 控制Y轴的分割数
},
series: [
{
name: '年度计划',
type: 'bar',
data: progressPlans,
4 months ago
barWidth: '35%', // 设置柱状图的宽度
itemStyle: {
color: '#00b39d', // 年度计划的柱状图颜色
},
},
{
name: '实际完成',
type: 'bar',
data: actuals,
4 months ago
barWidth: '35%',
itemStyle: {
color: '#00a7ee', // 实际完成的柱状图颜色
},
},
],
}
this.investmentChartOption = option;
},
// 初始化项目投资统计柱形图
initInvestmentChart() {
// const chart = echarts.init(document.getElementById('investmentChart'));
4 months ago
},
// 初始化项目分类柱形图
initCategoryChart() {
// const chart = echarts.init(document.getElementById('categoryChart'));
4 months ago
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow', // 使用阴影指示器
},
},
legend: {
data: ['重大工程', '面上工程'],
bottom: '0%', // 将legend显示在下方
itemWidth: 12, // 设置图例正方形的宽度
itemHeight: 12, // 设置图例正方形的高度
itemStyle: {
borderRadius: 0, // 确保图例为正方形
},
},
grid: {
left: '2%',
right: '2%',
top: '13%',
bottom: '15%',
containLabel: true, // 保证标签显示不超出范围
},
xAxis: {
type: 'category',
data: ['北京市', '上海市', '广东省', '浙江省', '江苏省', '山东省', '河北省', '河南省', '湖北省', '湖南省'],
axisLabel: {
interval: 0, // 确保X轴标签不重叠
rotate: 45, // 旋转X轴标签以适应长文本
},
axisTick: {
alignWithLabel: true,
},
axisLine: {
lineStyle: {
color: '#000',
},
},
boundaryGap: true, // 使得柱状图的起点和终点显示
},
yAxis: {
type: 'value',
name: '个',
nameLocation: 'end', // 将标题放在轴的起始位置
nameGap: 20, // 设置标题与轴的间距
axisLabel: {
formatter: '{value}',
color: '#8C8C8C', // Y轴字体颜色
fontSize: 12, // Y轴字体大小
},
axisLine: {
lineStyle: {
color: '#8C8C8C'
},
},
splitLine: {
lineStyle: {
color: '#f0f0f0', // 灰色的分割线
},
},
splitNumber: 5, // 控制Y轴的分割数
},
series: [
{
name: '重大工程',
type: 'bar',
data: [120, 200, 150, 80, 70, 110, 95, 130, 115, 100],
barWidth: '35%', // 设置柱状图的宽度
itemStyle: {
color: '#00b39d', // 年度计划的柱状图颜色
},
},
{
name: '面上工程',
type: 'bar',
data: [100, 180, 130, 60, 50, 90, 80, 120, 110, 90],
barWidth: '35%',
itemStyle: {
color: '#00a7ee', // 实际完成的柱状图颜色
},
},
],
};
this.categoryChartOption = option;
// chart.setOption(option);
4 months ago
},
// 初始化项目类型统计饼状图
initTypeChart() {
// const chart = echarts.init(document.getElementById('typeChart'));
4 months ago
const data = [
{
value: 2088,
name: '饮水工程',
itemStyle: {
color: '#00b39d',
},
},
{
value: 1000,
name: '枢纽工程',
itemStyle: {
color: '#0073ee',
},
},
{
value: 1000,
name: '新建水库',
itemStyle: {
color: '#00a7ee',
},
},
{
value: 800,
name: '病险',
itemStyle: {
color: '#00b368',
},
},
{
value: 1000,
name: '灌区',
itemStyle: {
color: '#ecb800',
},
},
{
value: 350,
name: '水保',
itemStyle: {
color: '#ec7000',
},
},
{
value: 350,
name: '其他',
itemStyle: {
color: '#e04040',
},
},
]
// 计算总量
const total = data.reduce((sum, item) => sum + item.value, 0);
const option = {
tooltip: {
trigger: 'item',
show: false, // 去掉提示线
},
legend: {
orient: 'vertical',
right: '5%', // 图例显示在右边
top: '15%', // 调整图例的垂直位置
data: ['饮水工程', '枢纽工程', '新建水库', '病险', '灌区', '水保', '其他'],
itemWidth: 12, // 图例宽度
itemHeight: 12, // 图例高度
itemStyle: {
borderRadius: 0, // 确保图例为正方形
},
formatter: function(name) {
const item = data.find(d => d.name === name);
return `${name} ${item.value}`; // 自定义图例显示内容
}
},
series: [
{
name: '项目类别',
type: 'pie',
center: ['32%', '50%'], // 设置饼图中心位置
radius: ['80%', '60%'], // 设置饼图的内外半径
// avoidLabelOverlap: false,
4 months ago
itemStyle: {
borderRadius: 0,
borderColor: '#fff',
borderWidth: 1,
},
label: {
show: false,
position: 'outside', // 标签在外部显示
formatter: '{b}\n{c} ({d}%)', // 显示标签内容:名称、数值、百分比
},
labelLine: {
show: true,
},
data,
// 设置饼图的厚度
roseType: false, // 确保饼图是圆形
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowOffsetY: 0,
},
},
}
],
// graphic: [
// {
// type: 'text',
// top: '40%',
// left: '28%',
// style: {
// text: '合计', // 显示“合计”
// font: '16px Microsoft YaHei', // 字体样式
// fill: '#333' // 字体颜色
// },
// // 使文本居中
// // textAlign: 'center',
// // textVerticalAlign: 'middle'
// },
// {
// type: 'text',
// top: '53%',
// left: '24%',
// style: {
// text: total, // 显示总量
// font: 'bold 24px Microsoft YaHei', // 字体样式
// fill: '#262626' // 字体颜色
// },
// // 使文本居中
// // textAlign: 'center',
// // textVerticalAlign: 'middle'
// // 使总量文字稍微下移以保持间距
// // silent: true,
// // top: 'center', // 这里可以调整以使其居中
// // style: {
// // textAlign: 'center',
// // textVerticalAlign: 'middle',
// // }
// }
// ]
4 months ago
};
this.typeChartOption = option;
// chart.setOption(option);
4 months ago
},
// 初始化项目状态统计饼状图
initStatusChart() {
// const chart = echarts.init(document.getElementById('statusChart'));
4 months ago
const data = [
{
value: 2088,
name: '施工中',
itemStyle: {
color: '#00b39d',
},
},
{
value: 1000,
name: '已完工',
itemStyle: {
color: '#ec7000',
},
}
]
// 计算总量
const total = data.reduce((sum, item) => sum + item.value, 0);
const option = {
tooltip: {
trigger: 'item',
show: true, // 去掉提示线
},
legend: {
orient: 'horizontal',
left: 'center', // 图例显示在右边
bottom: '0%', // 调整图例的垂直位置
data: ['施工中', '已完工'],
itemWidth: 12, // 图例宽度
itemHeight: 12, // 图例高度
itemStyle: {
borderRadius: 0, // 确保图例为正方形
},
formatter: function(name) {
const item = data.find(d => d.name === name);
return `${name} ${item.value}`; // 自定义图例显示内容
}
},
series: [
{
name: '项目类别',
type: 'pie',
// center: ['50%', '50%'], // 设置饼图中心位置
radius: ['70%', '50%'], // 设置饼图的内外半径
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 0,
borderColor: '#fff',
borderWidth: 1,
},
label: {
show: true,
position: 'outside', // 标签在外部显示
formatter: '{b}{c}', // 显示标签内容:名称、数值、百分比
},
// labelLine: {
// show: true,
// },
data,
// 设置饼图的厚度
roseType: false, // 确保饼图是圆形
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowOffsetY: 0,
},
},
}
],
graphic: [
{
type: 'text',
top: '38%',
left: 'center',
style: {
text: '合计', // 显示“合计”
font: '16px Microsoft YaHei', // 字体样式
fill: '#333' // 字体颜色
},
// 使文本居中
// textAlign: 'center',
// textVerticalAlign: 'middle'
},
{
type: 'text',
top: '53%',
left: 'center',
style: {
text: total, // 显示总量
font: 'bold 24px Microsoft YaHei', // 字体样式
fill: '#262626' // 字体颜色
}
}
]
};
this.statusChartOption = option;
// chart.setOption(option);
4 months ago
},
// 初始化项目行政区划分布统计饼状图
initDistrictChart() {
// const chart = echarts.init(document.getElementById('districtChart'));
4 months ago
const data = [
{
value: 2088,
name: '饮水工程',
itemStyle: {
color: '#00b39d',
},
},
{
value: 1000,
name: '枢纽工程',
itemStyle: {
color: '#0073ee',
},
},
{
value: 1000,
name: '新建水库',
itemStyle: {
color: '#00a7ee',
},
},
{
value: 800,
name: '病险',
itemStyle: {
color: '#00b368',
},
},
{
value: 1000,
name: '灌区',
itemStyle: {
color: '#ecb800',
},
},
{
value: 350,
name: '水保',
itemStyle: {
color: '#ec7000',
},
},
{
value: 350,
name: '其他',
itemStyle: {
color: '#e04040',
},
},
]
// 计算总量
const total = data.reduce((sum, item) => sum + item.value, 0);
const option = {
tooltip: {
trigger: 'item',
show: false, // 去掉提示线
},
legend: {
orient: 'vertical',
right: '5%', // 图例显示在右边
top: '15%', // 调整图例的垂直位置
data: ['饮水工程', '枢纽工程', '新建水库', '病险', '灌区', '水保', '其他'],
itemWidth: 12, // 图例宽度
itemHeight: 12, // 图例高度
itemStyle: {
borderRadius: 0, // 确保图例为正方形
},
formatter: function(name) {
const item = data.find(d => d.name === name);
return `${name} ${item.value}`; // 自定义图例显示内容
}
},
series: [
{
name: '项目类别',
type: 'pie',
center: ['32%', '50%'], // 设置饼图中心位置
radius: ['80%', '60%'], // 设置饼图的内外半径
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 0,
borderColor: '#fff',
borderWidth: 1,
},
label: {
show: false,
position: 'outside', // 标签在外部显示
formatter: '{b}\n{c} ({d}%)', // 显示标签内容:名称、数值、百分比
},
labelLine: {
show: true,
},
data,
// 设置饼图的厚度
roseType: false, // 确保饼图是圆形
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowOffsetY: 0,
},
},
}
],
graphic: [
{
type: 'text',
top: '40%',
left: '28%',
style: {
text: '合计', // 显示“合计”
font: '16px Microsoft YaHei', // 字体样式
fill: '#333' // 字体颜色
},
// 使文本居中
// textAlign: 'center',
// textVerticalAlign: 'middle'
},
{
type: 'text',
top: '53%',
left: '24%',
style: {
text: total, // 显示总量
font: 'bold 24px Microsoft YaHei', // 字体样式
fill: '#262626' // 字体颜色
},
// 使文本居中
// textAlign: 'center',
// textVerticalAlign: 'middle'
// 使总量文字稍微下移以保持间距
// silent: true,
// top: 'center', // 这里可以调整以使其居中
// style: {
// textAlign: 'center',
// textVerticalAlign: 'middle',
// }
}
]
};
this.districtChartOption = option;
// chart.setOption(option);
4 months ago
},
// 初始化项目预警统计饼状图
initWarningChart() {
// const chart = echarts.init(document.getElementById('warningChart'));
4 months ago
const data = [
{
value: 2088,
name: '饮水工程',
itemStyle: {
color: '#00b39d',
},
},
{
value: 1000,
name: '枢纽工程',
itemStyle: {
color: '#0073ee',
},
},
{
value: 1000,
name: '新建水库',
itemStyle: {
color: '#00a7ee',
},
},
{
value: 800,
name: '病险',
itemStyle: {
color: '#00b368',
},
},
{
value: 1000,
name: '灌区',
itemStyle: {
color: '#ecb800',
},
},
{
value: 350,
name: '水保',
itemStyle: {
color: '#ec7000',
},
},
{
value: 350,
name: '其他',
itemStyle: {
color: '#e04040',
},
},
]
// 计算总量
const total = data.reduce((sum, item) => sum + item.value, 0);
const option = {
tooltip: {
trigger: 'item',
show: false, // 去掉提示线
},
legend: {
orient: 'vertical',
right: '5%', // 图例显示在右边
top: '15%', // 调整图例的垂直位置
data: ['饮水工程', '枢纽工程', '新建水库', '病险', '灌区', '水保', '其他'],
itemWidth: 12, // 图例宽度
itemHeight: 12, // 图例高度
itemStyle: {
borderRadius: 0, // 确保图例为正方形
},
formatter: function(name) {
const item = data.find(d => d.name === name);
return `${name} ${item.value}`; // 自定义图例显示内容
}
},
series: [
{
name: '项目类别',
type: 'pie',
center: ['32%', '50%'], // 设置饼图中心位置
radius: ['80%', '60%'], // 设置饼图的内外半径
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 0,
borderColor: '#fff',
borderWidth: 1,
},
label: {
show: false,
position: 'outside', // 标签在外部显示
formatter: '{b}\n{c} ({d}%)', // 显示标签内容:名称、数值、百分比
},
labelLine: {
show: true,
},
data,
// 设置饼图的厚度
roseType: false, // 确保饼图是圆形
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowOffsetY: 0,
},
},
}
],
graphic: [
{
type: 'text',
top: '40%',
left: '28%',
style: {
text: '合计', // 显示“合计”
font: '16px Microsoft YaHei', // 字体样式
fill: '#333' // 字体颜色
},
// 使文本居中
// textAlign: 'center',
// textVerticalAlign: 'middle'
},
{
type: 'text',
top: '53%',
left: '24%',
style: {
text: total, // 显示总量
font: 'bold 24px Microsoft YaHei', // 字体样式
fill: '#262626' // 字体颜色
},
// 使文本居中
// textAlign: 'center',
// textVerticalAlign: 'middle'
// 使总量文字稍微下移以保持间距
// silent: true,
// top: 'center', // 这里可以调整以使其居中
// style: {
// textAlign: 'center',
// textVerticalAlign: 'middle',
// }
}
]
};
this.warningChartOption = option;
// chart.setOption(option);
4 months ago
},
// 跳转到生成报告页
handleGenerateProject() {
this.$tab.navigateTo(`/pages/statistics/generate`);
}
},
// 页面加载完成后,初始化所有图表
mounted() {
this.initInvestmentChart();
this.initCategoryChart();
this.initTypeChart();
this.initStatusChart();
this.initDistrictChart();
this.initWarningChart();
}
};
</script>
<style lang="scss" scoped>
.statistics {
padding-bottom: 80px;
.chart-list {
padding: 16px 20px;
.card {
canvas {
width: 100%;
height: 250px;
}
}
}
}
.card-body {
padding: 20px;
font-size: 16px;
color: #333;
}
.ec-canvas {
height: 300px;
}
</style>