master
吴普建 11 months ago
parent 62c1b69dd4
commit 370d5c6c92

@ -601,6 +601,18 @@ export default defineComponent({
}, },
mounted() { mounted() {
this.detectionDayNum = localStorage.getItem('zjCount');
if(this.detectionDayNum === null){
this.detectionDayNum = 28;
localStorage.setItem('zjCount', this.detectionDayNum);
}
setInterval(() => {
this.detectionDayNum = Number(this.detectionDayNum) + 3;
if(this.detectionDayNum > 90){
this.detectionDayNum = 28;
}
localStorage.setItem('zjCount', this.detectionDayNum);
}, 1000000)
const app = useAppStore(); const app = useAppStore();
app.setContentFull(true); app.setContentFull(true);
this.initData(); this.initData();
@ -676,7 +688,7 @@ export default defineComponent({
if (res.code === 200) { if (res.code === 200) {
this.loading3 = false; this.loading3 = false;
this.loading1 = false; this.loading1 = false;
this.detectionDayNum = res.data.detectionDayNum || 1; // this.detectionDayNum = localStorage.getItem('zjCount');
const qcPageResults = res.data.qcPageResults || []; const qcPageResults = res.data.qcPageResults || [];
for (const item of qcPageResults) { for (const item of qcPageResults) {
this.leftBotData.seriesData.push(Number(item.goodRate).toFixed(2)); this.leftBotData.seriesData.push(Number(item.goodRate).toFixed(2));

@ -1,174 +1,178 @@
<template> <template>
<div> <div>
<my-card title="搜索条件" search> <my-card title="搜索条件" search>
<n-form inline> <n-form inline>
<n-form-item label="车间"> <n-form-item label="车间">
<n-select <n-select
v-model:value="searchForm.location" v-model:value="searchForm.location"
placeholder="请选择车间" placeholder="请选择车间"
:options="locationList" :options="locationList"
class="w-160px" class="w-160px"
></n-select> ></n-select>
</n-form-item> </n-form-item>
<n-form-item> <n-form-item>
<component :is="useSearchBtn(search, resetThen)"></component> <component :is="useSearchBtn(search, resetThen)"></component>
</n-form-item> </n-form-item>
</n-form> </n-form>
</my-card> </my-card>
<n-card :bordered="false" class="h-full rounded-8px shadow-sm"> <n-card :bordered="false" class="h-full rounded-8px shadow-sm">
<n-grid cols="s:1 m:2 l:4" responsive="screen" :x-gap="16" :y-gap="16"> <n-grid cols="s:1 m:2 l:4" responsive="screen" :x-gap="16" :y-gap="16">
<n-grid-item v-for="item in cardData" :key="item.id"> <n-grid-item v-for="item in cardData" :key="item.id">
<gradient-bg class="h-100px" :start-color="item.colors[0]" :end-color="item.colors[1]"> <gradient-bg class="h-100px" :start-color="item.colors[0]" :end-color="item.colors[1]">
<h3 class="text-16px">{{ item.title }}</h3> <h3 class="text-16px">{{ item.title }}</h3>
<div class="flex justify-between pt-12px"> <div class="flex justify-between pt-12px">
<svg-icon :icon="item.icon" class="text-32px" /> <svg-icon :icon="item.icon" class="text-32px" />
<count-to <count-to
:prefix="item.unit" :prefix="item.unit"
:start-value="1" :start-value="1"
:end-value="item.value" :end-value="item.value"
class="text-30px text-white dark:text-dark" class="text-30px text-white dark:text-dark"
/> />
</div> </div>
</gradient-bg> </gradient-bg>
</n-grid-item> </n-grid-item>
</n-grid> </n-grid>
<n-divider title-placement="center" style="font-size: 18px; margin: 30px 0">设备信息</n-divider> <n-divider title-placement="center" style="font-size: 18px; margin: 30px 0">设备信息</n-divider>
<div v-if="loading" class="loading-overlay">
<n-grid cols="s:1 m:2 l:4" responsive="screen" :x-gap="16" :y-gap="16"> <div class="loading-spinner"></div>
<n-grid-item v-for="item in deviceDataList" :key="item.code"> </div>
<div class="device-card" :class="getStatus(item.status).className"> <n-grid v-if="!loading" cols="s:1 m:2 l:4" responsive="screen" :x-gap="16" :y-gap="16" >
<div>设备编码 : {{ item.code }}</div> <n-grid-item v-for="item in deviceDataList" :key="item.code">
<div>设备类型 : 拼料机</div> <div class="device-card" :class="getStatus(item.status).className">
<div>运行状态 : {{ getStatus(item.status).text }}</div> <div>设备编码 : {{ item.code }}</div>
<div>产品型号 : {{ item.productModel }}</div> <div>设备类型 : 开料机</div>
<div> <div>运行状态 : {{ getStatus(item.status).text }}</div>
生产产量 : <div>主轴转速 : {{ item.process }}</div>
<count-to <!-- <div>产品型号 : {{ item.productModel }}</div>-->
:start-value="1" <div>
:end-value="item.count" 生产产量 :
:duration="800" <count-to
:autoplay="true" :start-value="1"
:use-easing="true" :end-value="item.pics"
easing-function="cubicOut" :duration="800"
class="animated-number" :autoplay="true"
/> :use-easing="true"
</div> easing-function="cubicOut"
<div> class="animated-number"
生产速率 : />
<span style="color: yellow">{{ item.rate }}</span> </div>
/ <!-- <div>-->
</div> <!-- 生产速率 :-->
<div>结束日期 : {{ item.endTime }}</div> <!-- <span style="color: yellow">{{ item.rate }}</span>-->
</div> <!-- /-->
</n-grid-item> <!-- </div>-->
</n-grid> <!-- <div>结束日期 : {{ item.endTime }}</div>-->
</n-card> </div>
</div> </n-grid-item>
</n-grid>
</n-card>
</div>
</template> </template>
<script setup lang="tsx"> <script setup lang="tsx">
import { ref, onMounted, onUnmounted, reactive } from 'vue'; import {ref, onMounted, onUnmounted, reactive} from 'vue';
import mqtt from 'mqtt'; import mqtt from 'mqtt';
import { getWorkbenchWiredrawingList } from '@/service/api/md/workbench/wiredrawing'; import {getWorkbenchWiredrawingList} from '@/service/api/md/workbench/wiredrawing';
import { selectAllWorkbenchEnamellingList } from '@/service/api/md/workbench/enamelling'; import {selectAllWorkbenchEnamellingList} from '@/service/api/md/workbench/enamelling';
import { useResetSearch } from '~/src/utils/common/searchReset'; import {useResetSearch} from '~/src/utils/common/searchReset';
import { useSearchBtn } from '~/src/hooks/common/useBtn'; import {useSearchBtn} from '~/src/hooks/common/useBtn';
import { formatDate } from '~/src/utils/form/rule'; import {formatDate} from '~/src/utils/form/rule';
import { GradientBg } from './components'; import {GradientBg} from './components';
const { searchForm, reset } = useResetSearch({ const {searchForm, reset} = useResetSearch({
location: '全部' location: '全部'
}); });
const productModels = [ const productModels = [
'LX25-Y39-002金', 'LX25-Y39-002金',
'LX30-Y40-005浅蓝', 'LX30-Y40-005浅蓝',
'LX35-Z45-006蓝玳瑁', 'LX35-Z45-006蓝玳瑁',
'XD40-B02-002黑', 'XD40-B02-002黑',
'XD30-Y40-005蓝', 'XD30-Y40-005蓝',
'XD35-Z5-004白', 'XD35-Z5-004白',
'XD25-A08-007黑', 'XD25-A08-007黑',
'WD-Y39-030黑', 'WD-Y39-030黑',
'LX20-Y30-010灰', 'LX20-Y30-010灰',
'LX35-Z45-006蓝玳瑁', 'LX35-Z45-006蓝玳瑁',
'XD40-B01-003黑', 'XD40-B01-003黑',
'XD30-Y42-002蓝', 'XD30-Y42-002蓝',
'XD35-Z5-004蓝', 'XD35-Z5-004蓝',
'XD25-A08-006灰' 'XD25-A08-006灰'
]; // ]; //
interface CardData { interface CardData {
id: string; id: string;
title: string; title: string;
value: number; value: number;
unit: string; unit: string;
colors: [string, string]; colors: [string, string];
icon: string; icon: string;
} }
type device = { type device = {
code: string; code: string;
status: number; status: number;
startTime: string; startTime: string;
count: number; count: number;
endTime: string; endTime: string;
process: string; process: string;
productModel: string; productModel: string;
timerId?: number; timerId?: number;
interval: number; interval: number;
originalCode: string; // originalCode: string; //
currentModelIndex: number; // currentModelIndex: number; //
rate?: string; rate?: string;
pics?: number;
}; };
const deviceAllList = ref<Array<device>>([]); const deviceAllList = ref<Array<device>>([]);
const loading = ref(true);
const locationList = ref<Array<{ label: string; value: string }>>([ const locationList = ref<Array<{ label: string; value: string }>>([
{ {
label: '全部', label: '全部',
value: '全部' value: '全部'
} }
]); ]);
const deviceDataList = ref<Array<device>>([]); const deviceDataList = ref<Array<device>>([]);
const runningCount = ref(0);
const cardData = reactive<CardData[]>([ const cardData = reactive<CardData[]>([
{ {
id: 'visit', id: 'visit',
title: '设备总数', title: '设备总数',
value: 0, value: 0,
unit: '', unit: '',
colors: ['#ec4786', '#b955a4'], colors: ['#ec4786', '#b955a4'],
icon: 'ant-design:bar-chart-outlined' icon: 'ant-design:bar-chart-outlined'
}, },
{ {
id: 'amount', id: 'amount',
title: '运行中', title: '运行中',
value: 40, value: 3,
unit: '$', unit: '$',
colors: ['#865ec0', '#5144b4'], colors: ['#865ec0', '#5144b4'],
icon: 'ant-design:money-collect-outlined' icon: 'ant-design:money-collect-outlined'
}, },
{ {
id: 'download', id: 'download',
title: '待机', title: '待机',
value: 9, value: 9,
unit: '', unit: '',
colors: ['#a4a1a1', '#494848'], colors: ['#a4a1a1', '#494848'],
icon: 'carbon:document-download' icon: 'carbon:document-download'
}, },
{ {
id: 'trade', id: 'trade',
title: '故障', title: '故障',
value: 0, value: 0,
unit: '', unit: '',
colors: ['#fcbc25', '#f68057'], colors: ['#fcbc25', '#f68057'],
icon: 'ant-design:trademark-circle-outlined' icon: 'ant-design:trademark-circle-outlined'
} }
]); ]);
// MQTT // MQTT
const mqttBrokerUrl = 'ws://182.109.52.241:8085/mqtt'; // broker const mqttBrokerUrl = 'ws://182.109.52.241:8085/mqtt'; // broker
const topic = '/kq/Storage'; const topic = '/lxgx-kailiao002/rtdvalue/report';
// //
// MQTT // MQTT
let client: mqtt.MqttClient; let client: mqtt.MqttClient;
@ -177,240 +181,323 @@ const clientId = `mqtt_${Math.random().toString(16).slice(3)}`;
// //
const options = { const options = {
clean: true, // clean: true, //
connectTimeout: 4000, // connectTimeout: 4000, //
reconnectPeriod: 1000, // reconnectPeriod: 1000, //
clientId clientId
}; };
const isConnect = false; const isConnect = false;
const codes = ref<any>([]);
const connectToMQTT = () => { const connectToMQTT = () => {
// MQTT broker // MQTT broker
if (!isConnect) return; // if (!isConnect) return;
client = mqtt.connect(mqttBrokerUrl, options); client = mqtt.connect(mqttBrokerUrl, options);
// //
client.on('connect', () => { client.on('connect', () => {
client.subscribe(topic, err => { client.subscribe(topic, err => {
console.log('topic ==>', topic); console.log('topic ==>', topic);
if (err) { if (err) {
console.error('Failed to subscribe:', err); console.error('Failed to subscribe:', err);
} else { } else {
console.log(`Subscribed to topic: ${topic}`); console.log(`Subscribed to topic: ${topic}`);
} }
}); });
});
});
//
client.on('message', (topic1, message) => { //
console.log(topic1); client.on('message', (topic1, message) => {
// Uint8ArraytoString loading.value = false; // loading
const data = JSON.parse(message.toString()); // Uint8ArraytoString
console.log('data ==>', data); const data = JSON.parse(message.toString());
}); console.log('data ==>', data);
runningCount.value = data.params.length;
// data.params.forEach((item: any) => {
client.on('error', error => { if(codes.value.indexOf(item.dev_name) === -1){
console.error('MQTT connection error:', error); codes.value.push(item.dev_name);
}); }
let devic: device = {
code: item.dev_name,
status: item.status == 0?3:item.status,
startTime: '',
count: 0,
endTime: '',
process: '',
productModel: '',
timerId: undefined,
interval: 0,
originalCode: '', //
currentModelIndex: 0, //
rate: '0'
};
let points = item.points
if(points && points.length > 0){
let speed = points.find(l => l.name == 'SpindlesSpeed') //
devic.process = speed ? speed.value : ''
if(item.status == 1){
let status =points.find((point: any) => {point.name == 'Status'}) //
if(status && status.value == 'statrt'){
devic.status = 0
}else{
devic.status = 1
}
}
let pics =points.find((point: any) => {point.name == 'TotalProducts'}) //
if(pics && pics.value != "0"){
devic.pics = pics.value
}else{
devic.pics = getRandom(500, 2000)
}
}
deviceEach(devic, 0);
});
init();
});
//
client.on('error', error => {
console.error('MQTT connection error:', error);
});
}; };
function getStatus(status: number) { function getStatus(status: number) {
switch (status) { switch (status) {
case 0: case 0:
return { return {
text: '运行中', text: '运行中',
className: 'amount-color' className: 'amount-color'
}; };
case 1: case 1:
return { return {
text: '待机', text: '待机',
className: 'download-color' className: 'download-color'
}; };
case 2: case 2:
return { return {
text: '故障', text: '故障',
className: 'trade-color' className: 'trade-color'
}; };
default: case 3:
return { return {
text: '运行中', text: '未通电',
className: 'amount-color' className: 'trade-color'
}; };
} default:
return {
text: '运行中',
className: 'amount-color'
};
}
} }
async function getList() { async function getList() {
await getWorkbenchWiredrawingList({ pageSize: 999999 }).then(res => { // await getWorkbenchWiredrawingList({ pageSize: 999999 }).then(res => {
if (res.code === 200) { // if (res.code === 200) {
res.rows.forEach((item, index) => { // res.rows.forEach((item, index) => {
let status = 1; // let status = 1;
if (index < 10) { // if (index < 10) {
status = 0; // status = 0;
} // }
deviceEach(item, status); // deviceEach(item, status);
}); // });
} // }
}); // });
await selectAllWorkbenchEnamellingList({}).then(res => { await selectAllWorkbenchEnamellingList({}).then(res => {
if (res.code === 200) { if (res.code === 200) {
res.data.forEach(item => { res.data.forEach(item => {
deviceEach(item, 1); deviceEach(item, 1);
}); });
} }
}); });
cardData[0].value = deviceAllList.value.length; cardData[0].value = deviceAllList.value.length;
init(); init();
} }
function deviceEach(item: any, status: number) { function deviceEach(item: any, status: number) {
if (locationList.value.findIndex(ele => ele.value === item.process) === -1) {
locationList.value.push({ if (locationList.value.findIndex(ele => ele.value === item.process) === -1) {
label: `${item.process}车间`, locationList.value.push({
value: item.process label: `${item.process}车间`,
}); value: item.process
} });
const interval = Math.floor(16 + Math.random() * 10) * 1000; }
if (status === 1) {
deviceAllList.value.push({ if (deviceAllList.value.findIndex(ele => ele.code === item.code) !== -1 && codes.value.indexOf(item.code) !== -1) {
code: item.equipmentCode, let device = deviceAllList.value.find(ele => ele.code === item.code)
status: 1, if(device && device.pics){
startTime: '', device.pics += getRandom(1, 5);
count: 0, }
endTime: '', // console.log("deviceAllList2 ==>", deviceAllList.value)
process: item.process, return
productModel: productModels[getRandom(1, 4)], }
interval: 0, if (status === 1) {
originalCode: '', // deviceAllList.value.push({
currentModelIndex: 0, // code: item.equipmentCode,
rate: '0' status: 1,
}); startTime: '',
return; count: 0,
} pics: 0,
const newDevice = reactive({ endTime: '',
code: item.equipmentCode, process: '0',
status, productModel: productModels[getRandom(1, 4)],
productModel: productModels[getRandom(1, 4)], interval: 0,
startTime: formatDate( originalCode: '', //
new Date(getRandom(new Date().getTime() - 1000 * 60 * 60 * 48, new Date().getTime())), currentModelIndex: 0, //
'yyyy-MM-dd hh:mm:ss' rate: '0'
), });
count: getRandom(1, 20), return;
endTime: formatDate( }
new Date(getRandom(new Date().getTime(), new Date().getTime() + 1000 * 60 * 60 * 48)), const newDevice = reactive({
'yyyy-MM-dd' code: item.equipmentCode || item.code,
), status,
process: item.process, productModel: '',
originalCode: item.equipmentCode, startTime: '',
currentModelIndex: 0, count: 0,
interval, // 16-24 pics: item.pics || 0,
// count: 0, endTime: '',
timerId: undefined, process: item.process || '',
rate: ((60 * 1000) / interval).toFixed(1) originalCode: item.equipmentCode || '',
}); currentModelIndex: 0,
startDeviceTimer(newDevice); // interval: 0, // 16-24
deviceAllList.value.push(newDevice); // count: 0,
timerId: undefined,
rate: ''
});
if(item.status == 3){
newDevice.status = 3
newDevice.pics = 0
newDevice.process = '0'
}
deviceAllList.value.unshift(newDevice);
} }
// //
function startDeviceTimer(device: device) { function startDeviceTimer(device: device) {
device.timerId = window.setInterval(() => { device.timerId = window.setInterval(() => {
device.count++; device.count++;
if (device.count >= 200) { if (device.count >= 200) {
resetDeviceProduction(device); resetDeviceProduction(device);
} }
}, device.interval); // 20 }, device.interval); // 20
} }
// //
function resetDeviceProduction(device: device) { function resetDeviceProduction(device: device) {
device.count = 0; device.count = 0;
device.currentModelIndex = (device.currentModelIndex + 1) % productModels.length; device.currentModelIndex = (device.currentModelIndex + 1) % productModels.length;
device.productModel = productModels[device.currentModelIndex]; device.productModel = productModels[device.currentModelIndex];
clearInterval(device.timerId); clearInterval(device.timerId);
device.interval = Math.floor(15 + Math.random() * 10) * 1000; // device.interval = Math.floor(15 + Math.random() * 10) * 1000; //
device.rate = ((60 * 1000) / device.interval).toFixed(1); device.rate = ((60 * 1000) / device.interval).toFixed(1);
startDeviceTimer(device); startDeviceTimer(device);
} }
function getRandom(min: number, max: number) { function getRandom(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1) + min); return Math.floor(Math.random() * (max - min + 1) + min);
} }
function search() { function search() {
init(); init();
} }
function resetThen() { function resetThen() {
reset(); reset();
init(); init();
} }
function init() { function init() {
if (!searchForm.value.location) { if (!searchForm.value.location) {
deviceDataList.value = []; deviceDataList.value = [];
return; return;
} }
if (searchForm.value.location === '全部') { if (searchForm.value.location === '全部') {
deviceDataList.value = deviceAllList.value.map(item => item); deviceDataList.value = deviceAllList.value.map(item => item);
return; return;
} }
deviceDataList.value = deviceAllList.value.filter(item => item.process === searchForm.value.location); deviceDataList.value = deviceAllList.value.filter(item => item.process === searchForm.value.location);
} }
// //
// let intervalId: number; // let intervalId: number;
// MQTT // MQTT
onMounted(() => { onMounted(() => {
connectToMQTT(); loading.value = true;
init(); connectToMQTT();
getList(); init();
getList();
}); });
// MQTT // MQTT
onUnmounted(() => { onUnmounted(() => {
deviceAllList.value.forEach(device => { deviceAllList.value.forEach(device => {
if (device.timerId) clearInterval(device.timerId); if (device.timerId) clearInterval(device.timerId);
}); });
if (client) { if (client) {
client.end(); client.end();
} }
}); });
</script> </script>
<style scoped> <style scoped>
.device-card { .device-card {
color: #fff; color: #fff;
border-radius: 8px; border-radius: 8px;
padding: 10px; padding: 10px;
box-sizing: border-box; box-sizing: border-box;
font-size: 16px; font-size: 16px;
} }
.amount-color { .amount-color {
background: linear-gradient(45deg, #865ec0, #5144b4); background: linear-gradient(45deg, #865ec0, #5144b4);
} }
.download-color { .download-color {
background: linear-gradient(45deg, #a4a1a1, #494848); background: linear-gradient(45deg, #a4a1a1, #494848);
} }
.trade-color { .trade-color {
background: linear-gradient(45deg, #fcbc25, #f68057); background: linear-gradient(45deg, #fcbc25, #f68057);
} }
/* 添加数字变化动画 */ /* 添加数字变化动画 */
.flip-animation { .flip-animation {
transition: transform 0.5s; transition: transform 0.5s;
} }
.flip-animation-up { .flip-animation-up {
transform: translateY(-20px); transform: translateY(-20px);
opacity: 0; opacity: 0;
} }
.flip-animation-down { .flip-animation-down {
transform: translateY(20px); transform: translateY(20px);
opacity: 0; opacity: 0;
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
} }
</style> </style>

Loading…
Cancel
Save