bonus-ui-canteen-screen/src/views/view copy.vue

683 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="container">
<div class="topdiv">
<div class="dateTimeClass">
<span style="color:#D8E2FF;font-size: 24px;margin-top: 12px;">{{dateTime}}</span>
</div>
<div class="titlediv">
公示大屏
</div>
<div class="hourTimeClass">
<span style="color:#D8E2FF;font-size: 24px;margin-top: 12px;">{{hourTime}}</span>
</div>
</div>
<div style="height: auto;width: 100%;margin-bottom: 40px;">
<div class="partthree_title"><span>健康晨检</span></div>
<div class="partthree_title2"><div class="fegexian2" style="margin-top: 2px;"></div></div>
<div class="contentclass">
<table style="width: 100%;height: 100%;">
<tr>
<td>晨检</td>
<td>健康证</td>
</tr>
<tr style="height: 100%;width: 100%;">
<!-- 图表容器统一设置固定宽高+100%填充避免尺寸偏差 -->
<td rowspan="5" style="width: 50%;">
<div style="width: 100%;height: 240px;display: flex;align-items: center;justify-content: center;">
<div ref="chartone" style="width: 90%;height: 90%;"></div>
</div>
</td>
<td rowspan="5" style="width: 50%;">
<div style="width: 100%;height: 240px;display: flex;align-items: center;justify-content: center;">
<div ref="chartfour" style="width: 90%;height: 90%;"></div>
</div>
</td>
</tr>
<tr></tr>
<tr></tr>
<tr></tr>
<tr></tr>
<tr>
<td>晨检正常{{Number(morningCheckNum)-Number(morningCheckAbno)}}</td>
<td>正常{{Number(healthNum)-Number(healthAbno)}}</td>
</tr>
<tr>
<td>晨检异常{{morningCheckAbno}}</td>
<td>过期{{healthAbno}}</td>
</tr>
</table>
</div>
</div>
<div style="height: auto;width: 100%;margin-bottom: 40px;">
<div class="partthree_title"><span>今日菜品</span></div>
<div class="partthree_title2"><div class="fegexian2" style="margin-top: 2px;"></div></div>
<div class="contentclass">
<div style="width: 80%;border: 1px solid rgba(191,191,255,0.04);margin-top: 10px;">
<div class="dishclass">
<img src="../assets/images/Frame1.png"/><span>早餐供应</span><img src="../assets/images/breakfast.png" style="float: right;"/>
</div>
<div class="dishcontentclass">
<template v-if="onedataList.length>0">
<template v-for="(group, groupIndex) in groupedBreakfastList">
<div class="dishcontentrefclass" v-for="item in group.dishes" :key="item.id || item.dishesName">
{{item.dishesName}}&nbsp;&nbsp;&nbsp;&nbsp;
</div>
</template>
</template>
</div>
</div>
<div style="width: 80%;border: 2px solid rgba(191,191,255,0.04);margin-top: 10px;">
<div class="dishclass">
<img src="../assets/images/Frame2.png"/><span>午餐供应</span><img src="../assets/images/lunch.png" style="float: right;"/>
</div>
<div class="dishcontentclass">
<template v-if="twodataList.length>0">
<div v-for="(group, groupIndex) in groupedLunchList" :key="groupIndex" style="width: 100%;display: flex;align-items: baseline;">
<div class="dishtypeclass" v-if="group.dishes.length>0 && group.typeName" :key="'type-' + groupIndex">
{{getDisplayTypeName(group.typeName)}}
</div>
<div style="width: 80%;display: flex;align-items: center;flex-wrap: wrap;">
<div class="dishcontentrefclass" style="width: 30%;" v-for="item in group.dishes" :key="item.id || item.dishesName">
{{item.dishesName}}&nbsp;&nbsp;&nbsp;&nbsp;
</div>
</div>
</div>
</template>
</div>
</div>
<div style="width: 80%;border: 2px solid rgba(191,191,255,0.04);margin-top: 10px;">
<div class="dishclass">
<img src="../assets/images/Frame.png"/><span>晚餐供应</span><img src="../assets/images/dinner.png" style="float: right;"/>
</div>
<div class="dishcontentclass">
<template v-if="fourdataList.length>0">
<div class="dishcontentrefclass" v-for="item in fourdataList" :key="item.id || item.dishesName">
{{item.dishesName}}&nbsp;&nbsp;&nbsp;&nbsp;
</div>
</template>
</div>
</div>
</div>
</div>
<div style="height: auto;width: 90%;margin: 0 auto;">
<div class="partthree_title"><span>证件公示(健康证)</span></div>
<div class="partthree_title2"><div class="fegexian2" style="margin-top: 2px;"></div></div>
<div style="width: 100%; height:100%; ">
<carousel :per-page="4" :mouse-drag="true" :autoplay="true" :autoplay-timeout="4000" :loop="true" >
<slide v-for="(item, index) in staffNums" :key="index">
<div style="padding: 10px;;width: 240px;overflow: hidden;">
<img style="width: 240px; object-fit: cover;" :src="item.healthCertFrontImg"/>
</div>
</slide>
</carousel>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import VueCarousel from 'vue-carousel';
Vue.use(VueCarousel);
import axios from 'axios';
import Cookies from 'js-cookie';
import { getCurrentRecipeListApi,getCertificateListApi,getMorningCheckInfoApi } from "@/api/view";
import * as echarts from 'echarts';
export default {
name: "Index",
data() {
return {
version: "24.7.1",
mealNum:0,
dateTime:'',
hourTime:'',
countTime:0,
sysTime:0,
timer:null,
timer2:null,
morningCheckNum:0, //晨检数
morningCheckPerc:0,//晨检比
morningCheckAbno:0,//晨检异常数
healthNum:0, //健康证数
healthPerc:0,//健康证比
healthAbno:0,//健康证异常数
onedataList:[{"dishesName":"无菜单","salePrice":""}],
twodataList:[{"dishesName":"无菜单","salePrice":""}],
threedataList:[{"dishesName":"无菜单","salePrice":""}],
fourdataList:[{"dishesName":"无菜单","salePrice":""}],
fivedataList:[{"dishesName":"无菜单","salePrice":""}],
staffNums:[],
dataForm:{type:1},
angle:0,
queryParams: {
pageNum: 1,
pageSize: 10,
key:"2",
applyDate:"",
areaId:null,
canteenId:null,
stallId:null,
recipeName:"",
},
// 存储图表实例用于销毁和resize
chartOne: null,
chartFour: null
};
},
created() {
},
mounted() {
this.handleLogin()
window.addEventListener('popstate', this.handlePopState);
this.getMorningCheck()
this.timer = setInterval(() => {
this.initData();
}, 600000);
this.timer2 = setInterval(this.getCurrentTime, 1000);
setTimeout(()=>{
this.initData();
},1500)
// ------------ 1. 禁止左右滑动:添加事件监听 ------------
document.addEventListener('touchstart', this.handleTouchStart);
document.addEventListener('touchmove', this.handleTouchMove, { passive: false });
document.addEventListener('wheel', this.handleWheel, { passive: false });
// 监听窗口resize确保图表自适应
window.addEventListener('resize', this.handleWindowResize);
},
beforeDestroy() {
window.removeEventListener('popstate', this.handlePopState);
clearInterval(this.timer);
clearInterval(this.timer2);
// ------------ 移除滑动事件监听 ------------
document.removeEventListener('touchstart', this.handleTouchStart);
document.removeEventListener('touchmove', this.handleTouchMove);
document.removeEventListener('wheel', this.handleWheel);
window.removeEventListener('resize', this.handleWindowResize);
// 销毁图表实例,避免内存泄漏
if (this.chartOne) this.chartOne.dispose();
if (this.chartFour) this.chartFour.dispose();
},
computed: {
groupedBreakfastList() {
if (!this.onedataList || this.onedataList.length === 0) {
return [];
}
const hasTypeName = this.onedataList.some(item => item.dishesTypeName);
if (!hasTypeName) {
return [{ typeName: '', dishes: this.onedataList, isBreakfastMingdang: false }];
}
const typeMap = {};
this.onedataList.forEach(item => {
const typeName = item.dishesTypeName || '其他';
if (!typeMap[typeName]) typeMap[typeName] = [];
typeMap[typeName].push(item);
});
const result = [];
if (typeMap['早餐-明档']) {
result.push({ typeName: '早餐-明档', dishes: typeMap['早餐-明档'], isBreakfastMingdang: true });
delete typeMap['早餐-明档'];
}
if (typeMap['早餐明档']) {
result.push({ typeName: '早餐明档', dishes: typeMap['早餐明档'], isBreakfastMingdang: true });
delete typeMap['早餐明档'];
}
Object.keys(typeMap).forEach(typeName => {
if (typeMap[typeName].length > 0) {
result.push({ typeName, dishes: typeMap[typeName], isBreakfastMingdang: false });
}
});
return result;
},
groupedLunchList() {
if (!this.twodataList || this.twodataList.length === 0) return [];
const hasTypeName = this.twodataList.some(item => item.dishesTypeName);
if (!hasTypeName) return [{ typeName: '', dishes: this.twodataList }];
const typeMap = {};
this.twodataList.forEach(item => {
const typeName = item.dishesTypeName || '其他';
if (!typeMap[typeName]) typeMap[typeName] = [];
typeMap[typeName].push(item);
});
const lunchOrder = ['午餐-荤菜', '午餐-炒菜', '午餐-素菜', '午餐-汤类', '午餐-五谷杂粮', '荤菜', '炒菜', '素菜', '汤类', '五谷杂粮','杂粮'];
const result = [];
lunchOrder.forEach(typeName => {
if (typeMap[typeName]?.length > 0) {
result.push({ typeName, dishes: typeMap[typeName] });
delete typeMap[typeName];
}
});
Object.keys(typeMap).forEach(typeName => {
if (typeMap[typeName].length > 0) result.push({ typeName, dishes: typeMap[typeName] });
});
return result;
},
groupedAfternoonTeaList() {
if (!this.threedataList || this.threedataList.length === 0) return [];
const hasTypeName = this.threedataList.some(item => item.dishesTypeName);
if (!hasTypeName) return [{ typeName: '', dishes: this.threedataList }];
const typeMap = {};
this.threedataList.forEach(item => {
const typeName = item.dishesTypeName || '其他';
if (!typeMap[typeName]) typeMap[typeName] = [];
typeMap[typeName].push(item);
});
return Object.keys(typeMap).map(typeName => ({ typeName, dishes: typeMap[typeName] }));
},
groupedDinnerList() {
if (!this.fourdataList || this.fourdataList.length === 0) return [];
const hasTypeName = this.fourdataList.some(item => item.dishesTypeName);
if (!hasTypeName) return [{ typeName: '', dishes: this.fourdataList }];
const typeMap = {};
this.fourdataList.forEach(item => {
const typeName = item.dishesTypeName || '其他';
if (!typeMap[typeName]) typeMap[typeName] = [];
typeMap[typeName].push(item);
});
return Object.keys(typeMap).map(typeName => ({ typeName, dishes: typeMap[typeName] }));
},
groupedNightSnackList() {
if (!this.fivedataList || this.fivedataList.length === 0) return [];
const hasTypeName = this.fivedataList.some(item => item.dishesTypeName);
if (!hasTypeName) return [{ typeName: '', dishes: this.fivedataList }];
const typeMap = {};
this.fivedataList.forEach(item => {
const typeName = item.dishesTypeName || '其他';
if (!typeMap[typeName]) typeMap[typeName] = [];
typeMap[typeName].push(item);
});
return Object.keys(typeMap).map(typeName => ({ typeName, dishes: typeMap[typeName] }));
}
},
methods: {
// ------------ 2. 禁止左右滑动相关方法 ------------
handlePopState(event) {
event.preventDefault();
},
// 记录触摸起始位置
handleTouchStart(e) {
this.touchStartX = e.touches[0].clientX;
this.touchStartY = e.touches[0].clientY;
},
// 阻止横向滑动
handleTouchMove(e) {
if (!this.touchStartX || !this.touchStartY) return;
const diffX = e.touches[0].clientX - this.touchStartX;
const diffY = e.touches[0].clientY - this.touchStartY;
// 横向滑动距离大于纵向,阻止默认行为(避免浏览器前进/后退)
if (Math.abs(diffX) > Math.abs(diffY)) {
e.preventDefault();
}
},
// 阻止横向滚轮
handleWheel(e) {
if (e.deltaX !== 0) {
e.preventDefault();
}
},
// 窗口resize时图表自适应
handleWindowResize() {
if (this.chartOne) this.chartOne.resize();
if (this.chartFour) this.chartFour.resize();
},
// 原有业务方法
handleLogin(){
let param = {
code: "",
loginType: "PHONE_PASSWORD",
password: "e07e2a30f7431f4aa173e8ba4e97fedc",
phoneUuid: "",
username: "60064de642247faee1559140f80c7246",
uuid: "",
verificationCode: ""
}
this.$store.dispatch('Login',param).then(res => {}).catch(() => {})
},
refrespage(){
this.$router.go(0);
return;
},
getMorningCheck(){
getMorningCheckInfoApi({type:1}).then(res => {
this.morningCheckNum=res.data.morningCheckNum;
this.morningCheckAbno=res.data.morningCheckAbno;
this.healthNum=res.data.healthNum;
this.healthAbno=res.data.healthAbno;
this.sysTime=Number(res.data.thisTime)
// 确保DOM渲染完成后初始化图表
this.$nextTick(() => {
this.initChartOne();
this.initChartFour();
});
});
},
getCurrentTime() {
this.countTime = this.countTime+1000;
var nowTime = this.countTime+this.sysTime
const now = new Date(nowTime);
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
this.dateTime = year+'-'+month+'-'+day;
this.hourTime = hours+':'+minutes+':'+seconds;
},
initData(){
this.queryParams.applyDate=this.dateTime;
getCurrentRecipeListApi(this.queryParams).then(response => {
if(response.rows!=null&&response.rows.length>0){
const datas= response.rows[0].detail.detailList;
if(datas!=null&&datas.length>0){
datas.map((item,index)=>{
if("1"==item.mealtimeType){
if(item.dishesList!=null&&item.dishesList.length>0){
this.onedataList=item.dishesList;
}
}else if("2"==item.mealtimeType){
if(item.dishesList!=null&&item.dishesList.length>0){
this.twodataList=item.dishesList;
}
}else if("3"==item.mealtimeType){
if(item.dishesList!=null&&item.dishesList.length>0){
this.threedataList=item.dishesList;
}
}else if("4"==item.mealtimeType){
if(item.dishesList!=null&&item.dishesList.length>0){
this.fourdataList=item.dishesList;
}
}else if(""==item.mealtimeType){
if(item.dishesList!=null&&item.dishesList.length>0){
this.fivedataList=item.dishesList;
}
}
})
}
}
});
this.queryParams.pageNum=1;
this.queryParams.pageSize=20;
getCertificateListApi(this.queryParams).then(res => {
this.staffNums=res.rows;
});
},
goTarget(href) {
window.open(href, "_blank");
},
// ------------ 3. 图表初始化(统一配置,确保大小一致) ------------
initChartOne() {
this.morningCheckPerc = this.morningCheckNum == 0 ? 0 : ((this.morningCheckNum - this.morningCheckAbno) / this.morningCheckNum * 100).toFixed(2);
// 确保容器存在再初始化
if (!this.$refs.chartone) return;
this.chartOne = echarts.init(this.$refs.chartone);
// 统一图表配置
const option = {
title: {
text: `${this.morningCheckPerc}%`,
subtext: '合格率',
x: 'center',
y: 'center',
subtextStyle: { fontSize: 15, color: '#fff' },
textStyle: { fontWeight: 'normal', color: '#0580f2', fontSize: 15 }
},
color: ['rgba(176, 212, 251, 1)'],
legend: { show: false },
series: [{
name: 'Line 1',
type: 'pie',
clockWise: true,
radius: ['76%', '96%'], // 统一环形大小
itemStyle: { normal: { label: { show: false }, labelLine: { show: false } } },
hoverAnimation: false,
data: [
{
value: this.morningCheckNum - this.morningCheckAbno,
name: '01',
itemStyle: {
normal: {
color: {
colorStops: [{ offset: 0, color: '#00cefc' }, { offset: 1, color: '#367bec' }]
}
}
}
},
{ name: '02', value: this.morningCheckAbno }
]
}]
};
this.chartOne.setOption(option);
},
initChartFour() {
this.healthPerc = this.healthNum == 0 ? 0 : ((this.healthNum - this.healthAbno) / this.healthNum * 100).toFixed(2);
if (!this.$refs.chartfour) return;
this.chartFour = echarts.init(this.$refs.chartfour);
// 完全复用左边图表的配置,仅修改数据
const option = {
title: {
text: `${this.healthPerc}%`,
subtext: '合格率',
x: 'center',
y: 'center',
subtextStyle: { fontSize: 15, color: '#fff' },
textStyle: { fontWeight: 'normal', color: '#0580f2', fontSize: 15 }
},
color: ['rgba(176, 212, 251, 1)'],
legend: { show: false },
series: [{
name: 'Line 1',
type: 'pie',
clockWise: true,
radius: ['76%', '96%'], // 与左边图表统一
itemStyle: { normal: { label: { show: false }, labelLine: { show: false } } },
hoverAnimation: false,
data: [
{
value: this.healthNum - this.healthAbno,
name: '01',
itemStyle: {
normal: {
color: {
colorStops: [{ offset: 0, color: '#00cefc' }, { offset: 1, color: '#367bec' }]
}
}
}
},
{ name: '02', value: this.healthAbno }
]
}]
};
this.chartFour.setOption(option);
},
closeView(){
Cookies.remove('password')
this.$router.push({ path:'/login' });
},
getDisplayTypeName(typeName) {
if (!typeName) return '';
return typeName.replace(/^(早餐-|午餐-|下午茶-|晚餐-|夜宵-)/, '');
},
},
};
</script>
<style lang="scss" scoped>
/* ------------ 4. 禁止横向滚动样式 ------------ */
html, body, #app, .container {
width: 100%;
height: 100%;
overflow-x: hidden !important; /* 关键:禁止横向滚动 */
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
height: 100%;
width: 100%;
background-image: url("../assets/images/background.jpg");
background-size: cover;
background-position: center;
overflow-y: hidden; /* 保留垂直滚动(如果内容超出屏幕) */
// display: flex;
// justify-content: center;
// flex-wrap: wrap;
}
.topdiv{
width: 100%;
display: flex;
background-image: url("../assets/images/canteen1.png");
background-size: cover;
background-position: center;
height: 5%;
margin-bottom: 20px;
}
.titlediv{
display: flex;
width: 40%;
justify-content: center;
font-family: Alibaba PuHuiTi 2.0, Alibaba PuHuiTi 20;
font-weight: normal;
font-size: 34px;
color: #E1EFFF;
}
.dateTimeClass{
display: flex;
justify-content: center;
color:#fff;
width:30%;
align-items: center;
}
.hourTimeClass{
display: flex;
justify-content: center;
align-items: center;
color:#fff;
width:30%;
}
.titlediv2{
display: flex;
width: 100%;
// height: 10px;
justify-content: center;
align-items: flex-start;
color:#fff;
font-size: 28px;
// background-image: url("../assets/images/caidanline.png");
// background-size: cover;
// background-position:bottom;
}
.contentclass{
display: flex;
width: 100%;
justify-content: center;
flex-wrap: wrap;
color:#fff;
}
.fegexian{
width: 50%;
height: 5px;
// background-image: url("../assets/images/caidanline.png");
// background-size: cover;
// background-position: center;
}
.fegexian2{
width: 50%;
height: 5px;
background-image: url("../assets/images/caidanline.png");
background-size: cover;
background-position: center;
}
.dishclass{
font-family: Alibaba PuHuiTi 2.0, Alibaba PuHuiTi 20;
font-weight: normal;
font-size: 24px;
color: #D8E2FF;
text-align: left;
font-style: normal;
text-transform: none;
display: flex;
align-items: center;
margin: 1%;
}
.dishclass span{
background-image: linear-gradient(0deg, rgba(111,169,255,0.5) 30%, #6FA9FF 86%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.dishcontentclass{
display: flex;
align-items: flex-end;
flex-wrap: wrap;
margin-top: 1%;
font-family: Alibaba PuHuiTi 2.0, Alibaba PuHuiTi 20;
font-weight: normal;
font-size: 22px;
color: #D8E2FF;
text-align: left;
font-style: normal;
padding-bottom: 1%;
}
.dishcontentrefclass{
width: 22%;
margin-left: 2%;
margin-right: 1%;
margin-bottom: 10px;
}
.dishtypeclass{
width: 20%;
margin-left: 2%;
margin-bottom: 1%;
font-family: Alibaba PuHuiTi 2.0, Alibaba PuHuiTi 20;
font-weight: bold;
font-size: 24px;
color: #6FA9FF;
text-align: left;
font-style: normal;
}
.partthree{
height: 100%;
width: 85%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
.partthree_title{
display: flex;
color:#fff;
font-size: 25px;
justify-content: center;
margin-bottom: 5px;
}
.partthree_title2{
display: flex;
height: 20px;
width: 100%;
justify-content: center;
}
.big-number {
font-size: 30px;
font-family: 'Arial', sans-serif;
color: #fff;
padding: 5px;
border-radius: 10px;
display: inline-flex;
}
.digit {
margin: 0 5px;
text-shadow: 0 0 10px rgba(255,255,255,0.5);
}
table, th, td {
text-align: center;
}
</style>