|
|
|
|
@ -39,9 +39,20 @@
|
|
|
|
|
<n-grid-item v-for="item in deviceDataList" :key="item.code">
|
|
|
|
|
<div class="device-card" :class="getStatus(item.status).className">
|
|
|
|
|
<div>设备编码 : {{ item.code }}</div>
|
|
|
|
|
<div>状态 : {{ getStatus(item.status).text }}</div>
|
|
|
|
|
<div>开始时间 : {{ item.startTime }}</div>
|
|
|
|
|
<div>加工数量 : {{ item.count }}</div>
|
|
|
|
|
<div>设备类型 : 开料机</div>
|
|
|
|
|
<div>运行状态 : {{ getStatus(item.status).text }}</div>
|
|
|
|
|
<div>产品型号 : {{ item.productModel }}</div>
|
|
|
|
|
<div>生产产量 :
|
|
|
|
|
<count-to
|
|
|
|
|
:start-value="1"
|
|
|
|
|
:end-value="item.count"
|
|
|
|
|
:duration="800"
|
|
|
|
|
:autoplay="true"
|
|
|
|
|
:use-easing="true"
|
|
|
|
|
easing-function="cubicOut"
|
|
|
|
|
class="animated-number"
|
|
|
|
|
/></div>
|
|
|
|
|
<div>生产速率 : <span style="color:yellow">{{item.rate}}</span> 个/分</div>
|
|
|
|
|
<div>结束日期 : {{ item.endTime }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</n-grid-item>
|
|
|
|
|
@ -59,10 +70,12 @@ import { useResetSearch } from '~/src/utils/common/searchReset';
|
|
|
|
|
import {useSearchBtn} from '~/src/hooks/common/useBtn';
|
|
|
|
|
import {formatDate} from '~/src/utils/form/rule';
|
|
|
|
|
import {GradientBg} from './components';
|
|
|
|
|
|
|
|
|
|
const {searchForm, reset} = useResetSearch({
|
|
|
|
|
location: '全部'
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const productModels = ['LX25-Y39-002金', 'LX30-Y40-005浅蓝', 'LX35-Z25-006蓝灰', 'LX40-B02-002黑', 'LX30-Y40-005蓝', 'LX35-Z5-004白', 'LX25-A08-007黑'
|
|
|
|
|
, 'LX-Y39-030黑', 'LX20-Y30-010灰', 'LX35-Z5-006蓝', 'LX40-B01-003黑', 'LX30-Y42-002蓝', 'LX35-Z15-004单蓝', 'LX25-A08-006灰']; // 产品型号列表
|
|
|
|
|
interface CardData {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
@ -79,6 +92,12 @@ type device = {
|
|
|
|
|
count: number;
|
|
|
|
|
endTime: string;
|
|
|
|
|
process: string;
|
|
|
|
|
productModel: string;
|
|
|
|
|
timerId?: number;
|
|
|
|
|
interval: number;
|
|
|
|
|
originalCode: string; // 新增字段记录原始编码
|
|
|
|
|
currentModelIndex: number; // 新增字段用于跟踪当前型号索引
|
|
|
|
|
rate?: String;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const deviceAllList = ref<Array<device>>([]);
|
|
|
|
|
@ -96,7 +115,7 @@ const cardData = reactive<CardData[]>([
|
|
|
|
|
{
|
|
|
|
|
id: 'visit',
|
|
|
|
|
title: '设备总数',
|
|
|
|
|
value: 72,
|
|
|
|
|
value: 0,
|
|
|
|
|
unit: '',
|
|
|
|
|
colors: ['#ec4786', '#b955a4'],
|
|
|
|
|
icon: 'ant-design:bar-chart-outlined'
|
|
|
|
|
@ -104,7 +123,7 @@ const cardData = reactive<CardData[]>([
|
|
|
|
|
{
|
|
|
|
|
id: 'amount',
|
|
|
|
|
title: '运行中',
|
|
|
|
|
value: 60,
|
|
|
|
|
value: 40,
|
|
|
|
|
unit: '$',
|
|
|
|
|
colors: ['#865ec0', '#5144b4'],
|
|
|
|
|
icon: 'ant-design:money-collect-outlined'
|
|
|
|
|
@ -112,7 +131,7 @@ const cardData = reactive<CardData[]>([
|
|
|
|
|
{
|
|
|
|
|
id: 'download',
|
|
|
|
|
title: '待机',
|
|
|
|
|
value: 10,
|
|
|
|
|
value: 9,
|
|
|
|
|
unit: '',
|
|
|
|
|
colors: ['#56cdf3', '#719de3'],
|
|
|
|
|
icon: 'carbon:document-download'
|
|
|
|
|
@ -216,7 +235,7 @@ async function getList() {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// cardData[0].value = deviceAllList.value.length;
|
|
|
|
|
cardData[0].value = deviceAllList.value.length;
|
|
|
|
|
init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -227,9 +246,11 @@ function deviceEach(item: any) {
|
|
|
|
|
value: item.process
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
deviceAllList.value.push({
|
|
|
|
|
let interval = Math.floor((16 + Math.random() * 10)) * 1000;
|
|
|
|
|
const newDevice = reactive({
|
|
|
|
|
code: item.equipmentCode,
|
|
|
|
|
status: 0,
|
|
|
|
|
productModel: productModels[getRandom(1, 4)],
|
|
|
|
|
startTime: formatDate(
|
|
|
|
|
new Date(getRandom(new Date().getTime() - 1000 * 60 * 60 * 48, new Date().getTime())),
|
|
|
|
|
'yyyy-MM-dd hh:mm:ss'
|
|
|
|
|
@ -239,10 +260,40 @@ function deviceEach(item: any) {
|
|
|
|
|
new Date(getRandom(new Date().getTime(), new Date().getTime() + 1000 * 60 * 60 * 48)),
|
|
|
|
|
'yyyy-MM-dd'
|
|
|
|
|
),
|
|
|
|
|
process: item.process
|
|
|
|
|
process: item.process,
|
|
|
|
|
originalCode: item.equipmentCode,
|
|
|
|
|
currentModelIndex: 0,
|
|
|
|
|
interval: interval, // 生成16-24秒随机间隔
|
|
|
|
|
// count: 0,
|
|
|
|
|
timerId: undefined,
|
|
|
|
|
rate: (60 * 1000 / interval).toFixed(1)
|
|
|
|
|
});
|
|
|
|
|
startDeviceTimer(newDevice); // 为每个设备启动独立定时器
|
|
|
|
|
deviceAllList.value.push(newDevice);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 为单个设备启动定时器
|
|
|
|
|
function startDeviceTimer(device: device) {
|
|
|
|
|
device.timerId = window.setInterval(() => {
|
|
|
|
|
device.count++;
|
|
|
|
|
if (device.count >= 200) {
|
|
|
|
|
resetDeviceProduction(device);
|
|
|
|
|
}
|
|
|
|
|
}, device.interval); // 20秒间隔
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 重置设备生产数据
|
|
|
|
|
function resetDeviceProduction(device: device) {
|
|
|
|
|
device.count = 0;
|
|
|
|
|
device.currentModelIndex = (device.currentModelIndex + 1) % productModels.length;
|
|
|
|
|
device.productModel = productModels[device.currentModelIndex];
|
|
|
|
|
clearInterval(device.timerId);
|
|
|
|
|
device.interval = Math.floor((15 + Math.random() * 10)) * 1000; // 重置时生成新间隔
|
|
|
|
|
device.rate = (60 * 1000 / device.interval).toFixed(1);
|
|
|
|
|
startDeviceTimer(device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getRandom(min: number, max: number) {
|
|
|
|
|
return Math.floor(Math.random() * (max - min + 1) + min);
|
|
|
|
|
}
|
|
|
|
|
@ -268,15 +319,21 @@ function init() {
|
|
|
|
|
deviceDataList.value = deviceAllList.value.filter(item => item.process === searchForm.value.location);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 定时器逻辑
|
|
|
|
|
let intervalId: number;
|
|
|
|
|
// 组件挂载时连接 MQTT
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
connectToMQTT();
|
|
|
|
|
init();
|
|
|
|
|
getList();
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 组件卸载时断开 MQTT 连接
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
deviceAllList.value.forEach(device => {
|
|
|
|
|
if (device.timerId) clearInterval(device.timerId);
|
|
|
|
|
});
|
|
|
|
|
if (client) {
|
|
|
|
|
client.end();
|
|
|
|
|
}
|
|
|
|
|
@ -284,8 +341,6 @@ onUnmounted(() => {
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
/* 你的样式 */
|
|
|
|
|
|
|
|
|
|
.device-card {
|
|
|
|
|
color: #fff;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
@ -305,4 +360,19 @@ onUnmounted(() => {
|
|
|
|
|
.trade-color {
|
|
|
|
|
background: linear-gradient(45deg, #fcbc25, #f68057);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 添加数字变化动画 */
|
|
|
|
|
.flip-animation {
|
|
|
|
|
transition: transform 0.5s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.flip-animation-up {
|
|
|
|
|
transform: translateY(-20px);
|
|
|
|
|
opacity: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.flip-animation-down {
|
|
|
|
|
transform: translateY(20px);
|
|
|
|
|
opacity: 0;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|