|
|
|
|
@ -4,23 +4,21 @@
|
|
|
|
|
<div class="jscC-top">
|
|
|
|
|
<div v-for="item in topObj">
|
|
|
|
|
<div class="label">{{item.label}}</div>
|
|
|
|
|
<div class="value">{{item.value}}</div>
|
|
|
|
|
<div class="value">
|
|
|
|
|
{{item.value}}
|
|
|
|
|
<!-- <CountUp :end="item.value" :duration="6" ref="count" /> -->
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="jscC-center">
|
|
|
|
|
<div class="jscC-center-left">
|
|
|
|
|
<div class="jscC-center-left-title">物资库种类(2025)</div>
|
|
|
|
|
<div style="display: flex; justify-content: space-between;">
|
|
|
|
|
<span
|
|
|
|
|
v-for="item in Object.keys(chartDataMap)"
|
|
|
|
|
:key="item"
|
|
|
|
|
:class="['custom-btn', { active: activeType === item }]"
|
|
|
|
|
@click="handleTypeClick(item)"
|
|
|
|
|
>
|
|
|
|
|
{{ item }}
|
|
|
|
|
</span>
|
|
|
|
|
<div class="jscC-center-left">
|
|
|
|
|
<div style="display: flex; justify-content: space-between;">
|
|
|
|
|
<span v-for="item in Object.keys(chartDataMap)" :key="item"
|
|
|
|
|
:class="['custom-btn', { active: activeType === item }]" @click="handleTypeClick(item)">
|
|
|
|
|
{{ item }}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- <Bar3DChart></Bar3DChart> -->
|
|
|
|
|
<!-- <Bar3DChart></Bar3DChart> -->
|
|
|
|
|
<fenleiChart :chartData="chartData"></fenleiChart>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="jscC-center-center">
|
|
|
|
|
@ -28,7 +26,8 @@
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
<div class="jscC-center-right">
|
|
|
|
|
<Pie3DChart></Pie3DChart>
|
|
|
|
|
<Bar3DChart :xData="xData" :yData="yData"></Bar3DChart>
|
|
|
|
|
<!-- <Pie3DChart></Pie3DChart> -->
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="jscC-bottom">
|
|
|
|
|
@ -43,15 +42,19 @@
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import Bar3DChart from "../jsc/components/barChart.vue"
|
|
|
|
|
import fenleiChart from "../jsc/components/fenleiChart.vue"
|
|
|
|
|
import Bar3DChart from "../jsc/components/barChart.vue"
|
|
|
|
|
import fenleiChart from "../jsc/components/fenleiChart.vue"
|
|
|
|
|
import Pie3DChart from "../jsc/components/pieChart.vue"
|
|
|
|
|
import echartsMap from "./components/mapChart.vue";
|
|
|
|
|
import {
|
|
|
|
|
fenleiCharts,
|
|
|
|
|
homeCharts
|
|
|
|
|
} from "@/api/charts.js"
|
|
|
|
|
export default {
|
|
|
|
|
components: {
|
|
|
|
|
Bar3DChart,
|
|
|
|
|
Pie3DChart,
|
|
|
|
|
echartsMap,
|
|
|
|
|
echartsMap,
|
|
|
|
|
fenleiChart
|
|
|
|
|
},
|
|
|
|
|
data() {
|
|
|
|
|
@ -68,28 +71,36 @@
|
|
|
|
|
},
|
|
|
|
|
topObj: [{
|
|
|
|
|
label: '仓库数量',
|
|
|
|
|
value: 45
|
|
|
|
|
},{
|
|
|
|
|
value: 0,
|
|
|
|
|
id: 'cangku_count',
|
|
|
|
|
}, {
|
|
|
|
|
label: '物资种类',
|
|
|
|
|
value: 3500
|
|
|
|
|
value: 0,
|
|
|
|
|
id: 'wuzizhonglei_count',
|
|
|
|
|
}, {
|
|
|
|
|
label: '本月出库',
|
|
|
|
|
value: 1390
|
|
|
|
|
value: 0,
|
|
|
|
|
id: 'chuku_month_count',
|
|
|
|
|
}, {
|
|
|
|
|
label: '本月入库',
|
|
|
|
|
value: 2350
|
|
|
|
|
value: 0,
|
|
|
|
|
id: 'ruku_month_count',
|
|
|
|
|
}, {
|
|
|
|
|
label: '应急调度次数',
|
|
|
|
|
value: 25
|
|
|
|
|
value: 0,
|
|
|
|
|
id: 'yingjidiaodu_count',
|
|
|
|
|
}, {
|
|
|
|
|
label: '设备总数',
|
|
|
|
|
value: 350
|
|
|
|
|
label: '装备总数',
|
|
|
|
|
value: 0,
|
|
|
|
|
id: 'shebei_count',
|
|
|
|
|
}, {
|
|
|
|
|
label: '盘点',
|
|
|
|
|
value: 0
|
|
|
|
|
value: 0,
|
|
|
|
|
id: 'pan_count',
|
|
|
|
|
}, {
|
|
|
|
|
label: '维护',
|
|
|
|
|
value: 0
|
|
|
|
|
value: 0,
|
|
|
|
|
id: 'weihu_count',
|
|
|
|
|
}],
|
|
|
|
|
bottomObj: [{
|
|
|
|
|
label: '库存管理',
|
|
|
|
|
@ -115,120 +126,151 @@
|
|
|
|
|
}, {
|
|
|
|
|
label: '工单管理',
|
|
|
|
|
path: '/flood/plan'
|
|
|
|
|
}],
|
|
|
|
|
// 分类
|
|
|
|
|
activeType: '防御材料',
|
|
|
|
|
chartDataMap: {
|
|
|
|
|
'防御材料': {
|
|
|
|
|
level1: [{ value: 100, name: '防御材料' }],
|
|
|
|
|
level2: [
|
|
|
|
|
{ value: 20, name: '袋类' },
|
|
|
|
|
{ value: 45, name: '土工布类' },
|
|
|
|
|
{ value: 25, name: '桩类' },
|
|
|
|
|
{ value: 10, name: '金属丝及其制品类' }
|
|
|
|
|
],
|
|
|
|
|
level3: [
|
|
|
|
|
{ value: 8, name: '个', parent: '袋类' },
|
|
|
|
|
{ value: 12, name: '只', parent: '袋类' },
|
|
|
|
|
{ value: 20, name: '捆', parent: '土工布类' },
|
|
|
|
|
{ value: 25, name: '匹', parent: '土工布类' },
|
|
|
|
|
{ value: 13, name: '根', parent: '桩类' },
|
|
|
|
|
{ value: 12, name: '堆', parent: '桩类' },
|
|
|
|
|
{ value: 2, name: '条', parent: '金属丝及其制品类' },
|
|
|
|
|
{ value: 4, name: '捆', parent: '金属丝及其制品类' },
|
|
|
|
|
{ value: 4, name: '个', parent: '金属丝及其制品类' }
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
'防御装备': {
|
|
|
|
|
level1: [{ value: 80, name: '防御装备' }],
|
|
|
|
|
level2: [
|
|
|
|
|
{ value: 15, name: '指挥通信类' },
|
|
|
|
|
{ value: 22, name: '观察测量类' },
|
|
|
|
|
{ value: 13, name: '动力及照明类' },
|
|
|
|
|
{ value: 30, name: '水下抢险类' }
|
|
|
|
|
],
|
|
|
|
|
level3: [
|
|
|
|
|
{ value: 15, name: '个', parent: '指挥通信类' },
|
|
|
|
|
{ value: 22, name: '个', parent: '观察测量类' },
|
|
|
|
|
{ value: 13, name: '个', parent: '动力及照明类' },
|
|
|
|
|
{ value: 10, name: '套', parent: '水下抢险类' },
|
|
|
|
|
{ value: 20, name: '件', parent: '水下抢险类' }
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
'配套装备': {
|
|
|
|
|
level1: [{ value: 60, name: '配套装备' }],
|
|
|
|
|
level2: [
|
|
|
|
|
{ value: 10, name: '野外生活保障车' },
|
|
|
|
|
{ value: 20, name: '野外抢险炊事车' },
|
|
|
|
|
{ value: 18, name: '牵引车' },
|
|
|
|
|
{ value: 12, name: '运输车' }
|
|
|
|
|
],
|
|
|
|
|
level3: [
|
|
|
|
|
{ value: 10, name: '辆', parent: '野外生活保障车' },
|
|
|
|
|
{ value: 20, name: '辆', parent: '野外抢险炊事车' },
|
|
|
|
|
{ value: 18, name: '辆', parent: '牵引车' },
|
|
|
|
|
{ value: 12, name: '辆', parent: '运输车' }
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
'装备耗材': {
|
|
|
|
|
level1: [{ value: 50, name: '装备耗材' }],
|
|
|
|
|
level2: [
|
|
|
|
|
{ value: 20, name: '软管' },
|
|
|
|
|
{ value: 30, name: '抱箍' }
|
|
|
|
|
],
|
|
|
|
|
level3: [
|
|
|
|
|
{ value: 12, name: '根', parent: '软管' },
|
|
|
|
|
{ value: 8, name: '捆', parent: '软管' },
|
|
|
|
|
{ value: 19, name: '个', parent: '抱箍' },
|
|
|
|
|
{ value: 11, name: '扎', parent: '抱箍' }
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
typeList: ['防御材料', '防御装备', '配套装备', '装备耗材'],
|
|
|
|
|
autoTimer: null, // 自动切换定时器
|
|
|
|
|
resumeTimer: null // 恢复自动切换的倒计时
|
|
|
|
|
}],
|
|
|
|
|
// 分类
|
|
|
|
|
activeType: '防御材料',
|
|
|
|
|
apiData: [],
|
|
|
|
|
chartDataMap: {},
|
|
|
|
|
typeList: [],
|
|
|
|
|
autoTimer: null, // 自动切换定时器
|
|
|
|
|
resumeTimer: null, // 恢复自动切换的倒计时
|
|
|
|
|
xData: [],
|
|
|
|
|
yData: [],
|
|
|
|
|
todoList: [{
|
|
|
|
|
id: 'gongdan',
|
|
|
|
|
value: '工单'
|
|
|
|
|
}, {
|
|
|
|
|
id: 'pandian',
|
|
|
|
|
value: '盘点'
|
|
|
|
|
}, {
|
|
|
|
|
id: 'weihu',
|
|
|
|
|
value: '维护'
|
|
|
|
|
}]
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
computed: {
|
|
|
|
|
chartData() {
|
|
|
|
|
return this.chartDataMap[this.activeType];
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
watch: {
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
computed: {
|
|
|
|
|
chartData() {
|
|
|
|
|
return this.chartDataMap[this.activeType];
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
|
this.$store.dispatch('app/toggleSideBar')
|
|
|
|
|
this.getChartData()
|
|
|
|
|
this.$store.dispatch('app/closeSideBar', {
|
|
|
|
|
withoutAnimation: false
|
|
|
|
|
});
|
|
|
|
|
this.setRem()
|
|
|
|
|
|
|
|
|
|
this.calculateScreenSize()
|
|
|
|
|
window.addEventListener('resize', this.calculateScreenSize)
|
|
|
|
|
window.addEventListener('resize', this.calculateScreenSize)
|
|
|
|
|
this.startAutoSwitch();
|
|
|
|
|
},
|
|
|
|
|
beforeRouteLeave(to, from, next) {
|
|
|
|
|
this.$store.dispatch('app/toggleSideBar');
|
|
|
|
|
next();
|
|
|
|
|
},
|
|
|
|
|
beforeDestroy() {
|
|
|
|
|
window.removeEventListener('resize', this.calculateScreenSize)
|
|
|
|
|
clearInterval(this.autoTimer);
|
|
|
|
|
clearTimeout(this.resumeTimer);
|
|
|
|
|
window.removeEventListener('resize', this.calculateScreenSize)
|
|
|
|
|
clearInterval(this.autoTimer);
|
|
|
|
|
clearTimeout(this.resumeTimer);
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
// 启动自动切换
|
|
|
|
|
startAutoSwitch() {
|
|
|
|
|
clearInterval(this.autoTimer);
|
|
|
|
|
let idx = this.typeList.indexOf(this.activeType);
|
|
|
|
|
this.autoTimer = setInterval(() => {
|
|
|
|
|
idx = (idx + 1) % this.typeList.length;
|
|
|
|
|
this.activeType = this.typeList[idx];
|
|
|
|
|
}, 5000); // 10秒
|
|
|
|
|
},
|
|
|
|
|
// 停止自动切换,并在20秒后恢复
|
|
|
|
|
stopAutoSwitchAndResumeLater() {
|
|
|
|
|
clearInterval(this.autoTimer);
|
|
|
|
|
clearTimeout(this.resumeTimer);
|
|
|
|
|
this.resumeTimer = setTimeout(() => {
|
|
|
|
|
this.startAutoSwitch();
|
|
|
|
|
}, 10000); // 20秒
|
|
|
|
|
},
|
|
|
|
|
// 按钮点击事件
|
|
|
|
|
handleTypeClick(type) {
|
|
|
|
|
this.activeType = type;
|
|
|
|
|
this.stopAutoSwitchAndResumeLater();
|
|
|
|
|
methods: {
|
|
|
|
|
// 获取统计数据
|
|
|
|
|
async getChartData() {
|
|
|
|
|
const res = await fenleiCharts()
|
|
|
|
|
const home = await homeCharts()
|
|
|
|
|
// 顶部数据
|
|
|
|
|
this.topObj.map(item => {
|
|
|
|
|
item.value = home.top[item.id]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
this.xData = []
|
|
|
|
|
|
|
|
|
|
this.yData = []
|
|
|
|
|
this.todoList.map(item => {
|
|
|
|
|
this.xData.push(item.value)
|
|
|
|
|
this.yData.push(home.rate[item.id])
|
|
|
|
|
})
|
|
|
|
|
console.log(this.xData, this.yData)
|
|
|
|
|
//
|
|
|
|
|
this.apiData = res.fenleiLevel1
|
|
|
|
|
this.chartDataMap = this.convertFenleiToChartDataMap(this.apiData)
|
|
|
|
|
},
|
|
|
|
|
// 处理分类数据
|
|
|
|
|
convertFenleiToChartDataMap(fenleiLevel1) {
|
|
|
|
|
const chartDataMap = {};
|
|
|
|
|
this.typeList = []
|
|
|
|
|
fenleiLevel1.forEach(level1 => {
|
|
|
|
|
const level1Name = level1.value;
|
|
|
|
|
// 一级
|
|
|
|
|
this.typeList.push(level1Name)
|
|
|
|
|
const level1Arr = [{
|
|
|
|
|
value: level1.details.reduce((sum, d) => sum + (d.total_count || 0), 0), // 或自定义总数
|
|
|
|
|
name: level1Name
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
// 二级
|
|
|
|
|
const level2Arr = [];
|
|
|
|
|
// 三级
|
|
|
|
|
const level3Arr = [];
|
|
|
|
|
|
|
|
|
|
(level1.details || []).forEach(level2 => {
|
|
|
|
|
// 二级 value 为其所有 inventorys 的 total_count 之和
|
|
|
|
|
let level2Value = 0;
|
|
|
|
|
(level2.inventorys || []).forEach(inv => {
|
|
|
|
|
level2Value += Number(inv.total_count) || 0;
|
|
|
|
|
});
|
|
|
|
|
// 如果没有三级,直接用 total_count 字段
|
|
|
|
|
if (level2Value === 0) level2Value = level2.total_count || 0;
|
|
|
|
|
|
|
|
|
|
level2Arr.push({
|
|
|
|
|
value: level2Value,
|
|
|
|
|
name: level2.value
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 三级
|
|
|
|
|
(level2.inventorys || []).forEach(inv => {
|
|
|
|
|
level3Arr.push({
|
|
|
|
|
value: inv.total_count,
|
|
|
|
|
name: inv.jiliangdanwei,
|
|
|
|
|
parent: level2.value
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
chartDataMap[level1Name] = {
|
|
|
|
|
level1: level1Arr,
|
|
|
|
|
level2: level2Arr,
|
|
|
|
|
level3: level3Arr
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return chartDataMap;
|
|
|
|
|
},
|
|
|
|
|
// 启动自动切换
|
|
|
|
|
startAutoSwitch() {
|
|
|
|
|
clearInterval(this.autoTimer);
|
|
|
|
|
let idx = this.typeList.indexOf(this.activeType);
|
|
|
|
|
this.autoTimer = setInterval(() => {
|
|
|
|
|
idx = (idx + 1) % this.typeList.length;
|
|
|
|
|
this.activeType = this.typeList[idx];
|
|
|
|
|
}, 5000); // 10秒
|
|
|
|
|
},
|
|
|
|
|
// 停止自动切换,并在20秒后恢复
|
|
|
|
|
stopAutoSwitchAndResumeLater() {
|
|
|
|
|
clearInterval(this.autoTimer);
|
|
|
|
|
clearTimeout(this.resumeTimer);
|
|
|
|
|
this.resumeTimer = setTimeout(() => {
|
|
|
|
|
this.startAutoSwitch();
|
|
|
|
|
}, 10000); // 20秒
|
|
|
|
|
},
|
|
|
|
|
// 按钮点击事件
|
|
|
|
|
handleTypeClick(type) {
|
|
|
|
|
this.activeType = type;
|
|
|
|
|
this.stopAutoSwitchAndResumeLater();
|
|
|
|
|
},
|
|
|
|
|
setRem() {
|
|
|
|
|
// 默认使用100px作为基准大小
|
|
|
|
|
@ -323,28 +365,31 @@
|
|
|
|
|
|
|
|
|
|
// flex-wrap: wrap;
|
|
|
|
|
&-left {
|
|
|
|
|
// width:5.3rem;
|
|
|
|
|
&-title{
|
|
|
|
|
color:#6dcde6;
|
|
|
|
|
text-align: center;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
margin-bottom:10px;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
}
|
|
|
|
|
.custom-btn {
|
|
|
|
|
background: #0b1b3a;
|
|
|
|
|
color: #19eaff;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
padding: 10px 15px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: background 0.2s, color 0.2s;
|
|
|
|
|
}
|
|
|
|
|
.custom-btn.active {
|
|
|
|
|
background: linear-gradient(90deg, #3ad0ff 0%, #4be3c1 100%);
|
|
|
|
|
color: #fff;
|
|
|
|
|
box-shadow: 0 2px 12px 0 rgba(58,208,255,0.2);
|
|
|
|
|
|
|
|
|
|
// width:5.3rem;
|
|
|
|
|
&-title {
|
|
|
|
|
color: #6dcde6;
|
|
|
|
|
text-align: center;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.custom-btn {
|
|
|
|
|
background: #0b1b3a;
|
|
|
|
|
color: #19eaff;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
padding: 10px 15px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: background 0.2s, color 0.2s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.custom-btn.active {
|
|
|
|
|
background: linear-gradient(90deg, #3ad0ff 0%, #4be3c1 100%);
|
|
|
|
|
color: #fff;
|
|
|
|
|
box-shadow: 0 2px 12px 0 rgba(58, 208, 255, 0.2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|