1.排名屏及led屏

This commit is contained in:
2026-03-16 16:10:40 +08:00
parent d86ac6a2ec
commit f032c31e22
12 changed files with 980 additions and 233 deletions
+4
View File
@@ -11,3 +11,7 @@ VUE_APP_ST_MQTT_URL = 192.168.1.210
VUE_APP_ST_MQTT_PORT = 61614
VUE_APP_CT_MQTT_URL = vip.shuziweidao.com
VUE_APP_CT_MQTT_PORT = 61614
VUE_APP_LED_MQTT_URL = dev.yixiong-tech.com
VUE_APP_LED_MQTT_PORT = 18083
VUE_APP_LED_MQTT_USERNAME = test
VUE_APP_LED_MQTT_PASSWORD = Yx123456
+4
View File
@@ -10,3 +10,7 @@ VUE_APP_ST_MQTT_URL = 192.168.1.210
VUE_APP_ST_MQTT_PORT = 61614
VUE_APP_CT_MQTT_URL = vip.shuziweidao.com
VUE_APP_CT_MQTT_PORT = 61614
VUE_APP_LED_MQTT_URL = dev.yixiong-tech.com
VUE_APP_LED_MQTT_PORT = 18083
VUE_APP_LED_MQTT_USERNAME = test
VUE_APP_LED_MQTT_PASSWORD = Yx123456
+56
View File
@@ -24,6 +24,7 @@
"process": "^0.11.10",
"regenerator-runtime": "^0.14.1",
"stream-browserify": "^3.0.0",
"swiper": "^5.4.5",
"url": "^0.11.4",
"util": "^0.12.5",
"vue": "^2.6.14",
@@ -4812,6 +4813,15 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/dom7": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/dom7/-/dom7-2.1.5.tgz",
"integrity": "sha512-xnhwVgyOh3eD++/XGtH+5qBwYTgCm0aW91GFgPJ3XG+jlsRLyJivnbP0QmUBFhI+Oaz9FV0s7cxgXHezwOEBYA==",
"license": "MIT",
"dependencies": {
"ssr-window": "^2.0.0"
}
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/domelementtype/-/domelementtype-2.3.0.tgz",
@@ -9877,6 +9887,12 @@
"node": ">= 6"
}
},
"node_modules/ssr-window": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-2.0.0.tgz",
"integrity": "sha512-NXzN+/HPObKAx191H3zKlYomE5WrVIkoCB5IaSdvKokxTpjBdWfr0RaP+1Z5KOfDT0ZVz+2tdtiBkhsEQ9p+0A==",
"license": "MIT"
},
"node_modules/ssri": {
"version": "8.0.1",
"resolved": "https://registry.npmmirror.com/ssri/-/ssri-8.0.1.tgz",
@@ -10070,6 +10086,24 @@
"node": ">= 10"
}
},
"node_modules/swiper": {
"version": "5.4.5",
"resolved": "https://registry.npmjs.org/swiper/-/swiper-5.4.5.tgz",
"integrity": "sha512-7QjA0XpdOmiMoClfaZ2lYN6ICHcMm72LXiY+NF4fQLFidigameaofvpjEEiTQuw3xm5eksG5hzkaRsjQX57vtA==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"dom7": "^2.1.5",
"ssr-window": "^2.0.0"
},
"engines": {
"node": ">= 4.7.0"
},
"funding": {
"type": "patreon",
"url": "https://www.patreon.com/vladimirkharlampidi"
}
},
"node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmmirror.com/tapable/-/tapable-2.2.1.tgz",
@@ -14655,6 +14689,14 @@
}
}
},
"dom7": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/dom7/-/dom7-2.1.5.tgz",
"integrity": "sha512-xnhwVgyOh3eD++/XGtH+5qBwYTgCm0aW91GFgPJ3XG+jlsRLyJivnbP0QmUBFhI+Oaz9FV0s7cxgXHezwOEBYA==",
"requires": {
"ssr-window": "^2.0.0"
}
},
"domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/domelementtype/-/domelementtype-2.3.0.tgz",
@@ -18378,6 +18420,11 @@
}
}
},
"ssr-window": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-2.0.0.tgz",
"integrity": "sha512-NXzN+/HPObKAx191H3zKlYomE5WrVIkoCB5IaSdvKokxTpjBdWfr0RaP+1Z5KOfDT0ZVz+2tdtiBkhsEQ9p+0A=="
},
"ssri": {
"version": "8.0.1",
"resolved": "https://registry.npmmirror.com/ssri/-/ssri-8.0.1.tgz",
@@ -18531,6 +18578,15 @@
}
}
},
"swiper": {
"version": "5.4.5",
"resolved": "https://registry.npmjs.org/swiper/-/swiper-5.4.5.tgz",
"integrity": "sha512-7QjA0XpdOmiMoClfaZ2lYN6ICHcMm72LXiY+NF4fQLFidigameaofvpjEEiTQuw3xm5eksG5hzkaRsjQX57vtA==",
"requires": {
"dom7": "^2.1.5",
"ssr-window": "^2.0.0"
}
},
"tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmmirror.com/tapable/-/tapable-2.2.1.tgz",
+1
View File
@@ -23,6 +23,7 @@
"process": "^0.11.10",
"regenerator-runtime": "^0.14.1",
"stream-browserify": "^3.0.0",
"swiper": "^5.4.5",
"url": "^0.11.4",
"util": "^0.12.5",
"vue": "^2.6.14",
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

+4 -5
View File
@@ -3,11 +3,10 @@ import {getServeUrl} from "@/utils/serveUrl";
let mqttClient = null;
export const initMqtt = (clientId, topic, type) => {
console.log(getServeUrl(type + 'MqttUrl'));
export const initMqtt = (clientId, topic, type, {username='sw_mqtt', password='150326sw@', head='ws'}) => {
return new Promise((resolve, reject) => {
const url = {
head: "ws", // 必须是 ws 或 wss mqtt:// 或 mqtts:// 必须让后端开放websocket服务)
head: head, // 必须是 ws 或 wss mqtt:// 或 mqtts:// 必须让后端开放websocket服务)
host: getServeUrl(type + 'MqttUrl'), // 服务地址
port: getServeUrl(type + 'MqttPORT'), // 服务端口
tailPath: "mqtt", // 服务路径
@@ -15,8 +14,8 @@ export const initMqtt = (clientId, topic, type) => {
const options = {
clientId: clientId,
username: "sw_mqtt",
password: "150326sw@",
username: username,
password: password,
// keepalive: 60,
clean: true,
cleanSession: true,
+6
View File
@@ -19,6 +19,12 @@ const getServeUrl = function(type) {
case 'ctMqttPORT':
serveUrl = process.env.VUE_APP_CT_MQTT_PORT;
break;
case 'ledMqttUrl':
serveUrl = process.env.VUE_APP_LED_MQTT_URL;
break;
case 'ledMqttPORT':
serveUrl = process.env.VUE_APP_LED_MQTT_PORT;
break;
}
return serveUrl;
};
+606 -53
View File
@@ -8,27 +8,45 @@
<div class="total-d">
<div>
<div>
<span>108</span>
<span>
<countTo
:startVal="dataInitOverview.userCount ? dataInitOverview.userCount : 0"
:endVal="dataOverview.userCount"
separator=""
:duration="1500" />
</span>
<span></span>
</div>
<div>用餐总人数</div>
</div>
<div>
<div>
<span>919</span>
<span>
<countTo
:startVal="dataInitOverview.perCalorie ? dataInitOverview.perCalorie : 0"
:endVal="dataOverview.perCalorie"
separator=""
:duration="1500" />
</span>
<span>千卡</span>
</div>
<div>人均热量</div>
</div>
<div>
<div>
<span>80</span>
<span>
<countTo
:startVal="dataInitOverview.perScore ? dataInitOverview.perScore : 0"
:endVal="dataOverview.perScore"
separator=""
:duration="1500" />
</span>
<span></span>
</div>
<div>人均营养分</div>
</div>
</div>
<div class="total-right">午餐10:30~13:30</div>
<div class="total-right">{{dinnerType}} {{mealTimeStart && mealTimeEnd ? `(${mealTimeStart} ~ ${mealTimeEnd})` : ''}}</div>
</div>
<div class="table-top">
<div>
@@ -38,17 +56,9 @@
</span>
</div>
<div>
<div>
<img src="@/assets/images/bigScreen/boy.png" alt="" />
* 89 第一
</div>
<div>
<img src="@/assets/images/bigScreen/girl.png" alt="" />
* 88 第一名
</div>
<div>
<img src="@/assets/images/dataBoard/user.png" alt="" />
陈知夏 86 第一名
<div v-for="(item,index) in listData.slice(0, 2)" :key="`top-list-data-${index}`">
<img style="border-radius: 8px" :src="item.faceUrl || require('@/assets/images/bigScreen/user.png')" alt="" />
{{preName(item.name)}} {{item.userScore}} {{index+1}}
</div>
</div>
</div>
@@ -57,12 +67,16 @@
<div class="table-title">
<div>排名</div>
<div>
<div>用户信息</div>
<div>健康得分</div>
<div>下单时间</div>
<div class="table-info-one">用户信息</div>
<div class="table-title-point table-info-two">
健康得分
<img src="@/assets/images/dataBoard/down.png" alt="" />
</div>
<div class="table-info-three">下单时间</div>
</div>
</div>
<div class="table-item" v-for="(item, index) in 10" :key="`list-data-${index}`">
<transition-group name="flip-list" tag="div" style="flex: 1;overflow: auto;">
<div class="table-item" v-for="(item, index) in listData" :key="`list-data-${index}`">
<div class="index-item">
<template v-if="index === 0">
<img src="@/assets/images/bigScreen/1.png" alt="" />
@@ -78,54 +92,352 @@
{{index+1}}
</div>
</template>
<img class="title-img" src="@/assets/images/bigScreen/boy.png" alt="" />
<img style="border-radius: 8px" class="title-img" :src="item.faceUrl || require('@/assets/images/bigScreen/user.png')" alt="" />
</div>
<div>
<div>用户信息</div>
<div>健康得分</div>
<div>下单时间</div>
<div class="table-info-one">{{preName(item.name)}}</div>
<div class="table-info-two" style="color: #FFB99C">{{ item.userScore}}</div>
<div class="table-info-three">{{preDate(item.orderDate)}}</div>
</div>
</div>
</transition-group>
</div>
<div class="table-right-d">
<div class="table-right-d-title">
餐品热度排行榜
</div>
<div class="table-right-d-body">
<transition-group name="flip-list" tag="div" class="progress-d">
<div class="progress-d-item" v-for="(item, index) in valList" :key="`val-list-${index}`">
<div style="color: #FFFFFF;display: flex;align-items: center">
<template v-if="index === 0">
<img src="@/assets/images/bigScreen/1.png" alt="" />
</template>
<template v-else-if="index === 1">
<img src="@/assets/images/bigScreen/2.png" alt="" />
</template>
<template v-else-if="index === 2">
<img src="@/assets/images/bigScreen/3.png" alt="" />
</template>
<template v-else>
<div class="index-d">
{{index+1}}
</div>
</template>
<div class="index-name">{{item.foodName}}</div>
</div>
<div>
<div :style="{width: item.weightPoint + '%'}" style="border-radius: 50px;height: 100%;transition: width 0.5s ease-in-out;" :class="getProgressClass(item.weightPoint )"></div>
</div>
</div>
</transition-group>
<div class="swiper-d">
<div class="swiper-container" v-if="swiperList.length !== 0">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="(item, index) in swiperList" :key="`slide-${index}`">
<!-- 图片轮播 -->
<img
v-if="item.type === '1'"
:src="item.url"
class="swiper-content"
alt="轮播图片"
/>
<!-- 视频轮播 -->
<video
v-else-if="item.type === '2'"
class="swiper-content"
:ref="`videRef${index}`"
:src="item.url"
@ended="onVideoEnded"
>
</video>
</div>
</div>
</div>
<div class="no-data-d" v-else>
<div>
<div style="display: flex;align-items: center;justify-content: center">
<img src="@/assets/images/bigScreen/noData.png" alt="" />
</div>
<div class="no-data-msg">
<div>
欢迎用餐
</div>
<div>
<div>均衡饮食很重要</div> <div>你我生活都需要</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="table-right-d"></div>
</div>
<div class="footer-d">
数智餐厅
</div>
</div>
</template>
<script setup lang="ts">
import {onBeforeUnmount, onMounted, ref} from "vue";
<script>
import * as dayjs from "dayjs";
import 'dayjs/locale/zh-cn';
import Swiper from 'swiper';
import 'swiper/css/swiper.css';
import {httpRequest} from "@/XMLHttpRequest";
import countTo from "vue-count-to";
import {callBackMqttMessage, initMqtt} from "@/utils/mqtt";
const nowTimeInterval = ref()
const nowTime = ref(dayjs())
const listData = ref([
{
name: '',
point: '',
time: '',
export default {
name: 'DataBoard',
components: {
countTo
},
data() {
return {
url: "https://dev.yixiong-tech.com:8081/terminal/neglect/large-screen/ranking",
nowTimeInterval: null,
nowTime: dayjs(),
dinnerType: '',
mealTimeStart: '',
mealTimeEnd: '',
dataInitOverview: {
userCount: 0,
perCalorie: 0,
perScore: 0
},
dataOverview: {
userCount: 0,
perCalorie: 0,
perScore: 0
},
listData: [],
// 餐品热度数据:包含名称和热度值
valList: [],
// 轮播数据:支持图片和视频
swiperList: [
// { type: '1', src: require('@/assets/images/bigScreen/1.png'), duration: 3000 },
// { type: '2', src: require('@/assets/images/bigScreen/demo.mp4'), duration: 0 },
// { type: '1', src: require('@/assets/images/bigScreen/1.png'), duration: 3000 },
// { type: '2', src: require('@/assets/images/bigScreen/demo.mp4'), duration: 0 }
],
// 当前轮播索引
currentSwiperIndex: 0,
// 轮播定时器
swiperTimer: null,
// 是否正在播放视频
isPlayingVideo: false,
// Swiper 实例引用
swiperInstance: null,
}
},
created() {
this.initMttqF()
},
mounted() {
callBackMqttMessage(() => {
console.log('loadData===')
this.initData();
})
this.initTime();
this.initData();
// this.$nextTick(() => {
// this.initSwiper();
// this.startSwiperAutoPlay();
// });
// this.startRandomVal();
},
beforeDestroy() {
if (this.nowTimeInterval) {
clearInterval(this.nowTimeInterval);
}
if (this.swiperTimer) {
clearTimeout(this.swiperTimer);
}
if (this.swiperInstance) {
this.swiperInstance.destroy();
}
},
methods: {
initMttqF() {
initMqtt('deviceId-' + Math.random().toString(16).substring(2, 8),'yx/device/rankingScreen/needUpdate','led', {username: process.env.VUE_APP_LED_MQTT_USERNAME, password: process.env.VUE_APP_LED_MQTT_PASSWORD, head: 'wss'})
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
})
},
preName(name) {
if (name === '匿名用户') return name
if (name.length < 3) {
return name.substring(0, 1) + '*'
} else {
return name.replace(/^(.)(.*?)(.)$/, (match, first, middle, last) => {
return first + '*'.repeat(middle.length) + last;
})
}
},
preDate(d) {
return dayjs(d).format('HH:mm:ss');
},
initData() {
let _this = this;
httpRequest("GET", this.url , {}, {"authorization": "57ee87183f2a4fa59683ec9ef41c8f5d"}).then(function (res) {
if (res?.code === '00000') {
_this.dinnerType = res.data.dinnerType;
_this.dataOverview = res.data.dataOverview || {
userCount: 0,
perCalorie: 0,
perScore: 0
};
_this.mealTimeStart = res.data.mealTimeStart;
_this.mealTimeEnd = res.data.mealTimeEnd;
_this.listData = res.data.userScoreInfos || [];
const maxWeight = res.data.foodSortInfos && res.data.foodSortInfos.length > 0 ? res.data.foodSortInfos[0].foodWeight || 0 : 0;
_this.valList = (res.data.foodSortInfos || []).map((item) => {
item['weightPoint'] = maxWeight === 0 ? 0 : parseFloat(((item?.foodWeight || 0) / maxWeight * 100).toFixed(2));
return item;
});
_this.swiperList = res.data.fileList || [];
if (_this.swiperInstance) {
_this.swiperInstance.destroy();
}
if (_this.swiperTimer) {
clearTimeout(_this.swiperTimer);
}
_this.$nextTick(() => {
_this.initSwiper();
_this.startSwiperAutoPlay();
});
} else {
}
}).catch(function(err) {
console.log(err)
})
},
preTime(time) {
return `${dayjs(time).format('YYYY年MM月DD日 HH:mm:ss')} ${dayjs(time).locale('zh-cn').format('dddd')}`
},
// 初始化时间
initTime() {
this.nowTime = dayjs();
this.nowTimeInterval = setInterval(() => {
this.nowTime = dayjs();
}, 1000);
},
// 生成随机热度值并排序
randomVal() {
this.valList.forEach(item => {
item.value = (Math.floor(Math.random() * 10) + 1) * 10;
});
// 按热度值降序排列
this.valList.sort((a, b) => b.value - a.value);
},
// 启动随机更新
startRandomVal() {
setInterval(() => {
this.randomVal();
}, 1500);
},
// 根据热度值返回对应的进度条样式类
getProgressClass(val) {
if (val < 30) {
return ['small-progress'];
}
if (val > 50) {
return ['large-progress'];
}
return ['middle-progress'];
},
// 初始化 Swiper
initSwiper() {
if (!this.swiperList || this.swiperList.length === 0) return;
this.swiperInstance = new Swiper('.swiper-container', {
loop: true,
grabCursor: true,
slidesPerView: 1,
spaceBetween: 0,
on: {
slideChangeTransitionEnd: () => {
this.onSlideChangeTransitionEnd();
},
slideChange: () => {
this.onSwiperSlideChange();
}
}
});
},
// Swiper 滑动事件处理
onSwiperSlideChange() {
if (!this.swiperInstance || this.swiperList.length === 0) return
// 获取当前索引
const realIndex = this.swiperInstance.activeIndex;
this.currentSwiperIndex = realIndex;
// 清除之前的定时器
if (this.swiperTimer) {
clearTimeout(this.swiperTimer);
}
const currentIndex = realIndex === 0 ? 0 : realIndex > this.swiperList.length ? 0 : realIndex - 1;
// 获取当前幻灯片数据
const currentItem = this.swiperList[currentIndex];
if (this.swiperList[currentIndex !== 0 ? currentIndex - 1 : this.swiperList.length - 1].type === 'video') {
const refD = this.$refs[`videRef${currentIndex !== 0 ? currentIndex - 1 : this.swiperList.length - 1}`];
if (refD.length > 0 && refD[0]) {
refD[0].currentTime = 0;
refD[0].pause();
}
const refD1 = this.$refs[`videRef${currentIndex === this.swiperList.length ? this.swiperList.length - 1 : currentIndex + 1 }`];
if (refD1.length > 0 && refD1[0]) {
refD1[0].currentTime = 0;
refD1[0].pause();
}
}
if (currentItem.type === '1') {
// 图片:按设定时长自动切换
this.swiperTimer = setTimeout(() => {
this.swiperInstance.slideNext();
}, 3000);
} else if (currentItem.type === '2') {
// 视频:等待播放完毕后切换
this.isPlayingVideo = true;
}
},
onSlideChangeTransitionEnd () {
if (!this.swiperInstance) return
// 获取当前索引
const realIndex = this.swiperInstance.activeIndex;
this.currentSwiperIndex = realIndex;
const currentIndex = realIndex === 0 ? 0 : realIndex > this.swiperList.length ? 0 : realIndex - 1;
const currentItem = this.swiperList[currentIndex];
if (currentItem.type === '2') {
const refD = this.$refs[`videRef${currentIndex}`]
if (refD && refD.length > 0) {
refD[0].muted = true;
refD[0].play().catch(() => {
refD[0].muted = true;
refD[0].play();
})
}
}
},
// 视频播放完毕回调
onVideoEnded() {
this.isPlayingVideo = false;
if (this.swiperInstance) {
this.swiperInstance.slideNext();
}
},
// 启动轮播自动播放
startSwiperAutoPlay() {
// 初始化时触发一次
this.onSwiperSlideChange();
}
}
])
onMounted(() => {
getNowTime();
})
function getNowTime() {
nowTimeInterval.value = setInterval(() => {
nowTime.value = dayjs(nowTime.value).add(1, 'seconds')
}, 1000)
}
function preTime(time) {
return `${dayjs(time).format('YYYY年MM月DD日 HH:mm:ss')} ${dayjs(time).locale('zh-cn').format('dddd')}`
}
onBeforeUnmount(() => {
nowTimeInterval.value && clearInterval(nowTimeInterval.value)
})
</script>
<style scoped lang="less">
.outer-d {
@@ -238,6 +550,8 @@
.bottom-d {
flex: 1;
padding: 10px 100px 20px;
display: flex;
overflow: hidden;
> div {
&:nth-child(1) {
@@ -253,7 +567,7 @@
display: flex;
flex-direction: column;
.table-title {
background: #6F9DFF;
background: #2f487e;
border-radius: 5px;
padding: 3px 40px;
color: #8CCAFF;
@@ -269,14 +583,54 @@
width: calc(100% / 3 * 2);
}
}
.table-title-point {
display: flex;
align-items: center;
position: relative;
img {
position: absolute;
width: 18px;
height: 18px;
right: -8px;
}
}
.table-info-one {
width: 90px;
text-align: left;
}
.table-info-two {
width: 90px;
text-align: center;
}
.table-info-three {
width: 90px;
text-align: center;
}
}
.table-item {
flex: 1;
height: 10%;
padding: 15px 40px 3px;
color: #8CCAFF;
font-size: 18px;
display: flex;
align-items: center;
.table-info-one {
width: 90px;
text-align: left;
}
.table-info-two {
width: 90px;
text-align: center;
}
.table-info-three {
width: 90px;
text-align: center;
}
> div {
display: flex;
justify-content: space-between;
@@ -313,6 +667,147 @@
}
}
.table-right-d {
padding-left: 60px;
color: #FFFFFF;
font-family: 'HarmonyOS Sans SC';
height: 100%;
display: flex;
flex-direction: column;
.table-right-d-title {
font-size: 20px;
background: #2f487e;
padding: 4px 20px;
border-radius: 5px;
}
.table-right-d-body {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
.progress-d {
padding: 20px 15px 15px;
height: calc(100% - 270px);
display: flex;
flex-direction: column;
overflow: hidden auto;
.progress-d-item {
margin-top: 10px;
height: calc(100% / 6 - 10px);
img {
width: 23px;
height: 23px;
margin-right: 15px;
}
>div {
&:nth-child(1) {
margin-bottom: 5px;
}
&:nth-child(2) {
height: 10px;
background: #1f2635;
border-radius: 50px;
}
}
.index-d {
height: 23px;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
padding-left: 7px;
}
.index-name {
font-size: 20px;
}
}
}
.swiper-d {
flex: 1;
height: 270px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
overflow: hidden;
position: relative;
width: 100%;
background: #183159;
.swiper-container {
width: 100%;
height: 100%;
position: relative;
}
.swiper-wrapper {
width: 100%;
height: 100%;
display: flex;
}
.no-data-d {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
left: 0;
img {
width: 100px;
height: 80px;
margin-bottom: 10px;
}
.no-data-msg {
text-align: center;
> div {
&:nth-child(1) {
font-size: 27px;
}
&:nth-child(2) {
margin-top: 5px;
font-size: 18px;
display: flex;
> div {
&:nth-child(1) {
padding-right: 13px;
}
&:nth-child(2) {
padding-left: 13px;
}
}
}
}
}
}
.swiper-slide {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.swiper-content {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
animation: fadeIn 0.5s ease-in-out;
}
}
}
}
}
.footer-d {
@@ -322,4 +817,62 @@
color: #8CCAFF;
}
}
.small-progress {
background: #45FFA1;
}
.middle-progress {
background: #FFFD45;
}
.large-progress {
background: linear-gradient(-90deg, #FF0048, #FFAB61);
}
// 列表排序动画
.flip-list-move {
transition: transform 0.6s ease-in-out;
}
// 轮播淡入动画
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
::-webkit-scrollbar {
width: 2px; /* 垂直滚动条宽度 */
height: 2px; /* 水平滚动条高度 */
}
/* 滚动条轨道 */
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
/* 滚动条滑块 */
::-webkit-scrollbar-thumb {
background: #888;
border-radius: 10px;
}
/* 滑块悬停效果 */
::-webkit-scrollbar-thumb:hover {
background: #555;
}
/* 滚动条两端按钮 */
::-webkit-scrollbar-button {
display: none;
}
/* 边角(两个滚动条交汇处) */
::-webkit-scrollbar-corner {
background: #f1f1f1;
}
</style>
+50 -47
View File
@@ -3,7 +3,7 @@
<template v-if="deviceData">
<div class="deviceData">
<div class="detailHeader">
<div>餐品热量</div>
<div>{{deviceData.foodName || '暂无餐品'}}</div>
<div>{{ deviceData.calorie }}千卡/100</div>
</div>
<div class="detailImg">
@@ -13,12 +13,12 @@
<div></div>
</div>
<div class="detailFooter">
<div class="detailFooter-1">
<div>{{ deviceData.foodName }}</div>
<template v-if="deviceData.differenceWeight">
<div>({{ deviceData.differenceWeight }})</div>
</template>
</div>
<!-- <div class="detailFooter-1">-->
<!-- <div class="detailFooter-1-food-name">{{ deviceData.foodName }}</div>-->
<!-- <template v-if="deviceData.makeFoodWeight">-->
<!-- <div>({{ deviceData.makeFoodWeight }}kg)</div>-->
<!-- </template>-->
<!-- </div>-->
<div class="detailFooter-2">
<template v-for="item in deviceData.labelList">
<div>{{ item }}</div>
@@ -26,16 +26,20 @@
</div>
<div class="detailFooter-3">
<div>
<div>{{ deviceData.realNameWeight }}</div>
<div>实名取用</div>
<div>{{ deviceData.makeFoodWeight }}</div>
<div>总制作量(kg)</div>
</div>
<div>
<div>{{ deviceData.marginWeight }}</div>
<div>余量</div>
<div :style="{ color: Number(deviceData.differenceWeight) > 0 ? '#F24439' : '' }">{{ deviceData.differenceWeight }}</div>
<div>异常损耗(kg)</div>
</div>
<div>
<div :style="{ color: Number(deviceData.anonymityWeight) > 0 ? '#F24439' : '' }">{{ deviceData.anonymityWeight }}</div>
<div>匿名取用</div>
<div>{{ deviceData.totalFoodWeight }}</div>
<div>总售卖量(kg)</div>
</div>
<div>
<div :style="{ color: Number(deviceData.marginWeight) > 0 ? '#95f204' : '#F24439' }">{{ deviceData.marginWeight }}</div>
<div>当前余量(kg)</div>
</div>
</div>
</div>
@@ -51,21 +55,21 @@
<div class="detailFooter-1">
<div>暂无餐品</div>
</div>
<div class="detailFooter-2"></div>
<div class="detailFooter-3">
<div>
<div>-</div>
<div>实名取</div>
</div>
<div>
<div>-</div>
<div>余量</div>
</div>
<div>
<div>-</div>
<div>匿名取用</div>
</div>
</div>
<!-- <div class="detailFooter-2"></div>-->
<!-- <div class="detailFooter-3">-->
<!-- <div>-->
<!-- <div>-</div>-->
<!-- <div>实名取(kg)</div>-->
<!-- </div>-->
<!-- <div>-->
<!-- <div>-</div>-->
<!-- <div>余量(kg)</div>-->
<!-- </div>-->
<!-- <div>-->
<!-- <div>-</div>-->
<!-- <div>异常损耗(kg)</div>-->
<!-- </div>-->
<!-- </div>-->
</div>
</div>
</template>
@@ -103,15 +107,15 @@ export default {
.detailHeader {
position: absolute;
z-index: 3;
width: 170px;
height: 64px;
width: 232px;
height: 78px;
top: 0;
left: 0;
right: 0;
margin: auto;
padding-top: 6px;
box-sizing: border-box;
background-image: url("@/assets/images/led/header.png");
background-image: url("@/assets/images/led/headerNew.png");
background-repeat: no-repeat;
background-position: center;
background-size: cover;
@@ -120,11 +124,11 @@ export default {
width: 100%;
height: 16px;
color: #FFFFFF;
font-size: 16px;
font-size: 22px;
font-weight: 500;
line-height: 16px;
text-align: center;
margin-bottom: 8px;
margin: 11px 0 8px;
}
> div:nth-of-type(2) {
@@ -210,7 +214,7 @@ export default {
display: flex;
flex-wrap: nowrap;
justify-content: center;
margin-bottom: 14px;
margin-bottom: 10px;
> div {
margin: 0 8px;
@@ -227,25 +231,22 @@ export default {
.detailFooter-3 {
width: 100%;
height: 100%;
padding: 0 10px;
//padding: 0 10px;
box-sizing: border-box;
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
flex-wrap: wrap;
> div {
width: 0;
flex: 1;
width: 50%;
margin-bottom: 6px;
> div:nth-of-type(1) {
color: #161616;
height: 26px;
line-height: 26px;
font-size: 26px;
font-size: 24px;
font-weight: bold;
text-align: center;
margin-bottom: 6px;
}
> div:nth-of-type(2) {
@@ -255,6 +256,7 @@ export default {
font-weight: 400;
font-size: 16px;
text-align: center;
white-space: nowrap;
}
}
}
@@ -295,7 +297,7 @@ export default {
.detailFooter {
position: absolute;
z-index: 3;
width: 240px;
width: 245px;
height: 160px;
left: 0;
right: 0;
@@ -309,10 +311,10 @@ export default {
.detailFooter-1 {
width: 100%;
height: 26px;
height: 100%;
display: flex;
flex-wrap: nowrap;
align-items: end;
align-items: center;
margin-bottom: 14px;
justify-content: center;
@@ -333,7 +335,7 @@ export default {
.detailFooter-3 {
width: 100%;
height: 100%;
padding: 0 10px;
//padding: 0 10px;
box-sizing: border-box;
display: flex;
flex-wrap: nowrap;
@@ -358,8 +360,9 @@ export default {
height: 16px;
line-height: 16px;
font-weight: 400;
font-size: 16px;
font-size: 14px;
text-align: center;
white-space: nowrap;
}
}
}
+249 -128
View File
@@ -20,7 +20,8 @@
<script>
import RowDom from "./components/rowDom.vue";
// import {httpRequest} from "@/XMLHttpRequest";
import {callBackMqttMessage, initMqtt} from "@/utils/mqtt";
import {httpRequest} from "@/XMLHttpRequest";
export default {
name: "led",
@@ -29,139 +30,253 @@ export default {
},
data() {
return {
// url: "http://192.168.1.201:14801",
url: "https://dev.yixiong-tech.com:8081/",
screenWidth: 1920,
deviceDataList: [{
deviceId: '1',
data: null
}, {
deviceId: '2',
data: {
foodId: "2028767531816284161",
foodName: "蒜香鸡翅根",
foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260303/ad0b893a-1fa6-4905-b969-016c44cd29b4.png",
calorie: "116",
labelList: ['补充蛋白质', '增强免疫力'],
differenceWeight: "14.88", // 偷菜
marginWeight: "5.32", // 余量(kg
realNameWeight: "7.86", // 实名取餐重量(kg
anonymityWeight: "1.70", // 匿名取餐重量(kg
}
}, {
deviceId: '3',
data: null
}, {
deviceId: '4',
data: {
foodId: "2028273122528030722",
foodName: "杏鲍菇炒肉",
foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260302/a0c9541a-47bb-43db-bff5-053fe3d88111.png",
calorie: "59",
labelList: ['润肠通便', '提高免疫'],
differenceWeight: "12.50", // 偷菜
marginWeight: "6.18", // 余量(kg
realNameWeight: "5.42", // 实名取餐重量(kg
anonymityWeight: "0.90", // 匿名取餐重量(kg
}
}, {
deviceId: '5',
data: null
}, {
deviceId: '6',
data: {
foodId: "2029388232071933954",
foodName: "青椒鸡肉丝",
foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260305/8e833968-f88b-4918-84d0-99dcc5118b4b.png",
calorie: "43",
labelList: ['促进消化', '补充维C'],
differenceWeight: "11.92", // 偷菜
marginWeight: "4.56", // 余量(kg
realNameWeight: "6.24", // 实名取餐重量(kg
anonymityWeight: "1.12", // 匿名取餐重量(kg
}
}, {
deviceId: '7',
data: null
}, {
deviceId: '8',
data: {
foodId: "2028277177375617026",
foodName: "西红柿炒鸡蛋",
foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260302/660cc729-09cc-4b77-bfe9-9d2918714a3c.png",
calorie: "44",
labelList: ['美容养颜', '健脑益智'],
differenceWeight: "15.00", // 偷菜
marginWeight: "3.74", // 余量(kg
realNameWeight: "8.96", // 实名取餐重量(kg
anonymityWeight: "2.30", // 匿名取餐重量(kg
}
}, {
deviceId: '9',
data: null
}, {
deviceId: '10',
data: {
foodId: "2028768323575050242",
foodName: "凉拌菠菜",
foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260303/af27cd5a-325f-4d9c-bedf-4b32870f293c.png",
calorie: "30",
labelList: ['补铁补血', '明目护眼'],
differenceWeight: "12.14", // 偷菜
marginWeight: "7.20", // 余量(kg
realNameWeight: "4.38", // 实名取餐重量(kg
anonymityWeight: "0.56", // 匿名取餐重量(kg
}
}, {
deviceId: '11',
data: null
}, {
deviceId: '12',
data: {
foodId: "2031257721365442561",
foodName: "青笋炒木耳?",
foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260310/45e6f7fc-f58a-4828-b5ff-72c5a5f561da.png",
calorie: "28",
labelList: ['清热解毒', '活血化瘀'],
differenceWeight: "10.50", // 偷菜
realNameWeight: "3.82", // 实名取餐重量(kg
marginWeight: "5.94", // 余量(kg
anonymityWeight: "0.74", // 匿名取餐重量(kg
}
}, {
deviceId: '13',
data: null
}, {
deviceId: '14',
data: {
foodId: "2031248239226892289",
foodName: "玉米粒大米饭",
foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260306/db3b1d29-8a8d-4e26-a93f-fdc066959f30.png",
calorie: "137",
labelList: ['补充能量', '促进消化'],
differenceWeight: "20.00",
marginWeight: "8.64", // 余量(kg
realNameWeight: "10.26", // 实名取餐重量(kg
anonymityWeight: "1.10", // 匿名取餐重量(kg
}
}, {
deviceId: '15',
data: null
}],
// deviceDataList: [
// {
// deviceId: '1',
// data: null
// }, {
// deviceId: '2',
// data: {
// foodId: "2028767531816284161",
// foodName: "蒜香鸡翅根",
// foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260303/ad0b893a-1fa6-4905-b969-016c44cd29b4.png",
// calorie: "116",
// labelList: ['补充蛋白质', '增强免疫力'],
// differenceWeight: "14.88", // 偷菜
// marginWeight: "5.32", // 余量(kg
// realNameWeight: "7.86", // 实名取餐重量(kg
// anonymityWeight: "1.70", // 匿名取餐重量(kg
// }
// }, {
// deviceId: '3',
// data: null
// }, {
// deviceId: '4',
// data: {
// foodId: "2028273122528030722",
// foodName: "杏鲍菇炒肉",
// foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260302/a0c9541a-47bb-43db-bff5-053fe3d88111.png",
// calorie: "59",
// labelList: ['润肠通便', '提高免疫'],
// differenceWeight: "12.50", // 偷菜
// marginWeight: "6.18", // 余量(kg
// realNameWeight: "5.42", // 实名取餐重量(kg
// anonymityWeight: "0.90", // 匿名取餐重量(kg
// }
// }, {
// deviceId: '5',
// data: null
// }, {
// deviceId: '6',
// data: {
// foodId: "2029388232071933954",
// foodName: "青椒鸡肉丝",
// foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260305/8e833968-f88b-4918-84d0-99dcc5118b4b.png",
// calorie: "43",
// labelList: ['促进消化', '补充维C'],
// differenceWeight: "11.92", // 偷菜
// marginWeight: "4.56", // 余量(kg
// realNameWeight: "6.24", // 实名取餐重量(kg
// anonymityWeight: "1.12", // 匿名取餐重量(kg
// }
// }, {
// deviceId: '7',
// data: null
// }, {
// deviceId: '8',
// data: {
// foodId: "2028277177375617026",
// foodName: "西红柿炒鸡蛋",
// foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260302/660cc729-09cc-4b77-bfe9-9d2918714a3c.png",
// calorie: "44",
// labelList: ['美容养颜', '健脑益智'],
// differenceWeight: "15.00", // 偷菜
// marginWeight: "3.74", // 余量(kg
// realNameWeight: "8.96", // 实名取餐重量(kg
// anonymityWeight: "2.30", // 匿名取餐重量(kg
// }
// }, {
// deviceId: '9',
// data: null
// }, {
// deviceId: '10',
// data: {
// foodId: "2028768323575050242",
// foodName: "凉拌菠菜",
// foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260303/af27cd5a-325f-4d9c-bedf-4b32870f293c.png",
// calorie: "30",
// labelList: ['补铁补血', '明目护眼'],
// differenceWeight: "12.14", // 偷菜
// marginWeight: "7.20", // 余量(kg
// realNameWeight: "4.38", // 实名取餐重量(kg
// anonymityWeight: "0.56", // 匿名取餐重量(kg
// }
// }, {
// deviceId: '11',
// data: null
// }, {
// deviceId: '12',
// data: {
// foodId: "2031257721365442561",
// foodName: "青笋炒木耳?",
// foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260310/45e6f7fc-f58a-4828-b5ff-72c5a5f561da.png",
// calorie: "28",
// labelList: ['清热解毒', '活血化瘀'],
// differenceWeight: "10.50", // 偷菜
// realNameWeight: "3.82", // 实名取餐重量(kg
// marginWeight: "5.94", // 余量(kg
// anonymityWeight: "0.74", // 匿名取餐重量(kg
// }
// }, {
// deviceId: '13',
// data: null
// }, {
// deviceId: '14',
// data: {
// foodId: "2031248239226892289",
// foodName: "玉米粒大米饭",
// foodImg: "https://dev.yixiong-tech.com:8081/common/files/20260306/db3b1d29-8a8d-4e26-a93f-fdc066959f30.png",
// calorie: "137",
// labelList: ['补充能量', '促进消化'],
// differenceWeight: "20.00",
// marginWeight: "8.64", // 余量(kg
// realNameWeight: "10.26", // 实名取餐重量(kg
// anonymityWeight: "1.10", // 匿名取餐重量(kg
// }
// }, {
// deviceId: '15',
// data: null
// }],
deviceDataList: [],
initDeviceDataList: [
{
deviceId: '1',
data: null
},
{
deviceId: '2',
data: null
},
{
deviceId: '3',
data: null
},
{
deviceId: '4',
data: null
},
{
deviceId: '5',
data: null
},
{
deviceId: '6',
data: null
},
{
deviceId: '7',
data: null
},
{
deviceId: '8',
data: null
},
{
deviceId: '9',
data: null
},
{
deviceId: '10',
data: null
},
{
deviceId: '11',
data: null
},
{
deviceId: '12',
data: null
},
{
deviceId: '13',
data: null
},
{
deviceId: '14',
data: null
},
{
deviceId: '15',
data: null
},
],
}
},
mounted() {
callBackMqttMessage((data) => {
console.log(data)
this.getInfoByDeviceId(data?.message || {});
})
},
created() {
// this.getDeviceId();
this.initData();
this.initMttqF()
},
methods: {
// getDeviceId() {
// httpRequest("GET", this.url + "/terminal/neglect/large-screen/longScreen", {}).then(function (res) {
// console.log(res);
// }).catch(function(err) {
//
// })
// },
getInfoByDeviceId(deviceIdInfo) {
if (deviceIdInfo.deviceId === 'all') {
this.initData();
} else {
let _this = this;
if (!deviceIdInfo.deviceId) return;
httpRequest("GET", this.url+'terminal/neglect/large-screen/longScreen/device' , {deviceId: deviceIdInfo.deviceId}, {"authorization": "57ee87183f2a4fa59683ec9ef41c8f5d"})
.then((res) => {
if (res.code === '00000') {
let data = JSON.parse(JSON.stringify(_this.deviceDataList));
for (let i = 0; i < data; i++) {
if (data[i].deviceId === deviceIdInfo.deviceId) {
data[i].data = res.data;
break;
}
}
_this.deviceDataList = data;
}
})
.catch((err) => {
console.log(err)
})
}
},
initData() {
let _this = this;
httpRequest("GET", this.url+'terminal/neglect/large-screen/longScreen', {}, {"authorization": "57ee87183f2a4fa59683ec9ef41c8f5d"}).then(function (res) {
if (res?.code === '00000') {
_this.deviceDataList = res?.data?.foodList ? res?.data?.foodList.map((item, index) => {
return {
deviceId: item?.deviceId || index + '',
data: item.foodName ? item : null
}
}) : _this.initDeviceDataList;
} else {
_this.deviceDataList = _this.initDeviceDataList
}
console.log(_this.deviceDataList);
}).catch(function(err) {
console.log(err)
_this.deviceDataList = _this.initDeviceDataList
})
},
initMttqF() {
initMqtt('deviceId-' + Math.random().toString(16).substring(2, 8),'yx/device/foodRecord/needUpdate','led', {username: process.env.VUE_APP_LED_MQTT_USERNAME, password: process.env.VUE_APP_LED_MQTT_PASSWORD, head: 'wss'})
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
})
}
}
}
</script>
@@ -203,4 +318,10 @@ export default {
}
}
}
.detailFooter-1-food-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>