This commit is contained in:
朱文强 2025-02-19 14:13:47 +08:00
parent f143c5e2d9
commit b43876fe67
11 changed files with 2904 additions and 187 deletions

View File

@ -1,3 +1,10 @@
/*
* @Author: zwq
* @Date: 2024-10-29 09:47:40
* @LastEditors: zwq
* @LastEditTime: 2025-02-12 09:25:11
* @Description:
*/
import request from '@/utils/request'
// 获得工厂产线工段设备树形结构
export function getTree() {

View File

@ -58,3 +58,12 @@ export function exportFactoryExcel(query) {
responseType: 'blob'
})
}
// 获取产线设备状态
export function getLineEqStatus(data) {
return request({
url: '/base/production-line/getLineEqStatus',
method: 'post',
data: data
})
}

View File

@ -112,6 +112,7 @@
{ label: '无类型', value: 0 },
{ label: '进口统计', value: 1 },
{ label: '出口统计', value: 2 },
{ label: '进出口计数', value: 3 },
]"
:key="opt.value"
:label="opt.label"

View File

@ -0,0 +1,529 @@
<!--
filename: index.vue
author: liubin
date: 2023-09-04 09:34:52
description: 设备状态时序图
-->
<template>
<div class="status-timegraph-container" style="background: #f2f4f9; flex: 1; display: flex; flex-direction: column">
<el-row class="" style="
margin-bottom: 12px;
background: #fff;
padding: 16px 16px 0;
border-radius: 8px;
">
<div class="blue-title">生产节拍时序图</div>
<SearchBar :formConfigs="searchBarFormConfig" ref="search-bar" :remove-blue="true"
@select-changed="handleSearchBarSelectChange" @headBtnClick="handleSearchBarBtnClick" />
</el-row>
<el-row class="" style="
height: 1px;
flex: 1;
margin-bottom: 12px;
background: #fff;
padding: 16px 16px 32px;
border-radius: 8px;
display: flex;
flex-direction: column;
">
<el-row :gutter="20">
<el-col :span="6">
<div class="blue-title">设备状态时序图</div>
</el-col>
<el-col :span="18" class="legend-row">
<div class="legend">
<div class="icon running"></div>
<div>运行中</div>
</div>
<div class="legend">
<div class="icon fault"></div>
<div>故障</div>
</div>
<div class="legend">
<div class="icon stop"></div>
<div>计划停机</div>
</div>
</el-col>
</el-row>
<div class="main-area" style="flex: 1; display: flex; flex-direction: column;">
<div class="graphs" v-show="graphList.length" id="status-chart" style="height: 1px; flex: 1;"></div>
<h2 v-if="!graphList || graphList.length == 0" class="no-data-bg"></h2>
</div>
</el-row>
<!-- 对话框(添加 / 修改) -->
<base-dialog dialogTitle="添加设备" :dialogVisible="open" width="500px" @close="open = false" @cancel="open = false"
@confirm="submitForm">
<el-select v-if="open" style="width: 100%" v-model="queryParams.equipmentId" placeholder="请选择一个设备">
<el-option v-for="eq in eqList" :key="eq.id" :value="eq.id" :label="eq.name"></el-option>
</el-select>
</base-dialog>
</div>
</template>
<script>
import Gantt from './gantt';
export default {
name: 'SGStatus',
components: {},
props: {},
data() {
return {
chart: null,
searchBarFormConfig: [
{
type: 'select',
label: '产线',
placeholder: '请选择产线',
selectOptions: [],
param: 'lineId',
onchange: true,
},
{
type: 'select',
label: '工段',
placeholder: '请选择工段',
selectOptions: [],
param: 'sectionId',
},
//
{
type: 'datePicker',
label: '时间段',
dateType: 'date',
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
placeholder: '选择日期',
param: 'recordTime',
required: true,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: 'button',
btnName: '添加对比',
name: 'compare',
color: 'primary',
plain: true,
},
],
queryParams: {
lineId: null,
sectionId: null,
equipmentId: null,
recordTime: null,
},
graphList: [],
existingEquipments: [],
open: false,
eqList: [],
startTime: null,
gantt: null
// demo: [
// [
// {
// equipmentName: '',
// duration: 30,
// relativeDuration: 0.6,
// status: 0,
// startPos: 0,
// startTime: 1691568181000,
// },
// {
// equipmentName: '',
// duration: 20,
// relativeDuration: 0.4,
// status: 2,
// startPos: 30,
// startTime: 1691569981000
// },
// ],
// ],
};
},
computed: {},
created() {
this.initProductline();
this.initWorksection();
this.initEquipment();
// this.getList();
},
mounted() { },
watch: {
graphList: {
handler(val) {
if (val && val.length) {
this.$nextTick(() => {
if (!this.gantt) {
this.gantt = new Gantt('#status-chart', this.startTime);
this.gantt.init(val);
return;
}
this.gantt.update(val);
});
}
return;
},
deep: true,
immediate: true,
},
},
methods: {
findMin() {
let min = 0;
this.graphList.forEach((arr) => {
arr.forEach((item) => {
if (min < item.startTime) min = item.startTime;
});
});
return min;
},
/** 重置查询条件 */
initQuery() {
this.queryParams.lineId = null;
this.queryParams.equipmentId = null;
this.queryParams.sectionId = null;
this.queryParams.recordTime = null;
},
/** 对象到数组的转换 */
objectToArray(obj) {
return Object.keys(obj).map((key) => {
obj[key].sort((a, b) => a.startTime - b.startTime);
obj[key].key = key;
return obj[key];
});
},
async getList() {
const { code, data } = await this.$axios({
url: '/analysis/equipment-analysis/status',
method: 'get',
params: this.queryParams,
});
if (code == 0) {
this.existingEquipments = Object.values(data).map((eq) => eq[0].equipmentId);
this.graphList = this.objectToArray(data);
}
},
/** 准备设备数据 */
async initEquipment() {
const { code, data } = await this.$axios({
url: '/base/equipment/listAll',
method: 'get',
});
if (code == 0) {
this.eqList = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
/** 准备产线数据 */
async initProductline() {
const { code, data } = await this.$axios({
url: '/base/production-line/listAll',
method: 'get',
});
if (code == 0) {
this.searchBarFormConfig[0].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
/** 准备工段数据 */
async initWorksection() {
const { code, data } = await this.$axios({
url: '/base/workshop-section/listAll',
method: 'get',
});
if (code == 0) {
this.searchBarFormConfig[1].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
handleSearchBarSelectChange({ param, value }) {
if (!value) {
this.searchBarFormConfig[1].selectOptions = [];
return;
}
switch (param) {
case 'lineId':
this.$axios({
url: '/base/workshop-section/listByParentId',
method: 'get',
params: {
id: value,
},
}).then(({ code, data }) => {
if (code == 0) {
this.searchBarFormConfig[1].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
});
}
},
handleSearchBarBtnClick({ btnName, ...payload }) {
switch (btnName) {
case 'search':
if (!payload.recordTime || payload.recordTime.length <= 0) {
this.$message.warning('请选择时间段');
return;
}
this.startTime = new Date(payload.recordTime)
this.queryParams.lineId = payload.lineId || null;
this.queryParams.sectionId = payload.sectionId || null;
this.queryParams.equipmentId = payload.equipmentId || null;
this.queryParams.recordTime = payload.recordTime
? [
payload.recordTime,
new Date(
new Date(payload.recordTime).getTime() + 24 * 3600 * 1000
)
.toLocaleDateString()
.split('/')
.map((value, index) => {
if (index == 1 || index == 2) {
return value.padStart(2, '0');
}
return value;
})
.join('-') + ' 00:00:00',
]
: null;
this.getList();
break;
case 'compare':
this.open = true;
break;
}
},
async submitForm() {
if (this.existingEquipments.indexOf(this.queryParams.equipmentId) >= 0) {
this.$message.warning('该设备已存在');
return;
}
const {sectionId,...params} = this.queryParams
const { code, data } = await this.$axios({
url: '/analysis/equipment-analysis/status',
method: 'get',
params: params,
});
if (code == 0) {
const newEqlist = this.objectToArray(data);
if (!newEqlist || newEqlist.length == 0) {
this.$message.warning('该设备没有状态数据');
return;
}
this.graphList.push(newEqlist[0]);
}
this.open = false;
},
},
};
</script>
<style scoped lang="scss">
.graph {
// border: 1px solid #ccc;
// padding: 12px 12px 28px 12px;
// margin: 64px 0;
position: relative;
display: flex;
}
.graph-title {
// position: absolute;
// top: -64px;
// left: -1px;
// padding: 8px 18px;
padding: 0 12px;
font-size: 14px;
line-height: 1;
}
.graph-content {
display: flex;
flex: 1;
padding: 22px 12px;
border: 1px solid #ccc;
border-bottom-width: 2px;
border-top: none;
position: relative;
}
.graph-content::after,
.graph-content::before {
content: '';
position: absolute;
width: 3px;
height: 80%;
background: #fff;
right: -1px;
top: 0;
}
.graph-content::before {
right: unset;
left: -1px;
}
.graph-item,
.graph-item-fixed {
// height: 88px;
// width: 24px;
flex: 1;
// border: 1px solid #ccc;
position: relative;
}
.graph-item-fixed {
flex: unset;
}
.graph-item::before,
.graph-item-fixed::before {
position: absolute;
bottom: -16px;
left: 0;
content: attr(data-time);
// font-size - js
// rotate - js
// color - js, default:
color: #777;
transform-origin: left top;
transform: rotate(12deg);
}
.graph-item-fixed::after,
.graph-item::after {
content: '';
position: absolute;
left: 0;
bottom: -3px;
display: inline-block;
}
.graph-item.tick::after,
.graph-item-fixed.tick::after {
width: 1px;
height: 6px;
border-left: 1px solid #777;
}
.running {
background-color: #288AFF;
// background-color: #84f04e;
}
.waiting {
background-color: #5ad8a6;
// background-color: #409eff;
}
.fault {
// background-color: #ea5b5b;
background-color: #FC9C91;
}
.full {
// background-color: #e6a23c;
background-color: #598fff;
}
.lack {
// background-color: #a69c8d;
background-color: #7585a2;
}
.stop {
background-color: #FFDC94;
}
.legend-row {
margin: 6px 0;
padding-right: 12px;
display: flex;
justify-content: flex-end;
>.legend:not(:last-child) {
margin-right: 12px;
}
.legend {
display: flex;
align-items: center;
}
.icon {
width: 8px;
height: 8px;
border-radius: 2px;
margin-right: 4px;
margin-top: 1px;
}
}
.blue-title {
position: relative;
padding: 4px 0;
padding-left: 12px;
font-size: 14px;
color: #606266;
font-weight: 700;
margin-bottom: 12px;
&::before {
content: '';
position: absolute;
left: 0;
top: 6px;
height: 16px;
width: 4px;
border-radius: 1px;
background: #0b58ff;
}
}
.echarts__status-chart {
background: #ccc;
}
.echarts__status-chart>div {
height: 100% !important;
width: 100% !important;
}
</style>

View File

@ -6,19 +6,28 @@
-->
<template>
<div class="status-timegraph-container" style="background: #f2f4f9; flex: 1; display: flex; flex-direction: column">
<el-row class="" style="
<div
class="status-timegraph-container"
style="background: #f2f4f9; flex: 1; display: flex; flex-direction: column">
<el-row
class=""
style="
margin-bottom: 12px;
background: #fff;
padding: 16px 16px 0;
border-radius: 8px;
">
<div class="blue-title">生产节拍时序图</div>
<SearchBar :formConfigs="searchBarFormConfig" ref="search-bar" :remove-blue="true"
@select-changed="handleSearchBarSelectChange" @headBtnClick="handleSearchBarBtnClick" />
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
:remove-blue="true"
@headBtnClick="handleSearchBarBtnClick" />
</el-row>
<el-row class="" style="
<el-row
class=""
style="
height: 1px;
flex: 1;
margin-bottom: 12px;
@ -47,17 +56,36 @@
</div>
</el-col>
</el-row>
<div class="main-area" style="flex: 1; display: flex; flex-direction: column;">
<div class="graphs" v-show="graphList.length" id="status-chart" style="height: 1px; flex: 1;"></div>
<div
class="main-area"
style="flex: 1; display: flex; flex-direction: column">
<div
class="graphs"
v-show="graphList.length"
id="status-chart"
style="height: 1px; flex: 1"></div>
<h2 v-if="!graphList || graphList.length == 0" class="no-data-bg"></h2>
</div>
</el-row>
<!-- 对话框(添加 / 修改) -->
<base-dialog dialogTitle="添加设备" :dialogVisible="open" width="500px" @close="open = false" @cancel="open = false"
<base-dialog
dialogTitle="添加设备"
:dialogVisible="open"
width="500px"
@close="open = false"
@cancel="open = false"
@confirm="submitForm">
<el-select v-if="open" style="width: 100%" v-model="queryParams.equipmentId" placeholder="请选择一个设备">
<el-option v-for="eq in eqList" :key="eq.id" :value="eq.id" :label="eq.name"></el-option>
<el-select
v-if="open"
style="width: 100%"
v-model="queryParams.equipmentId"
placeholder="请选择一个设备">
<el-option
v-for="eq in eqList"
:key="eq.id"
:value="eq.id"
:label="eq.name"></el-option>
</el-select>
</base-dialog>
</div>
@ -74,21 +102,6 @@ export default {
return {
chart: null,
searchBarFormConfig: [
{
type: 'select',
label: '产线',
placeholder: '请选择产线',
selectOptions: [],
param: 'lineId',
onchange: true,
},
{
type: 'select',
label: '工段',
placeholder: '请选择工段',
selectOptions: [],
param: 'sectionId',
},
//
{
type: 'datePicker',
@ -119,8 +132,6 @@ export default {
},
],
queryParams: {
lineId: null,
sectionId: null,
equipmentId: null,
recordTime: null,
},
@ -129,37 +140,41 @@ export default {
open: false,
eqList: [],
startTime: null,
gantt: null
// demo: [
// [
// {
// equipmentName: '',
// duration: 30,
// relativeDuration: 0.6,
// status: 0,
// startPos: 0,
// startTime: 1691568181000,
// },
// {
// equipmentName: '',
// duration: 20,
// relativeDuration: 0.4,
// status: 2,
// startPos: 30,
// startTime: 1691569981000
// },
// ],
// ],
gantt: null,
};
},
computed: {},
created() {
this.initProductline();
this.initWorksection();
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const formattedDate = `${year}-${month}-${day} 00:00:00`;
this.$nextTick(() => {
this.$refs['search-bar'].formInline.recordTime = formattedDate;
});
this.queryParams.equipmentId = Number(this.$route.query.eqid);
this.startTime = new Date(formattedDate);
this.queryParams.recordTime = formattedDate
? [
formattedDate,
new Date(new Date(formattedDate).getTime() + 24 * 3600 * 1000)
.toLocaleDateString()
.split('/')
.map((value, index) => {
if (index == 1 || index == 2) {
return value.padStart(2, '0');
}
return value;
})
.join('-') + ' 00:00:00',
]
: null;
this.getList();
this.initEquipment();
// this.getList();
},
mounted() { },
mounted() {
},
watch: {
graphList: {
handler(val) {
@ -171,7 +186,6 @@ export default {
return;
}
this.gantt.update(val);
});
}
return;
@ -193,9 +207,7 @@ export default {
/** 重置查询条件 */
initQuery() {
this.queryParams.lineId = null;
this.queryParams.equipmentId = null;
this.queryParams.sectionId = null;
this.queryParams.recordTime = null;
},
@ -215,7 +227,9 @@ export default {
params: this.queryParams,
});
if (code == 0) {
this.existingEquipments = Object.values(data).map((eq) => eq[0].equipmentId);
this.existingEquipments = Object.values(data).map(
(eq) => eq[0].equipmentId
);
this.graphList = this.objectToArray(data);
}
},
@ -236,65 +250,8 @@ export default {
}
},
/** 准备产线数据 */
async initProductline() {
const { code, data } = await this.$axios({
url: '/base/production-line/listAll',
method: 'get',
});
if (code == 0) {
this.searchBarFormConfig[0].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
/** 准备工段数据 */
async initWorksection() {
const { code, data } = await this.$axios({
url: '/base/workshop-section/listAll',
method: 'get',
});
if (code == 0) {
this.searchBarFormConfig[1].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
handleSearchBarSelectChange({ param, value }) {
if (!value) {
this.searchBarFormConfig[1].selectOptions = [];
return;
}
switch (param) {
case 'lineId':
this.$axios({
url: '/base/workshop-section/listByParentId',
method: 'get',
params: {
id: value,
},
}).then(({ code, data }) => {
if (code == 0) {
this.searchBarFormConfig[1].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
});
}
},
handleSearchBarBtnClick({ btnName, ...payload }) {
this.queryParams.equipmentId = Number(this.$route.query.eqid);
switch (btnName) {
case 'search':
if (!payload.recordTime || payload.recordTime.length <= 0) {
@ -302,26 +259,23 @@ export default {
return;
}
this.startTime = new Date(payload.recordTime)
this.queryParams.lineId = payload.lineId || null;
this.queryParams.sectionId = payload.sectionId || null;
this.queryParams.equipmentId = payload.equipmentId || null;
this.startTime = new Date(payload.recordTime);
this.queryParams.recordTime = payload.recordTime
? [
payload.recordTime,
new Date(
new Date(payload.recordTime).getTime() + 24 * 3600 * 1000
)
.toLocaleDateString()
.split('/')
.map((value, index) => {
if (index == 1 || index == 2) {
return value.padStart(2, '0');
}
return value;
})
.join('-') + ' 00:00:00',
]
payload.recordTime,
new Date(
new Date(payload.recordTime).getTime() + 24 * 3600 * 1000
)
.toLocaleDateString()
.split('/')
.map((value, index) => {
if (index == 1 || index == 2) {
return value.padStart(2, '0');
}
return value;
})
.join('-') + ' 00:00:00',
]
: null;
this.getList();
break;
@ -336,10 +290,11 @@ export default {
this.$message.warning('该设备已存在');
return;
}
const { ...params } = this.queryParams;
const { code, data } = await this.$axios({
url: '/analysis/equipment-analysis/status',
method: 'get',
params: this.queryParams,
params: params,
});
if (code == 0) {
const newEqlist = this.objectToArray(data);
@ -444,7 +399,7 @@ export default {
}
.running {
background-color: #288AFF;
background-color: #288aff;
// background-color: #84f04e;
}
@ -455,7 +410,7 @@ export default {
.fault {
// background-color: #ea5b5b;
background-color: #FC9C91;
background-color: #fc9c91;
}
.full {
@ -469,7 +424,7 @@ export default {
}
.stop {
background-color: #FFDC94;
background-color: #ffdc94;
}
.legend-row {
@ -478,7 +433,7 @@ export default {
display: flex;
justify-content: flex-end;
>.legend:not(:last-child) {
> .legend:not(:last-child) {
margin-right: 12px;
}
@ -521,7 +476,7 @@ export default {
background: #ccc;
}
.echarts__status-chart>div {
.echarts__status-chart > div {
height: 100% !important;
width: 100% !important;
}

View File

@ -56,6 +56,7 @@ import Editor from '@/components/Editor';
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import { getAccessToken } from '@/utils/auth';
import { getFactoryPage } from '@/api/core/base/factory';
import { publicFormatter } from '@/utils/dict';
export default {
@ -67,6 +68,7 @@ export default {
data() {
return {
searchBarKeys: ['checkTime'],
optionArrUrl: [getFactoryPage],
tableBtn: [
this.$auth.hasPermi('base:equipment-alarm-log:update')
? {
@ -82,6 +84,10 @@ export default {
: undefined,
].filter((v) => v),
tableProps: [
{
prop: 'factoryName',
label: '工厂',
},
{ prop: 'productionLine', label: '产线' },
{ prop: 'workshopSection', label: '工段' },
{ prop: 'equipment', label: '设备名称' },
@ -128,6 +134,13 @@ export default {
// },
],
searchBarFormConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'datePicker',
label: '时间段',
@ -155,6 +168,7 @@ export default {
queryParams: {
pageNo: 1,
pageSize: 10,
factoryId: undefined,
createTime: [],
},
//
@ -164,12 +178,25 @@ export default {
};
},
created() {
this.getArr();
this.getList();
},
methods: {
getArr() {
const params = {
page: 1,
limit: 500,
};
this.optionArrUrl.forEach((item, index) => {
item(params).then((response) => {
this.searchBarFormConfig[index].selectOptions = response.data.list;
});
});
},
/** 重写 basicPageMixin 里的 handleSearchBarBtnClick */
handleSearchBarBtnClick(btn) {
//
this.queryParams.factoryId = btn.factoryId;
this.queryParams.createTime = btn.createTime;
this.handleQuery();
},

View File

@ -48,6 +48,9 @@
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import { publicFormatter } from '@/utils/dict';
import { getPdList } from '@/api/core/monitoring/auto';
import { getProductionLinePage } from '@/api/core/base/productionLine';
import { getFactoryPage } from '@/api/core/base/factory';
export default {
name: 'EquipmentStatusAndParams',
@ -56,6 +59,7 @@ export default {
data() {
return {
searchBarKeys: ['equipmentId', 'productionLineId'],
optionArrUrl: [getFactoryPage, getProductionLinePage],
tableBtn: [
this.$auth.hasPermi('base:equipment-alarm-log:update')
? {
@ -71,6 +75,10 @@ export default {
: undefined,
].filter((v) => v),
tableProps: [
{
prop: 'factoryName',
label: '工厂',
},
{
prop: 'lineName',
label: '产线名',
@ -78,7 +86,7 @@ export default {
{
prop: 'workshopName',
label: '工段名',
showOverflowtooltip :true,
showOverflowtooltip: true,
},
{
width: 200,
@ -87,7 +95,7 @@ export default {
},
{
width: 150,
showOverflowtooltip :true,
showOverflowtooltip: true,
prop: 'equipmentCode',
label: '设备编码',
},
@ -106,24 +114,24 @@ export default {
filter: (val) =>
val != null ? ['正常', '计划停机', '故障'][val] : '-',
},
{
width: 128,
prop: 'error',
label: '是否故障',
filter: (val) => (val != null ? (val ? '是' : '否') : '-'),
},
{
prop: 'quantityRecordTime',
label: '生产量记录时间',
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{
prop: 'statusRecordTime',
label: '状态记录时间',
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
// {
// width: 128,
// prop: 'error',
// label: '',
// filter: (val) => (val != null ? (val ? '' : '') : '-'),
// },
// {
// prop: 'quantityRecordTime',
// label: '',
// width: 180,
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
// },
// {
// prop: 'statusRecordTime',
// label: '',
// width: 180,
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
// },
{
_action: 'params-monitor',
label: '操作',
@ -154,20 +162,13 @@ export default {
},
],
searchBarFormConfig: [
// {
// type: 'datePicker',
// label: '',
// dateType: 'daterange', // datetimerange
// // format: 'yyyy-MM-dd HH:mm:ss',
// format: 'yyyy-MM-dd',
// valueFormat: 'yyyy-MM-dd HH:mm:ss',
// rangeSeparator: '-',
// startPlaceholder: '',
// endPlaceholder: '',
// defaultTime: ['00:00:00', '23:59:59'],
// param: 'createTime',
// // width: 350,
// },
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'select',
label: '产线',
@ -196,6 +197,7 @@ export default {
queryParams: {
pageNo: 1,
pageSize: 10,
factoryId: null,
productionLineId: null,
equipmentId: null,
},
@ -207,22 +209,21 @@ export default {
};
},
created() {
this.getLineList();
this.getArr();
this.getList();
},
methods: {
/** 获取产线 */
async getLineList() {
const { data } = await this.$axios({
url: '/base/production-line/listAll',
method: 'get',
getArr() {
const params = {
page: 1,
limit: 500,
};
this.optionArrUrl.forEach((item, index) => {
item(params).then((response) => {
this.searchBarFormConfig[index].selectOptions = response.data.list;
});
});
this.searchBarFormConfig[0].selectOptions = data.map((line) => ({
name: line.name,
id: line.id,
}));
},
/** 根据产线获取设备 */
async getEquipmentList(id) {
const { data } = await this.$axios({
@ -238,14 +239,24 @@ export default {
if (param == 'productionLineId') {
if (id == '') {
//
this.searchBarFormConfig[1].selectOptions = [];
this.searchBarFormConfig[2].selectOptions = [];
return;
}
const list = await this.getEquipmentList(id);
this.searchBarFormConfig[1].selectOptions = list.map((eq) => ({
this.searchBarFormConfig[2].selectOptions = list.map((eq) => ({
name: eq.name,
id: eq.id,
}));
} else if (param == 'factoryId') {
//
this.searchBarFormConfig[2].selectOptions = [];
this.queryParams.equipmentId = undefined;
this.queryParams.productionLineId = undefined;
this.$refs['search-bar'].formInline.equipmentId = undefined;
this.$refs['search-bar'].formInline.productionLineId = undefined;
getPdList(id).then((res) => {
this.searchBarFormConfig[1].selectOptions = res.data || [];
});
}
},
@ -256,6 +267,7 @@ export default {
if (productionLineId)
this.queryParams.productionLineId = productionLineId;
else this.queryParams.productionLineId = null;
this.queryParams.factoryId = btn.factoryId || null;
this.getList();
},

View File

@ -0,0 +1,299 @@
<!--
* @Author: zwq
* @Date: 2025-02-10 09:15:55
* @LastEditors: zwq
* @LastEditTime: 2025-02-19 09:41:10
* @Description:
-->
<template>
<div class="app-container" style="overflow: auto">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@select-changed="handleSearchBarChanged"
@headBtnClick="buttonClick" />
<div class="top-tip">
<div class="block" style="background: #5b8ff9" />
运行
<div class="block" style="background: #f4b183" />
停机
<div class="block" style="background: #ff4f3e" />
故障
</div>
<div class="canvas-line" v-for="(item, index) in lineArr" :key="index">
<div class="title">{{ item.name }}</div>
<canvas
style="
box-shadow: 1px 1px 2px 2px #909399;
padding: 0;
height: 210px;
width: 100%;
"
@click="getclient($event, index + 1, item.num)"
:id="'mycanvas' + (index + 1)"></canvas>
</div>
</div>
</template>
<script>
import { getPdList } from '@/api/core/monitoring/auto';
import { getFactoryPage, getLineEqStatus } from '@/api/core/base/factory';
import linePot from './line-pot';
export default {
data() {
return {
listQuery: {
factoryId: null,
lineId: null,
},
ctx: '', //canvas
lineArr: [],
formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'select',
label: '产线',
selectOptions: [],
param: 'lineId',
multiple: true,
},
{
type: 'button',
btnName: '搜索',
name: 'search',
color: 'primary',
},
],
linePot,
};
},
components: {},
created() {
this.getPdLineList();
},
methods: {
initCanvas(name) {
let canvas = document.getElementById(name);
canvas.width = canvas.clientWidth;
canvas.width = canvas.clientWidth;
canvas.height = 210;
this.ctx = canvas.getContext('2d');
this.ctx.lineWidth = 1;
this.ctx.strokeStyle = '#909399';
this.ctx.fillStyle = '#5b8ff9';
this.ctx.font = '12px 宋体'; //
this.ctx.clearRect(0, 0, canvas.clientWidth, 210); //
},
//
fillRect(x, y, width, height, name, color) {
this.ctx.beginPath(); //
this.ctx.fillStyle = color ? color : '#5b8ff9'; //
this.ctx.fillRect(x, y, width, height); //(x,y)
this.ctx.strokeRect(x, y, width, height);
this.ctx.fillStyle = '#fff'; //
if (height === 50) {
// y10
this.ctx.fillText(name, x + 5, y + 30);
} else {
this.ctx.fillText(name, x + 5, y + 20);
}
this.ctx.closePath(); //
},
//
fillLRect(LArr, name, color) {
this.ctx.beginPath(); //
LArr.forEach((item, index) => {
if (index === 0) {
this.ctx.moveTo(item[0], item[1]);
} else {
this.ctx.lineTo(item[0], item[1]);
}
});
this.ctx.closePath(); // //
this.ctx.fillStyle = color ? color : '#5b8ff9'; //
this.ctx.fill();
this.ctx.stroke();
this.ctx.fillStyle = '#fff'; //
if (LArr[0][0] === LArr[1][0]) {
//L
this.ctx.fillText(name, LArr[1][0] + 5, LArr[1][1] + 20); //
} else {
this.ctx.fillText(name, LArr[0][0] + 5, LArr[0][1] + 20);
}
},
setRect(item, index) {
const identifier = 'line' + item.num + 'canvas';
this.$nextTick(() => {
this.initCanvas('mycanvas' + (index + 1));
});
this.$nextTick(() => {
this.linePot[identifier].forEach((idItem) => {
item.children.forEach((eqItem) => {
if (eqItem.id === idItem.id) {
idItem.color = ['#5b8ff9', '#f4b183', '#ff4f3e'][
eqItem.equipmentStatus
];
}
});
if (idItem.isL) {
this.fillLRect(idItem.line, idItem.name, idItem.color);
} else {
this.fillRect(
idItem.x,
idItem.y,
idItem.width,
idItem.height,
idItem.name,
idItem.color
);
}
});
});
},
getclient(e, index, num) {
let canvas = document.getElementById('mycanvas' + index);
const rect = canvas.getBoundingClientRect();
const identifier = 'line' + num + 'canvas';
this.isEQ(e.clientX - rect.left, e.clientY - rect.top, identifier);
},
//
isEQ(x, y, identifier) {
this.linePot[identifier].forEach((idItem) => {
if (idItem.isEQ) {
//
if (
x >= idItem.x &&
x <= idItem.x + idItem.width &&
y >= idItem.y &&
y <= idItem.y + idItem.height
) {
console.log(idItem.name, idItem.id);
this.$router.push({
path: '/equipment/analysis/timing-diagram/equipment-status',
query: { eqid: idItem.id },
});
}
}
});
},
getPdLineList() {
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
getPdList().then((res) => {
this.formConfig[1].selectOptions = res.data || [];
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 100;
this.listQuery.factoryId = val.factoryId || undefined;
this.listQuery.lineId = val.lineId ? val.lineId : [];
this.getDataList();
break;
default:
console.log(val);
}
},
handleSearchBarChanged({ param, value }) {
this.listQuery.lineId = [];
this.$refs.searchBarForm.formInline.lineId = undefined;
getPdList(value).then((res) => {
this.formConfig[1].selectOptions = res.data || [];
});
},
getDataList() {
// this.lineArr = [
// {
// num: 1,
// name: 'A1',
// children: [],
// },
// {
// num: 2,
// name: 'A2',
// children: [],
// },
// {
// num: 3,
// name: 'A3',
// children: [],
// },
// {
// num: 4,
// name: 'A4',
// children: [],
// },
// {
// num: 5,
// name: 'A5',
// children: [],
// },
// ];
getLineEqStatus(this.listQuery).then((response) => {
this.lineArr = response.data;
this.lineArr.forEach((item, index) => {
const num = [
'',
'1672847052717821953',
'1672847052717821954',
'1686260211054157825',
'1701892552632770122',
'1714562503683465331',
].indexOf(item.id);
if (num > 0) {
item.num = num;
item.name = item.lineName;
this.setRect(item, index);
} else {
this.$message.warning('没有对应的产线!');
}
});
});
},
},
};
</script>
<style scoped lang="scss">
.top-tip {
.block {
display: inline-block;
width: 20px;
height: 10px;
margin-left: 20px;
margin-right: 3px;
}
}
.canvas-line {
margin-top: 20px;
min-width: 1600px;
.title {
font-size: 20px;
font-weight: bolder;
&::before {
content: '';
background: rgb(39, 240, 17);
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 3px;
transform: translateY(-50%);
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -2,13 +2,13 @@
setlocal enabledelayedexpansion
set cmdstr=rsync
set zipfile=cwrsync.zip
set downurl=https://itefix.net/dl/free-software/cwrsync_6.3.0_x64_free.zip
set downurl=https://itefix.net/download/free/cwrsync_6.3.0_x64_free.zip
set currpath=%~dp0
set "rsynchome=%ProgramFiles%\%zipfile:~0,-4%"
set passfile=%temp%\.password
set syncdir=dist/
:: 以下需要配置同步服务器
set accountwithost=kszny@47.96.93.140::line
set accountwithost=kszny@192.168.8.22::line
set "password=kszny@123"
set "runcommand=%cmdstr% --port=873 -rlptvz --progress --password-file=%passfile% --exclude=google.exe --exclude=Lodap.zip %syncdir% %accountwithost%"

68
sync_line_yy_prod.bat Normal file
View File

@ -0,0 +1,68 @@
@echo off
setlocal enabledelayedexpansion
set cmdstr=rsync
set zipfile=cwrsync.zip
set downurl=https://itefix.net/download/free/cwrsync_6.3.0_x64_free.zip
set currpath=%~dp0
set "rsynchome=%ProgramFiles%\%zipfile:~0,-4%"
set passfile=%temp%\.password
set syncdir=dist/
:: 以下需要配置同步服务器
set accountwithost=kszny@192.168.4.142::line
set "password=kszny@123"
set "runcommand=%cmdstr% --port=873 -rlptvz --progress --password-file=%passfile% --exclude=google.exe --exclude=Lodap.zip %syncdir% %accountwithost%"
where %cmdstr% >nul 2>nul
::有错误输出,说明不存在该命令
if %errorlevel% neq 0 (
::还未下载安装包或未正常解压到安装目录
if not exist "%rsynchome%" (
:: 请求提升管理员权限
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\runAsAdmin.vbs"
echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%temp%\runAsAdmin.vbs"
"%temp%\runAsAdmin.vbs"
:: 需要提升管理员权限才能创建此目录
mkdir "%rsynchome%"
del "%temp%\runAsAdmin.vbs"
exit /B
)
:: 使用powershell的curl下载软件包
powershell curl -o %temp%\%zipfile% %downurl%
:: 解压
tar -xf "%temp%\%zipfile%" -C "%rsynchome%"
echo "%cmdstr%已经安装到了%rsynchome%目录下"
:: 检查路径是否存在于 PATH 中
set "found=false"
for %%I in ("%PATH:;=";"%") do (
if /I "%%~I"=="%rsynchome%\bin" (
set "found=true"
)
)
:: 未设置到path变量中添加到path变量
if "!found!"=="false" (
:: 更新注册表中的 PATH 变量通过setx方式变量值长度超过1024个字符就会被截断
reg add "HKCU\Environment" /v PATH /t REG_EXPAND_SZ /d "%PATH%;%rsynchome%\bin" /f
)
)
::当前目录下没有dist目录
if not exist "%currpath%%syncdir%" (
echo 当前目录下没有需要同步的%syncdir%目录,请把需要同步的%syncdir%目录拷贝到当前目录下!
) else (
echo !password!>%passfile%
echo 数据同步开始,请稍后...
!runcommand! && (
echo 数据同步完成!
) || (
echo !runcommand!
echo 数据同步失败请确认是否开启了VPN
)
del %passfile%
)
endlocal
pause