新增页面

This commit is contained in:
2026-01-29 16:47:04 +08:00
parent 5a1fc57019
commit 62db6672f6
15 changed files with 1537 additions and 276 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,87 @@
<template>
<div class="progress-list">
<div class="list-item" v-for="(item, index) in listData" :key="index">
<div class="label">{{ item.label }}</div>
<div class="bar-container">
<div class="bar-bg">
<div class="bar-fill" :style="{ width: (item.value / maxValue * 100) + '%' }">
<span class="value-text">{{ item.value }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed,defineProps,watch } from 'vue'
const props = defineProps({
data: {
type: Array,
default: () => []
}
})
const listData = ref([])
const maxValue = computed(() => {
const max = Math.max(...listData.value.map(item => item.value))
return max > 0 ? max : 100
})
watch(() => props.data, (newVal) => {
listData.value = newVal
},{immediate:true})
</script>
<style scoped lang="scss">
.progress-list {
width: 100%;
height: 100%;
padding: 20px;
box-sizing: border-box;
overflow-y: auto;
.list-item {
width: 98%;
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
.label {
font-size: 14px;
color: #666;
margin-bottom: 8px;
}
.bar-container {
display: flex;
align-items: center;
.bar-bg {
flex: 1;
height: 16px;
background-color: #F5F7FA;
border-radius: 6px;
margin-right: 15px;
.bar-fill {
position: relative;
height: 100%;
border-radius: 6px;
background: linear-gradient(90deg, #FF6B22 0%, #FFC94B 100%);
transition: width 0.5s ease-out;
.value-text {
white-space: nowrap;
position: absolute;
left: 101%;
font-size: 14px;
color: #FF6B22;
font-weight: 500;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,268 @@
<template>
<div class="echratsBox">
<div class="chart-container" ref="echartsRef"></div>
<div class="legend-container">
<div class="legend-item" v-for="(item, index) in chartData" :key="index">
<div class="left-part">
<span class="dot" :style="{ backgroundColor: colors[index] }"></span>
<span class="name">{{ item.name }}</span>
<span class="value">{{ item.value }}</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import * as echarts from 'echarts'
import 'echarts-gl' // Ensure GL is available if needed, though we use custom series for better labels
const echartsRef = ref(null)
const chartData = ref([
{ name: '未签收', value: 18 },
{ name: '已签收', value: 18 },
{ name: '已反馈', value: 18 }
])
const colors = ['#FF4D4F', '#1890FF', '#00E6B8'] // Red, Blue, Cyan/Teal
let myChart = null
onMounted(() => {
initChart()
window.addEventListener('resize', resizeChart)
})
const initChart = () => {
if (!echartsRef.value) return
myChart = echarts.init(echartsRef.value)
const data = chartData.value.map((item, index) => ({
name: item.name,
value: item.value,
itemStyle: {
color: colors[index]
}
}));
const option = getPie3DOptions(data, 0.5);
option.series.push({
name: 'labelPie',
type: 'pie',
radius: ['70%', '85%'],
center: ['45%', '50%'],
label: {
show: false,
},
labelLine: {
show: false,
},
itemStyle: {
opacity: 0 // Invisible slices
},
data: data,
z: 100
});
myChart.setOption(option)
}
// 生成3D饼图的配置
const getPie3DOptions = (pieData, internalRadiusRatio) => {
const series = [];
let sumValue = 0;
let startValue = 0;
let endValue = 0;
const k = internalRadiusRatio || 1 / 3;
for (let i = 0; i < pieData.length; i++) {
sumValue += pieData[i].value;
const seriesItem = {
name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
type: 'surface',
parametric: true,
wireframe: {
show: false
},
pieData: pieData[i],
pieStatus: {
selected: false,
hovered: false,
k: k
},
shading: 'lambert', // Add realistic shading
itemStyle: {
opacity: 1
}
};
if (typeof pieData[i].itemStyle != 'undefined') {
const itemStyle = {};
typeof pieData[i].itemStyle.color != 'undefined' ? itemStyle.color = pieData[i].itemStyle.color : null;
typeof pieData[i].itemStyle.opacity != 'undefined' ? itemStyle.opacity = pieData[i].itemStyle.opacity : null;
seriesItem.itemStyle = { ...seriesItem.itemStyle, ...itemStyle };
}
series.push(seriesItem);
}
for (let i = 0; i < series.length; i++) {
endValue = startValue + series[i].pieData.value;
series[i].pieData.startRatio = startValue / sumValue;
series[i].pieData.endRatio = endValue / sumValue;
series[i].parametricEquation = getParametricEquation(series[i].pieData.startRatio, series[i].pieData.endRatio, false, false, k, series[i].pieData.value);
startValue = endValue;
}
return {
tooltip: {
formatter: params => {
if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'labelPie') {
return `${params.seriesName}<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>${series[params.seriesIndex].pieData.value}`;
}
}
},
xAxis3D: { min: -1, max: 1 },
yAxis3D: { min: -1, max: 1 },
zAxis3D: { min: -1, max: 1 },
grid3D: {
show: false,
boxHeight: 10,
top: '-10%',
light: {
main: {
intensity: 1.2,
shadow: true,
shadowQuality: 'high',
alpha: 40,
beta: -30
},
ambient: {
intensity: 0.5
}
},
viewControl: {
alpha: 30,
beta: 40,
distance: 180,
rotateSensitivity: 1,
zoomSensitivity: 0,
panSensitivity: 0,
autoRotate: false
}
},
series: series
};
}
function getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
const midRatio = (startRatio + endRatio) / 2;
const startRadian = startRatio * Math.PI * 2;
const endRadian = endRatio * Math.PI * 2;
const midRadian = midRatio * Math.PI * 2;
const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
const hoverRate = isHovered ? 1.05 : 1;
return {
u: {
min: -Math.PI,
max: Math.PI * 3,
step: Math.PI / 32
},
v: {
min: 0,
max: Math.PI * 2,
step: Math.PI / 20
},
x: function(u, v) {
if (u < startRadian) {
return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
if (u > endRadian) {
return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
},
y: function(u, v) {
if (u < startRadian) {
return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
if (u > endRadian) {
return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
},
z: function(u, v) {
if (u < -Math.PI * 0.5) {
return Math.sin(u);
}
if (u > Math.PI * 2.5) {
return Math.sin(u);
}
return Math.sin(v) * 1.5;
}
};
}
const resizeChart = () => {
myChart && myChart.resize()
}
</script>
<style scoped lang="scss">
.echratsBox {
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding: 10px;
box-sizing: border-box;
.chart-container {
flex: 1.5; // Give more space to chart
height: 100%;
min-height: 200px;
}
.legend-container {
flex: 0.8;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 20px;
.legend-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
border-bottom: 1px dashed #E0E0E0;
&:first-child {
border-top: 1px dashed #E0E0E0;
}
.left-part {
display: flex;
align-items: center;
.dot {
width: 12px;
height: 6px;
border-radius: 2px;
margin-right: 10px;
transform: skewX(-20deg);
}
.name {
font-size: 14px;
color: #666;
}
.value {
font-size: 14px;
color: #333;
font-weight: 500;
margin-left: 5px;
}
}
}
}
}
</style>

View File

@ -0,0 +1,100 @@
<template>
<div class="top-head">
<el-form :inline="true" :model="formSearch" class="form-search">
<el-form-item label="选择部门">
<MOSTY.Department clearable v-model="formSearch.ssbmdm" />
</el-form-item>
<el-form-item label="">
<div class="filter-section">
<el-radio-group v-model="radioTime" @change="changeRadio">
<el-radio v-for="(it,idx) in timeList" :key="idx" :label="it.num" >{{ it.label }}</el-radio>
</el-radio-group>
<span class="ml5 mr5">自定义</span>
<el-date-picker @change="handleDateChange" v-model="formSearch.dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit">查询</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { timeValidate, timeSlotChange } from "@/utils/tools.js";
import * as MOSTY from "@/components/MyComponents/index";
import { ref,defineEmits } from "vue";
const emit = defineEmits(['change'])
const timeList = ref([
{ label: "日", num: 0 },
{ label: "月", num: 1 },
{ label: "季", num: 2 },
{ label: "年", num: 3 }
]);
const radioTime = ref('')
const formSearch = ref({})
// 单选
const changeRadio = (val) =>{
switch(val){
case 0: //日
formSearch.value.dateRange = [timeValidate(),timeValidate()]
break;
case 1: //月
formSearch.value.dateRange = timeSlotChange('本月')
break;
case 2: //季度
formSearch.value.dateRange = timeSlotChange('本季度')
break;
case 3: //年
formSearch.value.dateRange = timeSlotChange('本年')
break;
}
}
// 自定义
const handleDateChange = (val) => {
radioTime.value = '';
if(val[0] == timeSlotChange('天')[0] && val[1] == timeSlotChange('天')[1]) radioTime.value = 0;
if(val[0] == timeSlotChange('本月')[0] && val[1] == timeSlotChange('本月')[1]) radioTime.value = 1;
if(val[0] == timeSlotChange('本季度')[0] && val[1] == timeSlotChange('本季度')[1]) radioTime.value = 2;
if(val[0] == timeSlotChange('本年')[0] && val[1] == timeSlotChange('本年')[1]) radioTime.value = 3;
};
// 查询
const handleSubmit = () => {
emit('change', formSearch.value)
}
// 重置
const resetForm = () => {
radioTime.value = '';
formSearch.value = { ssbmdm: '', dateRange: null }
emit('change', formSearch.value)
}
</script>
<style scoped lang="scss">
.top-head {
background-color: #fff;
font-size: 16px;
color: #333;
padding: 10px 10px 0;
box-sizing: border-box;
border-radius: 4px;
.filter-section {
display: flex;
align-items: center;
gap: 16px;
background: #fff;
border-radius: 4px;
::v-deep .el-radio{
--el-radio-input-border-radius: 10%;
}
::v-deep .el-radio__label{
color: #333;
}
}
}
</style>

View File

@ -0,0 +1,165 @@
<template>
<div class="echratsBox">
<div class="chart-container" :id="props.id"></div>
<div class="legend-container">
<div class="legend-item" v-for="(item, i) in legendList" :key="i">
<span class="dot" :style="{ background: item.dotColor }"></span>
<span class="name">{{ item.name }}</span>
<span class="value">{{ item.value }}</span>
<span class="label">占比</span>
<span class="percent">{{ item.percent }}%</span>
</div>
</div>
</div>
</template>
<script setup>
import { nextTick, ref ,defineProps,watch} from 'vue'
import * as echarts from 'echarts'
const props = defineProps({
data: {
type: Array,
default: () => [
{ name: '失控', value: 85 ,color: '#D66A8D'},
{ name: '在控', value: 55 ,color: '#17C0AE'},
]
},
id: {
type: String,
default: 'echartsRef'
}
})
const legendList = ref([])
watch(() => props.data, (newVal) => {
console.log(newVal,'-------------监听');
if (newVal.length) {
const total = newVal.reduce((s, v) => s + v.value, 0);
legendList.value = newVal.map((d, i) => ({
name: d.name,
value: 20,
percent: Math.round((d.value / total )* 100),
dotColor: i === 0 ? 'linear-gradient(90deg, #FF8DA7 0%, #D66A8D 100%)': d.color
}))
nextTick(() => {
initChart(newVal, total)
})
}
}, { immediate: true })
const initChart = (data, total) => {
let chart = echarts.init(document.getElementById(props.id))
if (!chart) return;
const seriesData = data.map((d) => ({
name: d.name,
value: d.value,
itemStyle: { color: d.color }
}))
const option = {
tooltip: { show: false },
legend: { show: false },
series: [
{
type: 'pie',
radius: ['50%', '78%'],
center: ['50%', '48%'],
startAngle:56,
roseType: 'radius',
label: { show: false },
labelLine: { show: false },
itemStyle: { borderColor: '#FFFFFF', borderWidth: 0 },
data: seriesData
}
],
graphic: [
{
type: 'text',
left: 'center',
top: '32%',
style: {
text: `${total}`,
fill: '#2F88FF',
fontSize: 24,
fontWeight: 700,
textAlign: 'center'
}
},
{
type: 'text',
left: 'center',
top: '52%',
style: {
text: '总数',
fill: '#666666',
fontSize: 14,
fontWeight: 400,
textAlign: 'center'
}
}
]
}
chart.setOption(option)
window.addEventListener('resize', () => chart.resize())
}
</script>
<style scoped lang="scss">
.echratsBox {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px 0;
box-sizing: border-box;
.chart-container {
width: 100%;
height: 180px;
}
.legend-container {
margin-top: 0;
display: flex;
gap: 20px;
align-items: center;
justify-content: center;
flex-shrink: 0;
.legend-item {
display: flex;
align-items: center;
font-size: 14px;
color: #666666;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.08) inset;
}
.name {
margin-right: 8px;
}
.value {
margin-right: 8px;
color: #333333;
font-weight: 500;
}
.label {
margin-right: 4px;
color: #666666;
}
.percent {
color: #2F88FF;
font-weight: 600;
}
}
}
</style>

View File

@ -1,282 +1,32 @@
<template> <template>
<div class="statistical-analysis"> <div>
<!-- 左侧树形菜单 --> <PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<div class="left-menu"> <template #left>
<!-- 这个部分用的是组件-后期替换 --> <el-button v-for="(item,index) in butList" :key="index" :type="qh == item ? 'primary' : 'default'" @click="qh = item" size="small">{{item}}</el-button>
<MOSTY.DepartmentTree width="310px" @change="init" placeholder="管理部门" clearable filterable :isBmId="false" </template>
v-model="listQuery.ssbmdm" /> </PageTitle>
</div> <div class="countBox">
<QbtjCount v-if="qh=='情报统计分析'" />
<!-- 右侧内容区 --> <YjCount v-if="qh=='预警统计'" />
<div class="right-content"> <QygktjCount v-if="qh=='全域管控统计'" />
<!-- 顶部筛选 --> <XxhjCount v-if="qh=='信息汇聚统计'" />
<div class="filter-section">
<el-radio-group v-model="radio" @change="changeRadio">
<el-radio v-for="(it, idx) in timeList" :key="idx" :label="it.num">{{ it.label }}</el-radio>
</el-radio-group>
<el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
end-placeholder="结束日期" format="YYYY-MM-DD" value-format="YYYY-MM-DD" @change="handleDateChange" />
<el-button type="primary" @click="init">查询</el-button>
<el-button type="primary" @click="handleRest">重置</el-button>
</div>
<!-- 统计图表区域 -->
<div class="charts-container">
<div class="chart-item">
<div class="chart-title">
<span>信息分组统计</span>
<!-- <el-button type="primary">导出统计表</el-button> -->
</div>
<div class="chart">
<PieEcharts echartsId="pieChart" color="#333" :data="obj.xsfzList" />
</div>
</div>
<div class="chart-item">
<div class="chart-title">
<span>预警等级统计</span>
<!-- <el-button type="primary">导出统计表</el-button> -->
</div>
<div class="chart">
<!-- {{ obj.yjdjList }} -->
<DbarEcharts echartsId="bar3DChart" :data="obj.yjdjList" />
</div>
</div>
<div class="chart-item">
<div class="chart-title">
<span>线索来源统计</span>
<!-- <el-button type="primary">导出统计表</el-button> -->
</div>
<ul class="chart mt8">
<li v-for="(it, idx) in obj.xslyList" :key="idx" class="mb6">
<div style="color: #333">{{ it.label }}</div>
<el-progress :text-inside="true" :stroke-width="20" :percentage="calculatePercentage(it.value)"
status="exception">
<span><span style="color: #e37233">{{ it.value }}</span> </span>
</el-progress>
</li>
</ul>
</div>
<div class="chart-item">
<div class="chart-title">
<span>研判统计</span>
<!-- <el-button type="primary">导出统计表</el-button> -->
</div>
<DbarEcharts echartsId="bar3DCharts" :data="obj.ypList" />
<!-- <lineEcharts color="#333" echartsId="areaChart" :data="obj.ypList" /> -->
</div>
</div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { timeValidate, timeSlotChange } from "@/utils/tools.js"; import PageTitle from "@/components/aboutTable/PageTitle.vue";
import * as MOSTY from "@/components/MyComponents/index"; import QbtjCount from './qbtjCount.vue'
import lineEcharts from "@/views/home/echarts/lineEcharts.vue"; import YjCount from './yjCount.vue'
import PieEcharts from "@/views/home/echarts/pieEcharts.vue"; import XxhjCount from './xxhjCount.vue'
import DbarEcharts from "@/views/home/echarts/3DbarEcharts.vue"; import QygktjCount from './qygktjCount.vue'
import { qcckPost, qcckGet } from "@/api/qcckApi.js"; import { ref } from "vue";
import { reactive, ref, onMounted } from "vue"; const butList=ref(["情报统计分析","预警统计",'全域管控统计','信息汇聚统计'])
const qh = ref('情报统计分析')
const dateRange = ref([timeValidate(new Date(), 'ymd'), timeValidate(new Date(), 'ymd')]);// 日期范围
const radio = ref(0); //当天
const timeList = ref([
{ label: "日", num: 0 },
{ label: "月", num: 1 },
{ label: "季", num: 2 },
{ label: "年", num: 3 }
]);
const listQuery = ref({})
const obj = reactive({
xsfzList: [],// 线索采集统计
xslyList: [],// 线索专题统计
ypList: {
list: [],//线索来源统计
topColor: '#1bd6c2',
colors: ["#28EEBF", "#0DBAC5"],
},
yjdjList: {
list: [],//线索来源统计
topColor: '#1bd6c2',
colors: ["#28EEBF", "#0DBAC5"],
}
});
onMounted(() => {
init() //初始化数据
});
const init = () => {
console.log(dateRange.value);
let data = {
ssbmdm: listQuery.value.ssbmdm,
startTime: dateRange.value[0]+' 00:00:00',
endTime: dateRange.value[1] + ' 23:59:59',
}
// 线索分组统计
qcckGet(data, '/mosty-gsxt/xxcj/xxfztj').then(res => {
let arr = res || [];
obj.xsfzList = arr.map(v => {
return { label: v.label, value: v.sl }
})
})
//研判统计
qcckGet(data, '/mosty-gsxt/ypbg/sjzl/yptj').then(res => {
let arr = res || [];
obj.ypList.list = arr.map(v => {
return { label: v.label, value: v.sl }
})
})
//线索来源统计
qcckPost(data, '/mosty-gsxt/qbcj/getXscjTjByQbly').then(res => {
let arr = res || [];
obj.xslyList = arr.map(v => {
return { label: v.zdmc, value: v.count }
})
})
//预警等级
const yjdjList = [
{ label: '红色预警', key: '01', count: 0 },
{ label: '橙色预警', key: '02', count: 0 },
{ label: '黄色预警', key: '03', count: 0 },
{ label: '蓝色预警', key: '04', count: 0 },
]
// 预警等级统计
qcckGet({ssbmdm:data.ssbmdm,kssj:data.startTime,jssj:data.endTime}, '/mosty-gsxt/tbYjxx/getYjxxTj').then(res => {
let arr = res || [];
obj.yjdjList.list = yjdjList.map(items => {
const index= arr.findIndex(item=>item.yj_jb===items.key);
return {
label: items.label,
value:index==-1?0:arr[index].count
}
})
})
}
const changeRadio = (val) => {
switch (val) {
case 0: //日
dateRange.value = timeSlotChange('日')
// [timeValidate(), timeValidate()]
break;
case 1: //月
dateRange.value = timeSlotChange('本月')
break;
case 2: //季度
dateRange.value = timeSlotChange('本季度')
break;
case 3: //年
dateRange.value = timeSlotChange('本年')
break;
}
}
const handleDateChange = (val) => {
radio.value = '';
if (val[0] == timeSlotChange('天')[0] && val[1] == timeSlotChange('天')[1]) radio.value = 0;
if (val[0] == timeSlotChange('本月')[0] && val[1] == timeSlotChange('本月')[1]) radio.value = 1;
if (val[0] == timeSlotChange('本季度')[0] && val[1] == timeSlotChange('本季度')[1]) radio.value = 2;
if (val[0] == timeSlotChange('本年')[0] && val[1] == timeSlotChange('本年')[1]) radio.value = 3;
};
// 重置
const handleRest = () => {
radio.value = 0;
dateRange.value = [timeValidate(), timeValidate()];
init();
};
// 计算百分比
const calculatePercentage = (value) => {
if (!obj.xslyList || obj.xslyList.length === 0) return 0;
const total = obj.xslyList.reduce((sum, item) => sum + (item.value || 0), 0);
if (total === 0) return 0;
return Math.round((value / total) * 100);
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.statistical-analysis { .countBox {
display: flex; height: calc(100vh - 180px);
height: 100%; border-radius: 4px;
.left-menu {
width: 350px;
padding: 20px;
margin-top: 20px;
border-radius: 4px;
background-color: #fff;
border-right: 1px solid #e8e8e8;
}
.right-content {
flex: 1;
padding: 20px;
.filter-section {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 20px;
background: #fff;
padding: 10px;
box-sizing: border-box;
border-radius: 4px;
}
.charts-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
height: calc(100% - 50px);
.chart-item {
width: 49.5%;
height: calc(50% - 5px);
background-color: #fff;
border-radius: 8px;
padding: 20px;
box-sizing: border-box;
overflow: hidden;
overflow-y: auto;
.chart-title {
font-size: 16px;
font-weight: bold;
color: #333;
display: flex;
justify-content: space-between;
align-items: center;
}
.chart {
height: calc(100% - 40px);
overflow: hidden;
overflow-y: auto;
}
}
}
}
::v-deep .el-radio {
color: #333;
}
::v-deep .el-radio__inner {
border-radius: 4px;
}
::v-deep .el-progress-bar__innerText {
color: #333;
margin: 0 -40px;
}
::v-deep .el-progress.is-exception .el-progress-bar__inner {
background: linear-gradient(90deg, #fe5d00 0%, #face35 100%);
}
} }
</style> </style>

View File

@ -0,0 +1,280 @@
<template>
<div class="statistical-analysis">
<!-- 左侧树形菜单 -->
<div class="left-menu">
<!-- 这个部分用的是组件-后期替换 -->
<MOSTY.DepartmentTree width="310px" @change="init" placeholder="管理部门" clearable filterable :isBmId="false"
v-model="listQuery.ssbmdm" />
</div>
<!-- 右侧内容区 -->
<div class="right-content">
<!-- 顶部筛选 -->
<div class="filter-section">
<el-radio-group v-model="radio" @change="changeRadio">
<el-radio v-for="(it, idx) in timeList" :key="idx" :label="it.num">{{ it.label }}</el-radio>
</el-radio-group>
<el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
end-placeholder="结束日期" format="YYYY-MM-DD" value-format="YYYY-MM-DD" @change="handleDateChange" />
<el-button type="primary" @click="init">查询</el-button>
<el-button type="primary" @click="handleRest">重置</el-button>
</div>
<!-- 统计图表区域 -->
<div class="charts-container">
<div class="chart-item">
<div class="chart-title">
<span>信息分组统计</span>
<!-- <el-button type="primary">导出统计表</el-button> -->
</div>
<div class="chart">
<PieEcharts echartsId="pieChart" color="#333" :data="obj.xsfzList" />
</div>
</div>
<div class="chart-item">
<div class="chart-title">
<span>预警等级统计</span>
<!-- <el-button type="primary">导出统计表</el-button> -->
</div>
<div class="chart">
<!-- {{ obj.yjdjList }} -->
<DbarEcharts echartsId="bar3DChart" :data="obj.yjdjList" />
</div>
</div>
<div class="chart-item">
<div class="chart-title">
<span>线索来源统计</span>
<!-- <el-button type="primary">导出统计表</el-button> -->
</div>
<ul class="chart mt8">
<li v-for="(it, idx) in obj.xslyList" :key="idx" class="mb6">
<div style="color: #333">{{ it.label }}</div>
<el-progress :text-inside="true" :stroke-width="20" :percentage="calculatePercentage(it.value)"
status="exception">
<span><span style="color: #e37233">{{ it.value }}</span> </span>
</el-progress>
</li>
</ul>
</div>
<div class="chart-item">
<div class="chart-title">
<span>研判统计</span>
<!-- <el-button type="primary">导出统计表</el-button> -->
</div>
<DbarEcharts echartsId="bar3DCharts" :data="obj.ypList" />
<!-- <lineEcharts color="#333" echartsId="areaChart" :data="obj.ypList" /> -->
</div>
</div>
</div>
</div>
</template>
<script setup>
import { timeValidate, timeSlotChange } from "@/utils/tools.js";
import * as MOSTY from "@/components/MyComponents/index";
import lineEcharts from "@/views/home/echarts/lineEcharts.vue";
import PieEcharts from "@/views/home/echarts/pieEcharts.vue";
import DbarEcharts from "@/views/home/echarts/3DbarEcharts.vue";
import { qcckPost, qcckGet } from "@/api/qcckApi.js";
import { reactive, ref, onMounted } from "vue";
const dateRange = ref([timeValidate(new Date(), 'ymd'), timeValidate(new Date(), 'ymd')]);// 日期范围
const radio = ref(0); //当天
const timeList = ref([
{ label: "日", num: 0 },
{ label: "月", num: 1 },
{ label: "季", num: 2 },
{ label: "年", num: 3 }
]);
const listQuery = ref({})
const obj = reactive({
xsfzList: [],// 线索采集统计
xslyList: [],// 线索专题统计
ypList: {
list: [],//线索来源统计
topColor: '#1bd6c2',
colors: ["#28EEBF", "#0DBAC5"],
},
yjdjList: {
list: [],//线索来源统计
topColor: '#1bd6c2',
colors: ["#28EEBF", "#0DBAC5"],
}
});
onMounted(() => {
init() //初始化数据
});
const init = () => {
console.log(dateRange.value);
let data = {
ssbmdm: listQuery.value.ssbmdm,
startTime: dateRange.value[0]+' 00:00:00',
endTime: dateRange.value[1] + ' 23:59:59',
}
// 线索分组统计
qcckGet(data, '/mosty-gsxt/xxcj/xxfztj').then(res => {
let arr = res || [];
obj.xsfzList = arr.map(v => {
return { label: v.label, value: v.sl }
})
})
//研判统计
qcckGet(data, '/mosty-gsxt/ypbg/sjzl/yptj').then(res => {
let arr = res || [];
obj.ypList.list = arr.map(v => {
return { label: v.label, value: v.sl }
})
})
//线索来源统计
qcckPost(data, '/mosty-gsxt/qbcj/getXscjTjByQbly').then(res => {
let arr = res || [];
obj.xslyList = arr.map(v => {
return { label: v.zdmc, value: v.count }
})
})
//预警等级
const yjdjList = [
{ label: '红色预警', key: '01', count: 0 },
{ label: '橙色预警', key: '02', count: 0 },
{ label: '黄色预警', key: '03', count: 0 },
{ label: '蓝色预警', key: '04', count: 0 },
]
// 预警等级统计
qcckGet({ssbmdm:data.ssbmdm,kssj:data.startTime,jssj:data.endTime}, '/mosty-gsxt/tbYjxx/getYjxxTj').then(res => {
let arr = res || [];
obj.yjdjList.list = yjdjList.map(items => {
const index= arr.findIndex(item=>item.yj_jb===items.key);
return {
label: items.label,
value:index==-1?0:arr[index].count
}
})
})
}
const changeRadio = (val) => {
switch (val) {
case 0: //日
dateRange.value = timeSlotChange('日')
// [timeValidate(), timeValidate()]
break;
case 1: //月
dateRange.value = timeSlotChange('本月')
break;
case 2: //季度
dateRange.value = timeSlotChange('本季度')
break;
case 3: //年
dateRange.value = timeSlotChange('本年')
break;
}
}
const handleDateChange = (val) => {
radio.value = '';
if (val[0] == timeSlotChange('天')[0] && val[1] == timeSlotChange('天')[1]) radio.value = 0;
if (val[0] == timeSlotChange('本月')[0] && val[1] == timeSlotChange('本月')[1]) radio.value = 1;
if (val[0] == timeSlotChange('本季度')[0] && val[1] == timeSlotChange('本季度')[1]) radio.value = 2;
if (val[0] == timeSlotChange('本年')[0] && val[1] == timeSlotChange('本年')[1]) radio.value = 3;
};
// 重置
const handleRest = () => {
radio.value = 0;
dateRange.value = [timeValidate(), timeValidate()];
init();
};
// 计算百分比
const calculatePercentage = (value) => {
if (!obj.xslyList || obj.xslyList.length === 0) return 0;
const total = obj.xslyList.reduce((sum, item) => sum + (item.value || 0), 0);
if (total === 0) return 0;
return Math.round((value / total) * 100);
};
</script>
<style lang="scss" scoped>
.statistical-analysis {
display: flex;
height: 100%;
.left-menu {
width: 350px;
padding: 20px;
border-radius: 4px;
background-color: #fff;
border-right: 1px solid #e8e8e8;
}
.right-content {
flex: 1;
padding: 0 20px 20px;
height: 100%;
.filter-section {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 20px;
background: #fff;
padding: 10px;
box-sizing: border-box;
border-radius: 4px;
}
.charts-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
height: calc(100% - 50px);
.chart-item {
width: 49.5%;
height: calc(50% - 5px);
background-color: #fff;
border-radius: 8px;
padding: 20px;
box-sizing: border-box;
overflow: hidden;
overflow-y: auto;
.chart-title {
font-size: 16px;
font-weight: bold;
color: #333;
display: flex;
justify-content: space-between;
align-items: center;
}
.chart {
height: calc(100% - 40px);
overflow: hidden;
overflow-y: auto;
}
}
}
}
::v-deep .el-radio {
color: #333;
}
::v-deep .el-radio__inner {
border-radius: 4px;
}
::v-deep .el-progress-bar__innerText {
color: #333;
margin: 0 -40px;
}
::v-deep .el-progress.is-exception .el-progress-bar__inner {
background: linear-gradient(90deg, #fe5d00 0%, #face35 100%);
}
}
</style>

View File

@ -0,0 +1,161 @@
<template>
<div class="countBox">
<div ref="searchRef">
<HeadLayout @change="handleChange" />
</div>
<ul class="cntBox" :style="{ height: boxHeight + 'px'}">
<li class="cnt-item">
<div class="common-title">
<div class="title">人员来源统计</div>
</div>
<div class="echratsBox">
<DbarEcharts echartsId="bar35DChart" :key="ketcount" :data="obj.rylyList" />
</div>
</li>
<li class="cnt-item">
<div class="common-title">
<div class="title">管控状态统计</div>
</div>
<div class="echratsBox">
<StatusCount :data="obj.gkztList" id="gkztCount" />
</div>
</li>
<li class="cnt-item">
<div class="common-title">
<div class="title">各类标签管控数量统计</div>
</div>
<div class="echratsBox"><BqyjslCount :data="obj.bqgkslList"/></div>
</li>
<li class="cnt-item">
<div class="common-title">
<div class="title">各部门管控数量统计</div>
</div>
<div class="echratsBox">
<DbarEcharts echartsId="bardepDChart" :key="ketcount" :data="obj.gbmgkList" />
</div>
</li>
</ul>
</div>
</template>
<script setup>
import * as echarts from 'echarts'
import HeadLayout from './components/headLayout.vue'
import BqyjslCount from './components/bqyjslCount.vue'
import StatusCount from './components/statusCount.vue'
import DbarEcharts from "@/views/home/echarts/3DbarEcharts.vue";
import { onMounted, reactive, ref } from "vue";
const searchRef = ref() //筛选组件实例
const boxHeight = ref() //盒子高度
const formSearch = ref({}) //查询条件
const ketcount = ref(0)
const obj = reactive({
gkztList: [
{ name: '失控', value: 85 ,color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [{ offset: 0, color: '#FF8DA7' },{ offset: 1, color: '#D66A8D' }])},
{ name: '在控', value: 55 ,color: '#17C0AE'},
],//管控状态统计
bqgkslList: [
{ label: '涉兼爆炸等恐怖袭击人员', value: 100 },
{ label: '全国涉稳重点人', value: 80 },
{ label: '国保涉稳人员', value: 70 },
{ label: '涉政涉恐涉稳重点人员', value: 60 },
{ label: '区涉稳人员', value: 50 },
],//各类标签预警数量统计
sevenList: [
{ label:'涉恐',value:30 },
{ label:'涉暴',value:20 },
{ label:'涉恐暴',value:10 },
{ label:'涉睡',value:30 },
{ label:'涉睡暴',value:20 },
{ label:'涉睡恐',value:10 },
{ label:'涉睡恐暴',value:5 },
],//7类重点人员预警统计
rylyList: {
list: [
{ label:'基础库',value:50 },
{ label:'重点库',value:40 },
{ label:'关注库',value:10 },
{ label:'重点群体',value:50 },
{ label:'重点车辆',value:40 },
],
topColor:'#17c8c3',
colors: ["#28EEBF","#0DBAC5"],
},//人员来源统计
gbmgkList: {
list: [
{ label:'国家保',value:100 },
{ label:'省保',value:80 },
{ label:'市保',value:70 },
{ label:'区保',value:60 },
{ label:'其他保',value:50 },
],
topColor:'#17c8c3',
colors: ["#28EEBF","#0DBAC5"],
},//各部门管控数量统计
})
onMounted(()=>{
tabHeightFn()
})
// 筛选
const handleChange = (val) => {
formSearch.value = val
}
// 表格高度计算
const tabHeightFn = () => {
boxHeight.value = window.innerHeight - searchRef.value.offsetHeight - 200;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style lang="scss" scoped>
.countBox {
height: 100%;
border-radius: 4px;
.cntBox{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-content: space-between;
margin-top: 10px;
overflow: hidden;
.cnt-item{
width: 49.8%;
height: 49.5%;
background: #fff;
border-radius: 4px;
.common-title {
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 20px;
box-sizing: border-box;
.title {
font-size: 14px;
font-weight: 600;
color: #333;
position: relative;
&::after {
content: '';
position: absolute;
left: 0;
bottom: -1px;
width: 80px;
height: 4px;
background: linear-gradient(to right, #409EFF, #ffffff);
}
}
}
.echratsBox{
height: calc(100% - 40px);
overflow: hidden;
}
}
}
}
</style>

View File

@ -0,0 +1,153 @@
<template>
<div class="countBox">
<div ref="searchRef">
<HeadLayout @change="handleChange" />
</div>
<ul class="cntBox" :style="{ height: boxHeight + 'px'}">
<li class="cnt-item">
<div class="common-title">
<div class="title">采用情况统计</div>
</div>
<div class="echratsBox">
<StatusCount :data="obj.cyqkList" id="cyqkCount" />
</div>
</li>
<li class="cnt-item">
<div class="common-title">
<div class="title">分组统计</div>
</div>
<div class="echratsBox">
<StatusCount :data="obj.fzList" id="fzCount" />
</div>
</li>
<li class="cnt-item">
<div class="common-title">
<div class="title">状态统计</div>
</div>
<div class="echratsBox">
<StatusCount :data="obj.ztList" id="ztCount" />
</div>
</li>
<li class="cnt-item cnt-item-last">
<div class="common-title">
<div class="title">各部门管控数量统计</div>
</div>
<div class="echratsBox">
<DbarEcharts echartsId="bardepDChart" :key="ketcount" :data="obj.bqList" />
</div>
</li>
</ul>
</div>
</template>
<script setup>
import * as echarts from 'echarts'
import HeadLayout from './components/headLayout.vue'
import StatusCount from './components/statusCount.vue'
import DbarEcharts from "@/views/home/echarts/3DbarEcharts.vue";
import { onMounted, reactive, ref } from "vue";
const searchRef = ref() //筛选组件实例
const boxHeight = ref() //盒子高度
const formSearch = ref({}) //查询条件
const ketcount = ref(0)
const obj = reactive({
cyqkList: [
{ name:'采纳',value:30,color:'#0dbac5' },
{ name:'退回',value:20,color:'#ff7700' },
],
fzList: [
{ name:'内部',value:30,color:'#fdbc3a' },
{ name:'共享',value:20,color:'#ff7700' },
],
ztList: [
{ name: '送审', value: 85 ,color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [{ offset: 0, color: '#FF8DA7' },{ offset: 1, color: '#D66A8D' }])},
{ name: '转线索', value: 55 ,color: '#17C0AE'},
],
bqList: {
list: [
{ label:'肇事肇祸',value:100 },
{ label:'涉稳人员',value:80 },
{ label:'前科人员',value:70 },
{ label:'肇事肇祸',value:100 },
{ label:'涉稳人员',value:80 },
{ label:'前科人员',value:70 },
{ label:'肇事肇祸',value:100 },
{ label:'涉稳人员',value:80 },
{ label:'前科人员',value:70 },
{ label:'肇事肇祸',value:100 },
{ label:'涉稳人员',value:80 },
{ label:'前科人员',value:70 },
],
topColor:'#17c8c3',
colors: ["#28EEBF","#0DBAC5"],
},//各部门管控数量统计
})
onMounted(()=>{
tabHeightFn()
})
// 筛选
const handleChange = (val) => {
formSearch.value = val
}
// 表格高度计算
const tabHeightFn = () => {
boxHeight.value = window.innerHeight - searchRef.value.offsetHeight - 200;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style lang="scss" scoped>
.countBox {
height: 100%;
border-radius: 4px;
.cntBox{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-content: space-between;
margin-top: 10px;
overflow: hidden;
.cnt-item{
width: 33%;
height: 49.5%;
background: #fff;
border-radius: 4px;
.common-title {
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 20px;
box-sizing: border-box;
.title {
font-size: 14px;
font-weight: 600;
color: #333;
position: relative;
&::after {
content: '';
position: absolute;
left: 0;
bottom: -1px;
width: 80px;
height: 4px;
background: linear-gradient(to right, #409EFF, #ffffff);
}
}
}
.echratsBox{
height: calc(100% - 40px);
overflow: hidden;
}
}
.cnt-item-last{
width: 100%;
}
}
}
</style>

View File

@ -0,0 +1,298 @@
<template>
<div class="countBox">
<div ref="searchRef">
<HeadLayout @change="handleChange" />
</div>
<ul class="countItem">
<li v-for="(item, index) in countList" :key="index" class="item">
<div class="left">
<img :src="item.icon" alt="" class="icon-img">
</div>
<div class="center">
<div class="label">{{ item.label }}</div>
<div class="value">{{ item.value }}</div>
</div>
<div class="divider"></div>
<div class="right">
<div class="stat-row">
<span class="stat-label">环比</span>
<span class="stat-val up">{{ item.hb }} <el-icon><CaretTop /></el-icon></span>
</div>
<div class="stat-row">
<span class="stat-label">同比</span>
<span class="stat-val down">{{ item.tb }} <el-icon><CaretBottom /></el-icon></span>
</div>
</div>
</li>
</ul>
<ul class="cntBox" :style="{ height: boxHeight + 'px'}">
<li class="cnt-item">
<div class="common-title">
<div class="title">各部门预警数量统计</div>
<div class="btn-group">
<div class="btn" :class="{ active: activeTab === '县局' }" @click="activeTab = '县局'">县局</div>
<div class="btn" :class="{ active: activeTab === '派出所' }" @click="activeTab = '派出所'">派出所</div>
</div>
</div>
<div class="echratsBox">
<DbarEcharts echartsId="bar3DChart" :key="ketcount" :data="obj.cnList" />
</div>
</li>
<li class="cnt-item">
<div class="common-title">
<div class="title">各类标签预警数量统计</div>
</div>
<div class="echratsBox"><BqyjslCount :data="obj.bqyjslList" /></div>
</li>
<li class="cnt-item">
<div class="common-title">
<div class="title">7类重点人员预警统计</div>
</div>
<div class="echratsBox">
<LineEcharts echartsId="seventTypeChart" color="#333333" :data="obj.sevenList" />
</div>
</li>
<li class="cnt-item">
<div class="common-title">
<div class="title">处置状态统计</div>
</div>
<div class="echratsBox"><CzztCount /></div>
</li>
</ul>
</div>
</template>
<script setup>
import HeadLayout from './components/headLayout.vue'
import BqyjslCount from './components/bqyjslCount.vue'
import CzztCount from './components/czztCount.vue'
import DbarEcharts from "@/views/home/echarts/3DbarEcharts.vue";
import LineEcharts from "@/views/home/echarts/lineEcharts.vue";
import { onMounted, reactive, ref } from "vue";
import { CaretTop, CaretBottom } from '@element-plus/icons-vue'
const searchRef = ref() //筛选组件实例
const boxHeight = ref() //盒子高度
const formSearch = ref({}) //查询条件
const activeTab = ref('县局')
const ketcount = ref(0)
const countList = ref([
{ label: '红色预警', value: '123,4', hb: '106,3', tb: '106,3', icon: require('@/assets/images/icon-red.png') },
{ label: '橙色预警', value: '123,4', hb: '106,3', tb: '106,3', icon: require('@/assets/images/icon-orange.png') },
{ label: '黄色预警', value: '123,4', hb: '106,3', tb: '106,3', icon: require('@/assets/images/icon-yellow.png') },
{ label: '蓝色预警', value: '123,4', hb: '106,3', tb: '106,3', icon: require('@/assets/images/icon-blue.png') },
])
const obj = reactive({
bqyjslList: [
{ label: '涉毒人员', value: 100 },
{ label: '前科人员', value: 80 },
{ label: '肇事肇祸', value: 70 },
{ label: '涉稳人员', value: 60 },
{ label: '涉稳人员', value: 50 },
],//各类标签预警数量统计
sevenList: [
{ label:'涉恐',value:30 },
{ label:'涉暴',value:20 },
{ label:'涉恐暴',value:10 },
{ label:'涉睡',value:30 },
{ label:'涉睡暴',value:20 },
{ label:'涉睡恐',value:10 },
{ label:'涉睡恐暴',value:5 },
],//7类重点人员预警统计
cnList: {
list: [
{ label:'工布江达县',value:50 },
{ label:'米林市',value:40 },
{ label:'墨脱县',value:10 },
{ label:'波密县',value:50 },
{ label:'察隅县',value:40 },
{ label:'郎县',value:10 },
{ label:'雅安分局',value:40 },
],
topColor:'#17c8c3',
colors: ["#28EEBF","#0DBAC5"],
}
})
onMounted(()=>{
tabHeightFn()
})
// 筛选
const handleChange = (val) => {
formSearch.value = val
}
// 表格高度计算
const tabHeightFn = () => {
boxHeight.value = window.innerHeight - searchRef.value.offsetHeight - 300;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style lang="scss" scoped>
.countBox {
height: 100%;
border-radius: 4px;
.countItem{
height: 100px;
background: transparent;
margin: 10px 0;
display: flex;
justify-content: space-between;
.item {
width: 24.5%;
background: #fff;
border-radius: 4px;
display: flex;
align-items: center;
padding: 0 20px;
box-sizing: border-box;
box-shadow: 0 0 10px rgba(0,0,0,0.05);
.left {
margin-right: 15px;
.icon-img {
width: 48px;
height: 48px;
display: block;
}
}
.center {
flex: 1;
.label {
font-size: 14px;
color: #999;
margin-bottom: 5px;
}
.value {
font-size: 24px;
font-weight: bold;
color: #333;
}
}
.divider {
width: 1px;
height: 40px;
background: #eee;
margin: 0 20px;
}
.right {
display: flex;
flex-direction: column;
justify-content: center;
font-size: 12px;
.stat-row {
display: flex;
align-items: center;
margin-bottom: 5px;
&:last-child {
margin-bottom: 0;
}
.stat-label {
color: #999;
margin-right: 10px;
}
.stat-val {
font-weight: bold;
display: flex;
align-items: center;
&.up {
color: #F56C6C;
}
&.down {
color: #67C23A; // Green for down in Chinese stocks usually, but commonly Red is up/bad, Green is down/good or vice versa. Image shows Red Up, Green Down.
// Image: Top one (red arrow) is Red. Bottom one (green arrow) is Green.
// 106,3 Red Arrow Up.
// 106,3 Green Arrow Down.
color: #00CC99; // Using a teal/green color often used in designs. Or #67C23A (Element Success).
// Let's use #00C853 or similar.
}
.el-icon {
margin-left: 2px;
}
}
}
}
}
}
.cntBox{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-content: space-between;
margin-top: 10px;
overflow: hidden;
.cnt-item{
width: 49.8%;
height: 49.5%;
background: #fff;
border-radius: 4px;
.common-title {
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 20px;
box-sizing: border-box;
.title {
font-size: 14px;
font-weight: 600;
color: #333;
position: relative;
&::after {
content: '';
position: absolute;
left: 0;
bottom: -1px;
width: 80px;
height: 4px;
background: linear-gradient(to right, #409EFF, #ffffff);
}
}
.btn-group {
display: flex;
gap: 10px;
.btn {
padding: 3px 16px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
color: #606266;
transition: all 0.3s;
user-select: none;
&.active {
background: #409EFF;
color: #fff;
border-color: #409EFF;
}
&:hover:not(.active) {
color: #409EFF;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
}
}
}
.echratsBox{
height: calc(100% - 40px);
overflow: hidden;
}
}
}
}
</style>

View File

@ -101,7 +101,6 @@ function chartFn() {
// 安全获取标签数据 // 安全获取标签数据
const labels = props.data.list && Array.isArray(props.data.list) ? props.data.list.map(v => v.label) : []; const labels = props.data.list && Array.isArray(props.data.list) ? props.data.list.map(v => v.label) : [];
console.log(labels);
const option = { const option = {
grid: { grid: {
@ -198,7 +197,7 @@ function chartFn() {
symbolSize: [barWidth - 4, 10], symbolSize: [barWidth - 4, 10],
itemStyle: { itemStyle: {
normal: { normal: {
color: colorArr[2] color: props.data.topColor || colorArr[2]
}, },
}, },
tooltip: { tooltip: {

View File

@ -41,8 +41,8 @@ function chartFn() {
grid: { grid: {
top: "8%", top: "8%",
right: "2%", right: "2%",
left: "10%", left: "2%",
bottom: "12%", bottom: "8%",
containLabel:true containLabel:true
}, },
tooltip: { tooltip: {