新增页面
This commit is contained in:
BIN
src/assets/images/icon-blue.png
Normal file
BIN
src/assets/images/icon-blue.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src/assets/images/icon-orange.png
Normal file
BIN
src/assets/images/icon-orange.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src/assets/images/icon-red.png
Normal file
BIN
src/assets/images/icon-red.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
BIN
src/assets/images/icon-yellow.png
Normal file
BIN
src/assets/images/icon-yellow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
@ -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>
|
||||||
@ -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>
|
||||||
@ -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>
|
||||||
@ -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>
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
@ -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>
|
||||||
@ -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>
|
||||||
@ -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>
|
||||||
@ -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: {
|
||||||
|
|||||||
@ -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: {
|
||||||
|
|||||||
Reference in New Issue
Block a user