<template>
|
<div class="centre">
|
<!-- 今日统计 -->
|
<div style="display: flex; justify-content: center; align-items: center;">
|
<h4>今日统计</h4>
|
</div>
|
<div class="top">
|
<div class="add">
|
<div class="img">
|
<img class="image" src="../assets/images/jrbg.png" alt="" />
|
</div>
|
<div class="txt">
|
<div class="day">今日登记 {{ Customer }}</div>
|
</div>
|
</div>
|
<div class="add">
|
<div class="img">
|
<img class="image" src="../assets/images/jrdj.png" alt="" />
|
</div>
|
<div class="txt">
|
<div class="day">今日已检 {{ Order }}</div>
|
</div>
|
</div>
|
<div class="add">
|
<div class="img">
|
<img class="image" src="../assets/images/jrwj.png" alt="" />
|
</div>
|
<div class="txt">
|
<div class="day">今日报告 {{ ReportToday }}</div>
|
</div>
|
</div>
|
<div class="add">
|
<div class="img">
|
<img class="image" src="../assets/images/jryj.png" alt="" />
|
</div>
|
<div class="txt">
|
<div class="day">今日待检 {{ TobeToday }}</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 近一月统计 -->
|
<div style="display: flex; justify-content: center; align-items: center;">
|
<h4>近一月统计</h4>
|
</div>
|
<div class="data-view">
|
<div id="main" style="width: 95%; height: 330px"></div>
|
</div>
|
<div class="view">
|
<div id="main2"></div>
|
<div id="main3"></div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import { getCustomer, getOrder, getReportToday, getTobeToday, getPieChart, getChart } from "@/api/home";
|
import { noticeToday } from "@/api/system/notice";
|
import { initWebSocket } from "@/utils/websocket";
|
const echarts = require('echarts/lib/echarts');
|
require('echarts/lib/component/title');
|
require('echarts/lib/component/tooltip');
|
require('echarts/lib/component/legend');
|
require('echarts/lib/chart/pie');
|
require('echarts/lib/chart/line');
|
|
export default {
|
data() {
|
return {
|
min: '',
|
max: '',
|
Customer: "",
|
Order: "",
|
ReportToday: "",
|
TobeToday: "",
|
LineChart: [],
|
personYYNum: [],
|
reportNum: [],
|
teamYYNum: [],
|
PieChart: [],
|
PieChart2: [],
|
loading: false
|
};
|
},
|
|
created() {
|
this.getList();
|
this.initWebSocket();
|
},
|
|
watch: {
|
$route(to, from) {
|
window.location.reload();
|
}
|
},
|
|
methods: {
|
goToNotice(noticeId) {
|
this.$router.push({
|
path: '/notice',
|
query: { noticeId }
|
});
|
},
|
|
// 初始化 WebSocket 连接
|
initWebSocket() {
|
const token = this.$store.state.user.token || '';
|
initWebSocket(token, (type, data) => {
|
if (type === 'error') {
|
this.$notify.error({
|
title: '错误',
|
message: data,
|
duration: 5000,
|
position: 'top-right'
|
});
|
return;
|
}
|
|
try {
|
const message = JSON.parse(data);
|
console.log('WebSocket 解析后消息:', message);
|
if (message.noticeId && message.noticeTitle) {
|
const noticeTypeLabel = message.noticeType === '1' ? '通知' : '公告';
|
this.$notify({
|
title: `新${noticeTypeLabel}`,
|
message: message.noticeTitle || '无标题',
|
type: 'success',
|
duration: 5000, // 悬停 5 秒
|
position: 'top-right',
|
offset: 50,
|
onClick: () => {
|
this.goToNotice(message.noticeId);
|
}
|
});
|
} else {
|
console.log('未知消息类型:', message);
|
}
|
} catch (error) {
|
console.error('消息解析失败:', error, '原始数据:', data);
|
this.$notify.info({
|
title: '消息',
|
message: `服务器回应字符串: ${data}`,
|
duration: 5000,
|
position: 'top-right',
|
offset: 50
|
});
|
}
|
});
|
},
|
|
getList() {
|
this.loading = true;
|
|
// 查询所有公告(仅用于初始化数据,可根据需要保留或移除)
|
noticeToday().then(response => {
|
console.log('Notice API response:', response);
|
this.loading = false;
|
}).catch(error => {
|
console.error('Notice API error:', error);
|
this.$notify.error({
|
title: '错误',
|
message: `获取通知失败:${error.message}`,
|
duration: 5000,
|
position: 'top-right'
|
});
|
this.loading = false;
|
});
|
|
getCustomer().then(response => {
|
this.Customer = response.data || response;
|
this.loading = false;
|
});
|
|
getOrder().then(response => {
|
this.Order = response.data || response;
|
this.loading = false;
|
});
|
|
getReportToday().then(response => {
|
this.ReportToday = response.data || response;
|
this.loading = false;
|
});
|
|
getTobeToday().then(response => {
|
this.TobeToday = response.data || response;
|
this.loading = false;
|
});
|
|
getChart().then(response => {
|
response.data.forEach(item => {
|
this.LineChart.push(item.date);
|
this.reportNum.push(item.tdcoun);
|
this.personYYNum.push(item.grcoun);
|
this.teamYYNum.push(item.bgcoun);
|
});
|
|
let myChart = this.$echarts.init(document.getElementById('main'));
|
myChart.setOption({
|
tooltip: { trigger: 'axis' },
|
legend: { data: ['每日体检登记数', '每日团体登记数', '每日发布报告数'] },
|
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
toolbox: { feature: { saveAsImage: {} } },
|
xAxis: {
|
type: 'category',
|
boundaryGap: false,
|
axisLine: {
|
show: true,
|
lineStyle: { width: 0, color: 'blue', type: 'solid' }
|
},
|
data: this.LineChart
|
},
|
yAxis: { type: 'value', min: 0, max: 400, interval: 20 },
|
series: [
|
{ name: '每日体检登记数', type: 'line', stack: 'Total', data: this.personYYNum },
|
{ name: '每日团体登记数', type: 'line', stack: 'Total', data: this.reportNum },
|
{ name: '每日发布报告数', type: 'line', stack: 'Total', data: this.teamYYNum }
|
]
|
});
|
|
const sizeFun = () => myChart.resize();
|
window.addEventListener('resize', sizeFun);
|
this.loading = false;
|
});
|
|
getPieChart().then(response => {
|
if (response.data) {
|
if (response.data.tjdj == 0 || !response.data.tjdj?.length) {
|
this.PieChart = [{ name: '体检登记人数分布', count: 1, value: 10 }];
|
} else {
|
this.PieChart = response.data.tjdj;
|
this.PieChart.forEach(item => { item.value = item.count; });
|
this.PieChart.reverse();
|
this.PieChart.push(this.PieChart[0]);
|
this.PieChart.splice(0, 1);
|
}
|
|
let myChart2 = this.$echarts.init(document.getElementById('main2'));
|
myChart2.setOption({
|
title: { text: '体检登记人数分布', top: '5' },
|
tooltip: { trigger: 'item' },
|
legend: { top: '80%', left: 'center' },
|
series: [{
|
type: 'pie',
|
radius: ['16%', '54%'],
|
center: ['50%', '43%'],
|
avoidLabelOverlap: false,
|
startAngle: 180,
|
minAngle: 10,
|
data: this.PieChart,
|
emphasis: {
|
itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' }
|
}
|
}]
|
});
|
|
if (response.data.tjyc == 0 || !response.data.tjyc?.length) {
|
this.PieChart2 = [{ name: '体检结果异常人数分布', count: 1, value: 0 }];
|
} else {
|
this.PieChart2 = response.data.tjyc;
|
this.PieChart2.reverse();
|
this.PieChart2.push(this.PieChart2[0]);
|
this.PieChart2.splice(0, 1);
|
this.PieChart2.forEach(item => { item.value = item.count; });
|
}
|
|
let myChart3 = this.$echarts.init(document.getElementById('main3'));
|
myChart3.setOption({
|
title: { text: '体检结果异常人数分布', top: '5' },
|
tooltip: { trigger: 'item' },
|
legend: { top: '80%', left: 'center' },
|
series: [{
|
type: 'pie',
|
radius: ['16%', '54%'],
|
center: ['50%', '43%'],
|
avoidLabelOverlap: false,
|
startAngle: 180,
|
minAngle: 10,
|
data: this.PieChart2,
|
emphasis: {
|
itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' }
|
}
|
}]
|
});
|
|
window.onresize = () => {
|
myChart2.resize();
|
myChart3.resize();
|
};
|
}
|
this.loading = false;
|
});
|
},
|
|
parseTime(time, cFormat) {
|
if (!time) return '';
|
try {
|
const date = new Date(time);
|
if (isNaN(date.getTime())) return '';
|
const formatObj = {
|
y: date.getFullYear(),
|
m: String(date.getMonth() + 1).padStart(2, '0'),
|
d: String(date.getDate()).padStart(2, '0'),
|
h: String(date.getHours()).padStart(2, '0'),
|
i: String(date.getMinutes()).padStart(2, '0'),
|
s: String(date.getSeconds()).padStart(2, '0')
|
};
|
return cFormat.replace(/{([ymdhis]+)}/g, (result, key) => formatObj[key] || '');
|
} catch (error) {
|
console.error('parseTime error:', error, 'time:', time);
|
return '';
|
}
|
}
|
}
|
};
|
</script>
|
|
<style>
|
.centre {
|
min-height: 820px;
|
margin: 15px;
|
background-color: #f3f3f3;
|
padding: 10px;
|
}
|
|
.top {
|
width: 100%;
|
display: flex;
|
height: 120px;
|
}
|
|
.add {
|
width: 320px;
|
height: 75px;
|
margin-top: 20px;
|
margin-left: 20px;
|
margin-right: 20px;
|
background-color: #fff;
|
display: flex;
|
}
|
|
.img {
|
width: 60%;
|
height: 100%;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
}
|
|
.image {
|
width: 60px;
|
height: 60px;
|
}
|
|
.txt {
|
display: flex;
|
align-items: center;
|
}
|
|
.day {
|
height: 40px;
|
line-height: 40px;
|
font-size: 12px;
|
}
|
|
.data-view {
|
margin: 0 15px;
|
height: 323px !important;
|
}
|
|
#main {
|
padding: 10px;
|
}
|
|
.view {
|
margin: 0 15px;
|
padding-top: 15px;
|
min-height: 350px;
|
display: flex;
|
}
|
|
#main2,
|
#main3 {
|
width: 820px;
|
height: 350px;
|
background-color: #fff;
|
margin-right: 20px;
|
}
|
|
/* 自定义 Element UI 通知样式 */
|
.el-notification {
|
min-width: 300px;
|
background-color: #f0f9eb;
|
border-color: #e1f3d8;
|
color: #67c23a;
|
font-size: 16px;
|
padding: 15px 20px;
|
}
|
|
.el-notification__title {
|
font-weight: bold;
|
}
|
|
.el-notification__content {
|
font-size: 14px;
|
color: #333;
|
}
|
|
.el-notification__closeBtn {
|
color: #999;
|
}
|
</style>
|