大屏
This commit is contained in:
63
src/api/mes/board/screen.js
Normal file
63
src/api/mes/board/screen.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function listBoardScreen(query) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/board/screen/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBoardScreen(screenId) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/board/screen/' + screenId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addBoardScreen(data) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/board/screen',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateBoardScreen(data) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/board/screen',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function delBoardScreen(screenId) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/board/screen/' + screenId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBoardScreenConfig(screenId) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/board/screen/config',
|
||||||
|
method: 'get',
|
||||||
|
params: { screenId }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveBoardScreenConfig(data) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/board/screen/config',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetBoardScreenConfig(screenId) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/board/screen/config',
|
||||||
|
method: 'delete',
|
||||||
|
params: { screenId }
|
||||||
|
})
|
||||||
|
}
|
||||||
9
src/api/mes/board/workshop.js
Normal file
9
src/api/mes/board/workshop.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getWorkshopBoardData(screenCode) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/board/workshop/data',
|
||||||
|
method: 'get',
|
||||||
|
params: { screenCode }
|
||||||
|
})
|
||||||
|
}
|
||||||
130
src/api/mes/md/screenbinding.js
Normal file
130
src/api/mes/md/screenbinding.js
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
const DEFAULT_SCREEN_CODE = 'WORKSHOP_BOARD_DEFAULT'
|
||||||
|
|
||||||
|
function createEmptyScreenBindingConfig(screenCode = DEFAULT_SCREEN_CODE) {
|
||||||
|
return {
|
||||||
|
screenCode,
|
||||||
|
workshopId: null,
|
||||||
|
workshopCode: '',
|
||||||
|
workshopName: '',
|
||||||
|
updatedAt: '',
|
||||||
|
basicBindings: [],
|
||||||
|
machineConfigs: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toUiBinding(binding) {
|
||||||
|
return {
|
||||||
|
bindingId: binding.bindingId,
|
||||||
|
screenCode: binding.screenCode,
|
||||||
|
workshopId: binding.workshopId,
|
||||||
|
workshopCode: binding.workshopCode,
|
||||||
|
workshopName: binding.workshopName,
|
||||||
|
sourceType: binding.sourceType || 'FIXED',
|
||||||
|
pointId: binding.pointId,
|
||||||
|
pointCode: binding.pointCode || '',
|
||||||
|
pointName: binding.pointName || '',
|
||||||
|
fixedValue: binding.fixedValue || '',
|
||||||
|
defaultValue: binding.defaultValue || '',
|
||||||
|
displayUnit: binding.displayUnit || '',
|
||||||
|
precisionDigit: binding.precisionDigit,
|
||||||
|
sortNum: binding.sortNum,
|
||||||
|
statusClass: binding.statusClass || 'is-running',
|
||||||
|
enableFlag: binding.enableFlag || 'Y',
|
||||||
|
key: binding.bindingKey,
|
||||||
|
label: binding.bindingName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toUiConfig(data) {
|
||||||
|
const emptyConfig = createEmptyScreenBindingConfig(data.screenCode || DEFAULT_SCREEN_CODE)
|
||||||
|
return {
|
||||||
|
...emptyConfig,
|
||||||
|
screenCode: data.screenCode || emptyConfig.screenCode,
|
||||||
|
workshopId: data.workshopId === undefined ? emptyConfig.workshopId : data.workshopId,
|
||||||
|
workshopCode: data.workshopCode || emptyConfig.workshopCode,
|
||||||
|
workshopName: data.workshopName || emptyConfig.workshopName,
|
||||||
|
updatedAt: data.updatedAt || emptyConfig.updatedAt,
|
||||||
|
basicBindings: (data.basicBindings || []).map(toUiBinding),
|
||||||
|
machineConfigs: (data.machineConfigs || []).map(item => ({
|
||||||
|
id: item.id,
|
||||||
|
statusClass: item.statusClass || 'is-running',
|
||||||
|
bindings: (item.bindings || []).map(toUiBinding)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toApiBinding(binding, scope, machineId, statusClass) {
|
||||||
|
return {
|
||||||
|
bindingId: binding.bindingId,
|
||||||
|
screenCode: binding.screenCode,
|
||||||
|
workshopId: binding.workshopId,
|
||||||
|
workshopCode: binding.workshopCode,
|
||||||
|
workshopName: binding.workshopName,
|
||||||
|
bindingScope: scope,
|
||||||
|
machineId,
|
||||||
|
bindingKey: binding.key,
|
||||||
|
bindingName: binding.label,
|
||||||
|
sourceType: binding.sourceType,
|
||||||
|
pointId: binding.pointId,
|
||||||
|
pointCode: binding.pointCode,
|
||||||
|
pointName: binding.pointName,
|
||||||
|
fixedValue: binding.fixedValue,
|
||||||
|
defaultValue: binding.defaultValue,
|
||||||
|
displayUnit: binding.displayUnit,
|
||||||
|
precisionDigit: binding.precisionDigit,
|
||||||
|
statusClass: statusClass || binding.statusClass,
|
||||||
|
sortNum: binding.sortNum,
|
||||||
|
enableFlag: binding.enableFlag,
|
||||||
|
remark: binding.remark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toApiConfig(config) {
|
||||||
|
return {
|
||||||
|
screenCode: config.screenCode,
|
||||||
|
workshopId: config.workshopId,
|
||||||
|
workshopCode: config.workshopCode,
|
||||||
|
workshopName: config.workshopName,
|
||||||
|
basicBindings: (config.basicBindings || []).map(item => toApiBinding(item, 'BASIC', 0, item.statusClass)),
|
||||||
|
machineConfigs: (config.machineConfigs || []).map(machine => ({
|
||||||
|
id: machine.id,
|
||||||
|
statusClass: machine.statusClass,
|
||||||
|
bindings: (machine.bindings || []).map(item => toApiBinding(item, 'MACHINE', machine.id, machine.statusClass))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getScreenBindingConfig(screenCode) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/md/screenbinding/config',
|
||||||
|
method: 'get',
|
||||||
|
params: { screenCode }
|
||||||
|
}).then(response => ({
|
||||||
|
...response,
|
||||||
|
data: toUiConfig(response.data || {})
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveScreenBindingConfig(data) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/md/screenbinding/config',
|
||||||
|
method: 'post',
|
||||||
|
data: toApiConfig(data)
|
||||||
|
}).then(response => ({
|
||||||
|
...response,
|
||||||
|
data: toUiConfig(response.data || {})
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetScreenBindingConfig(screenCode) {
|
||||||
|
return request({
|
||||||
|
url: '/mes/md/screenbinding/config',
|
||||||
|
method: 'delete',
|
||||||
|
params: { screenCode }
|
||||||
|
}).then(response => ({
|
||||||
|
...response,
|
||||||
|
data: toUiConfig(response.data || {})
|
||||||
|
}))
|
||||||
|
}
|
||||||
@ -3,11 +3,11 @@
|
|||||||
<div class="board-header">
|
<div class="board-header">
|
||||||
<div class="header-cell">
|
<div class="header-cell">
|
||||||
<div class="header-label">看板编号</div>
|
<div class="header-label">看板编号</div>
|
||||||
<div class="header-value">HY-CJKB-001</div>
|
<div class="header-value">{{ header.screenCode }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-cell">
|
<div class="header-cell">
|
||||||
<div class="header-label">管理责任人</div>
|
<div class="header-label">管理责任人</div>
|
||||||
<div class="header-value">张主管</div>
|
<div class="header-value">{{ header.ownerName }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-cell">
|
<div class="header-cell">
|
||||||
<div class="header-label">更新时间</div>
|
<div class="header-label">更新时间</div>
|
||||||
@ -290,99 +290,62 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function createMachine(id, name, model, statusText, statusClass, mode, runtime, output, workDate, batchNo, planQty, progress, productModel, color, remark, nextModel) {
|
import { getWorkshopBoardData } from '@/api/mes/board/workshop'
|
||||||
|
import { listRepair } from '@/api/mes/dv/repair'
|
||||||
|
import { listCheckplan } from '@/api/mes/dv/checkplan'
|
||||||
|
|
||||||
|
const DEFAULT_SCREEN_CODE = 'WORKSHOP_BOARD_DEFAULT'
|
||||||
|
|
||||||
|
function createEmptyWorkshopBoardData() {
|
||||||
return {
|
return {
|
||||||
id,
|
header: {},
|
||||||
name,
|
summary: {},
|
||||||
model,
|
faultList: [],
|
||||||
statusText,
|
maintenanceList: [],
|
||||||
statusClass,
|
machineList: [],
|
||||||
mode,
|
detailRealtime: [],
|
||||||
runtime,
|
detailSetting: [],
|
||||||
output,
|
detailProduction: []
|
||||||
workDate,
|
|
||||||
batchNo,
|
|
||||||
planQty,
|
|
||||||
progress,
|
|
||||||
productModel,
|
|
||||||
color,
|
|
||||||
remark,
|
|
||||||
nextModel
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'WorkshopBoard',
|
name: 'WorkshopBoard',
|
||||||
|
data() {
|
||||||
|
const boardData = createEmptyWorkshopBoardData()
|
||||||
|
return {
|
||||||
|
detailVisible: false,
|
||||||
|
boardTimer: null,
|
||||||
|
updateTime: '',
|
||||||
|
previousTitle: '',
|
||||||
|
activeMachine: {},
|
||||||
|
header: boardData.header,
|
||||||
|
faultTableRows: 8,
|
||||||
|
planTableRows: 8,
|
||||||
|
summary: boardData.summary,
|
||||||
|
faultList: boardData.faultList,
|
||||||
|
maintenanceList: boardData.maintenanceList,
|
||||||
|
machineList: boardData.machineList,
|
||||||
|
detailRealtime: boardData.detailRealtime,
|
||||||
|
detailSetting: boardData.detailSetting,
|
||||||
|
detailProduction: boardData.detailProduction
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
orderedMachineList() {
|
orderedMachineList() {
|
||||||
return [...this.machineList].sort((a, b) => a.id - b.id)
|
return [...this.machineList].sort((a, b) => a.id - b.id)
|
||||||
}
|
|
||||||
},
|
},
|
||||||
data() {
|
workshopMachineCodeSet() {
|
||||||
return {
|
return new Set(
|
||||||
detailVisible: false,
|
(this.machineList || [])
|
||||||
updateTime: '',
|
.map(item => this.normalizeMachineCode(item && item.name))
|
||||||
clockTimer: null,
|
.filter(Boolean)
|
||||||
previousTitle: '',
|
)
|
||||||
activeMachine: {},
|
|
||||||
faultTableRows: 8,
|
|
||||||
planTableRows: 8,
|
|
||||||
summary: {
|
|
||||||
total: 17,
|
|
||||||
online: 15,
|
|
||||||
running: 15,
|
|
||||||
stop: 2,
|
|
||||||
startRate: '88.2%'
|
|
||||||
},
|
|
||||||
faultList: [
|
|
||||||
{ deviceNo: '8#', faultTime: '09:25', faultDesc: '模温异常', owner: '李工', recoverTime: '10:10' },
|
|
||||||
{ deviceNo: '16#', faultTime: '11:40', faultDesc: '液压压力波动', owner: '王工', recoverTime: '13:00' },
|
|
||||||
{ deviceNo: '5#', faultTime: '13:18', faultDesc: '送料传感器告警', owner: '赵工', recoverTime: '13:45' }
|
|
||||||
],
|
|
||||||
maintenanceList: [
|
|
||||||
{ deviceNo: '2#', project: '保养润滑系统', planTime: '2026-03-23 16:00', status: '待执行' },
|
|
||||||
{ deviceNo: '11#', project: '校验温控模块', planTime: '2026-03-23 18:00', status: '待执行' },
|
|
||||||
{ deviceNo: '14#', project: '更换过滤组件', planTime: '2026-03-24 09:00', status: '已排期' }
|
|
||||||
],
|
|
||||||
machineList: [
|
|
||||||
createMachine(6, '6#', 'MA2500/1000G', '状态', 'is-running', '运行', '13小时', '600个', '2026.3.16-3.18', '25110914', '5000个', '30%', '23W 中间盖', '7037C 灰', '重点订单', '159BB'),
|
|
||||||
createMachine(12, '12#', 'MA1600/540G', '状态', 'is-running', '运行', '8小时', '305个', '2026.3.23-3.25', '25110953', '2800个', '27%', '中盖件', '灰色', '正常生产', 'J20R'),
|
|
||||||
createMachine(5, '5#', 'MA2500 2S/1000', '状态', 'is-running', '运行', '6小时', '210个', '2026.3.22-3.24', '25110937', '3600个', '19%', '卡扣件', '7035 灰', '待维修', '32QR'),
|
|
||||||
createMachine(11, '11#', 'MA3600/2250G', '状态', 'is-running', '运行', '15小时', '720个', '2026.3.23-3.25', '25110950', '6500个', '33%', '大型壳体', '深蓝', '计划保养', 'LT9X'),
|
|
||||||
createMachine(17, '17#', 'MA1600/540G', '状态', 'is-running', '运行', '12小时', '510个', '2026.3.23-3.25', '25110961', '3600个', '53%', '面框件', '冷白', '正常生产', 'AA17'),
|
|
||||||
createMachine(4, '4#', 'MA2500/1000G', '状态', 'is-running', '运行', '10小时', '488个', '2026.3.21-3.22', '25110931', '4500个', '61%', '28W 外壳', '米白', '正常生产', '26WA'),
|
|
||||||
createMachine(10, '10#', 'MA2500/1000G', '状态', 'is-running', '运行', '13小时', '610个', '2026.3.23-3.24', '25110946', '5100个', '44%', '挡板件', '黑色', '正常生产', 'M22A'),
|
|
||||||
createMachine(16, '16#', '570', '状态', 'is-running', '运行', '5小时', '190个', '2026.3.23-3.25', '25110959', '2400个', '18%', '小型卡件', '浅灰', '液压检修', 'Q30E'),
|
|
||||||
createMachine(3, '3#', 'MA2500/1000G', '状态', 'is-running', '运行', '8小时', '360个', '2026.3.20-3.22', '25110925', '3000个', '58%', '17W 支架', '银色', '等待换模', '90KT'),
|
|
||||||
createMachine(9, '9#', 'MA2500/1000G', '状态', 'is-running', '运行', '14小时', '680个', '2026.3.23-3.24', '25110945', '5400个', '52%', '导流板', '银灰', '正常生产', 'C88L'),
|
|
||||||
createMachine(15, '15#', 'MA1600/540G', '状态', 'is-running', '运行', '11小时', '460个', '2026.3.23-3.25', '25110957', '3500个', '41%', '转接件', '深灰', '正常生产', 'UV06'),
|
|
||||||
createMachine(2, '2#', 'MA2500/1000G', '状态', 'is-running', '运行', '11小时', '520个', '2026.3.18-3.20', '25110918', '4200个', '42%', '26W 面板', '黑色', '夜班优先', '188AX'),
|
|
||||||
createMachine(8, '8#', 'MA2500/1000G', '状态', 'is-running', '运行', '9小时', '430个', '2026.3.22-3.24', '25110941', '4600个', '36%', '封边件', '白色', '温控波动', 'B71S'),
|
|
||||||
createMachine(14, '14#', 'MA1600/540G', '状态', 'is-running', '运行', '10小时', '395个', '2026.3.23-3.25', '25110955', '3200个', '38%', '扣合件', '亮黑', '正常生产', 'R81N'),
|
|
||||||
createMachine(1, '1#', 'MA2500/1000G', '状态', 'is-running', '运行', '13小时', '600个', '2026.3.16-3.18', '25110914', '5000个', '30%', '23W 中间盖', '7037C 灰', '重点订单', '159BB'),
|
|
||||||
createMachine(7, '7#', 'MA2500/1000G', '状态', 'is-running', '运行', '4小时', '120个', '2026.3.22-3.24', '25110940', '3000个', '12%', '结构件', '深灰', '人工调试', 'X09M'),
|
|
||||||
createMachine(13, '13#', 'MA1600/540G', '状态', 'is-running', '运行', '7小时', '280个', '2026.3.23-3.25', '25110954', '2600个', '31%', '面罩件', '暖白', '待料', 'PK11')
|
|
||||||
],
|
|
||||||
detailRealtime: [
|
|
||||||
{ name: '温度一段(A15)', current: '186℃', currentTime: '14:20:15', target: '185℃', targetTime: '14:05:00', orderValue: '188℃', orderTime: '08:30:00' },
|
|
||||||
{ name: '温度二段(A16)', current: '192℃', currentTime: '14:20:15', target: '190℃', targetTime: '14:05:00', orderValue: '192℃', orderTime: '08:30:00' },
|
|
||||||
{ name: '射胶压力(A243)', current: '12.3MPa', currentTime: '14:20:10', target: '12.0MPa', targetTime: '14:00:00', orderValue: '12.5MPa', orderTime: '08:30:00' }
|
|
||||||
],
|
|
||||||
detailSetting: [
|
|
||||||
{ name: '开模行程(A060)', setting: '320mm', settingTime: '13:15:00', orderValue: '325mm', orderTime: '08:30:00' },
|
|
||||||
{ name: '锁模压力(A061)', setting: '86%', settingTime: '13:15:00', orderValue: '85%', orderTime: '08:30:00' },
|
|
||||||
{ name: '保压时间(A062)', setting: '4.5s', settingTime: '13:15:00', orderValue: '4.8s', orderTime: '08:30:00' }
|
|
||||||
],
|
|
||||||
detailProduction: [
|
|
||||||
{ name: '上模循环时(A37)', value: '28.6s', collectTime: '14:20:11' },
|
|
||||||
{ name: '一模产出数', value: '2', collectTime: '14:20:11' },
|
|
||||||
{ name: '累计良品数', value: '598', collectTime: '14:20:11' }
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.refreshClock()
|
this.loadBoardData()
|
||||||
this.clockTimer = setInterval(this.refreshClock, 1000)
|
this.boardTimer = setInterval(this.loadBoardData, 30000)
|
||||||
this.activeMachine = this.machineList[0]
|
this.activeMachine = this.machineList[0]
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -390,13 +353,111 @@ export default {
|
|||||||
this.tryEnterFullscreen()
|
this.tryEnterFullscreen()
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.clockTimer) {
|
if (this.boardTimer) {
|
||||||
clearInterval(this.clockTimer)
|
clearInterval(this.boardTimer)
|
||||||
this.clockTimer = null
|
this.boardTimer = null
|
||||||
}
|
}
|
||||||
this.restoreTitle()
|
this.restoreTitle()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
loadBoardData() {
|
||||||
|
const screenCode = this.$route && this.$route.query && this.$route.query.screenCode
|
||||||
|
? this.$route.query.screenCode
|
||||||
|
: DEFAULT_SCREEN_CODE
|
||||||
|
getWorkshopBoardData(screenCode).then(response => {
|
||||||
|
this.applyBoardData(response.data)
|
||||||
|
this.loadFaultList()
|
||||||
|
this.loadMaintenanceList()
|
||||||
|
}).catch(() => {
|
||||||
|
this.applyBoardData(createEmptyWorkshopBoardData())
|
||||||
|
this.faultList = []
|
||||||
|
this.maintenanceList = []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadFaultList() {
|
||||||
|
if (!this.workshopMachineCodeSet.size) {
|
||||||
|
this.faultList = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
listRepair({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: this.faultTableRows * 5
|
||||||
|
}).then(response => {
|
||||||
|
const rows = (response && response.rows) || []
|
||||||
|
this.faultList = rows
|
||||||
|
.filter(item => this.isWorkshopMachine(item && item.machineryCode))
|
||||||
|
.slice(0, this.faultTableRows)
|
||||||
|
.map(item => ({
|
||||||
|
deviceNo: item.machineryCode || '--',
|
||||||
|
faultTime: item.requireDate || '--',
|
||||||
|
faultDesc: item.repairName || item.remark || '--',
|
||||||
|
owner: item.acceptedName || item.acceptedBy || '--',
|
||||||
|
recoverTime: item.finishDate || '--'
|
||||||
|
}))
|
||||||
|
}).catch(() => {
|
||||||
|
this.faultList = []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadMaintenanceList() {
|
||||||
|
if (!this.workshopMachineCodeSet.size) {
|
||||||
|
this.maintenanceList = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
listCheckplan({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: this.planTableRows * 5
|
||||||
|
}).then(response => {
|
||||||
|
const rows = (response && response.rows) || []
|
||||||
|
this.maintenanceList = rows
|
||||||
|
.filter(item => this.hasWorkshopMachine(item && item.machineryCodes))
|
||||||
|
.slice(0, this.planTableRows)
|
||||||
|
.map(item => ({
|
||||||
|
deviceNo: item.machineryCodes || '--',
|
||||||
|
project: item.planName || '--',
|
||||||
|
planTime: this.formatPlanTime(item),
|
||||||
|
status: item.status || '--'
|
||||||
|
}))
|
||||||
|
}).catch(() => {
|
||||||
|
this.maintenanceList = []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
normalizeMachineCode(code) {
|
||||||
|
return code ? String(code).trim().toUpperCase() : ''
|
||||||
|
},
|
||||||
|
isWorkshopMachine(code) {
|
||||||
|
return this.workshopMachineCodeSet.has(this.normalizeMachineCode(code))
|
||||||
|
},
|
||||||
|
hasWorkshopMachine(codes) {
|
||||||
|
return String(codes || '')
|
||||||
|
.split(',')
|
||||||
|
.map(code => this.normalizeMachineCode(code))
|
||||||
|
.filter(Boolean)
|
||||||
|
.some(code => this.workshopMachineCodeSet.has(code))
|
||||||
|
},
|
||||||
|
formatPlanTime(item) {
|
||||||
|
const startDate = item && item.startDate ? item.startDate : ''
|
||||||
|
const endDate = item && item.endDate ? item.endDate : ''
|
||||||
|
if (startDate && endDate) {
|
||||||
|
return `${startDate} ~ ${endDate}`
|
||||||
|
}
|
||||||
|
return startDate || endDate || '--'
|
||||||
|
},
|
||||||
|
applyBoardData(boardData) {
|
||||||
|
const normalizedBoardData = boardData || createEmptyWorkshopBoardData()
|
||||||
|
this.header = normalizedBoardData.header || {}
|
||||||
|
this.summary = normalizedBoardData.summary || {}
|
||||||
|
this.machineList = normalizedBoardData.machineList || []
|
||||||
|
this.detailRealtime = normalizedBoardData.detailRealtime || []
|
||||||
|
this.detailSetting = normalizedBoardData.detailSetting || []
|
||||||
|
this.detailProduction = normalizedBoardData.detailProduction || []
|
||||||
|
this.refreshClock()
|
||||||
|
if (!this.activeMachine || !this.activeMachine.id) {
|
||||||
|
this.activeMachine = this.machineList[0] || {}
|
||||||
|
} else {
|
||||||
|
const currentMachine = this.machineList.find(item => item.id === this.activeMachine.id)
|
||||||
|
this.activeMachine = currentMachine || this.machineList[0] || {}
|
||||||
|
}
|
||||||
|
},
|
||||||
applyDisplayTitle() {
|
applyDisplayTitle() {
|
||||||
const mode = this.$route && this.$route.query ? this.$route.query.displayMode : ''
|
const mode = this.$route && this.$route.query ? this.$route.query.displayMode : ''
|
||||||
if (mode !== 'fullscreen') {
|
if (mode !== 'fullscreen') {
|
||||||
|
|||||||
@ -36,9 +36,6 @@
|
|||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['mes:md:measurepoint:remove']">删除</el-button>
|
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['mes:md:measurepoint:remove']">删除</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="warning" plain icon="el-icon-refresh" size="mini" @click="refreshLatest" v-hasPermi="['mes:md:measurepoint:query']">刷新最新值</el-button>
|
|
||||||
</el-col>
|
|
||||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
@ -53,12 +50,6 @@
|
|||||||
<el-table-column label="车间" align="center" prop="workshopName" min-width="120" />
|
<el-table-column label="车间" align="center" prop="workshopName" min-width="120" />
|
||||||
<el-table-column label="设备编码" align="center" prop="deviceCode" min-width="120" />
|
<el-table-column label="设备编码" align="center" prop="deviceCode" min-width="120" />
|
||||||
<el-table-column label="节点编码" align="center" prop="nodeCode" min-width="120" />
|
<el-table-column label="节点编码" align="center" prop="nodeCode" min-width="120" />
|
||||||
<el-table-column label="最新值" align="center" min-width="120">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span>{{ formatLatestValue(scope.row) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="最新时间" align="center" prop="latestTime" min-width="180" :show-overflow-tooltip="true" />
|
|
||||||
<el-table-column label="单位" align="center" prop="unit" width="80" />
|
<el-table-column label="单位" align="center" prop="unit" width="80" />
|
||||||
<el-table-column label="字段" align="center" prop="fieldKey" min-width="120" />
|
<el-table-column label="字段" align="center" prop="fieldKey" min-width="120" />
|
||||||
<el-table-column label="启用" align="center" prop="enableFlag" width="80">
|
<el-table-column label="启用" align="center" prop="enableFlag" width="80">
|
||||||
@ -371,9 +362,6 @@ export default {
|
|||||||
this.open = false
|
this.open = false
|
||||||
this.reset()
|
this.reset()
|
||||||
},
|
},
|
||||||
refreshLatest() {
|
|
||||||
this.getList()
|
|
||||||
},
|
|
||||||
formatLatestValue(row) {
|
formatLatestValue(row) {
|
||||||
if (!row || row.latestValue === null || row.latestValue === undefined || row.latestValue === '') {
|
if (!row || row.latestValue === null || row.latestValue === undefined || row.latestValue === '') {
|
||||||
return '-'
|
return '-'
|
||||||
|
|||||||
787
src/views/mes/md/screenbinding/index.vue
Normal file
787
src/views/mes/md/screenbinding/index.vue
Normal file
@ -0,0 +1,787 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container board-screen-page">
|
||||||
|
<el-form :model="queryParams" size="small" :inline="true" label-width="80px">
|
||||||
|
<el-form-item label="看板编码">
|
||||||
|
<el-input v-model="queryParams.screenCode" placeholder="请输入看板编码" clearable style="width: 180px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="责任人">
|
||||||
|
<el-input v-model="queryParams.ownerName" placeholder="请输入责任人" clearable style="width: 180px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所属车间">
|
||||||
|
<el-select v-model="queryParams.workshopId" placeholder="请选择车间" clearable filterable style="width: 180px">
|
||||||
|
<el-option v-for="item in workshopOptions" :key="item.workshopId" :label="item.workshopName" :value="item.workshopId" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="getScreenList">查询</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||||
|
<el-button type="success" plain icon="el-icon-plus" size="mini" @click="openScreenDialog()">新增看板</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="9">
|
||||||
|
<el-card shadow="never" class="panel-card">
|
||||||
|
<div slot="header" class="card-header">
|
||||||
|
<span>看板列表</span>
|
||||||
|
</div>
|
||||||
|
<el-table
|
||||||
|
v-loading="screenLoading"
|
||||||
|
:data="screenList"
|
||||||
|
border
|
||||||
|
height="620"
|
||||||
|
highlight-current-row
|
||||||
|
row-key="screenId"
|
||||||
|
@current-change="handleCurrentScreenChange"
|
||||||
|
>
|
||||||
|
<el-table-column label="看板编码" prop="screenCode" min-width="140" />
|
||||||
|
<el-table-column label="车间" prop="workshopName" min-width="120" show-overflow-tooltip />
|
||||||
|
<el-table-column label="责任人" prop="ownerName" min-width="100" />
|
||||||
|
<el-table-column label="设备数" align="center" prop="deviceTotal" width="80" />
|
||||||
|
<el-table-column label="操作" align="center" width="150" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="text" size="mini" @click.stop="openScreenDialog(scope.row)">编辑</el-button>
|
||||||
|
<el-button type="text" size="mini" @click.stop="removeScreen(scope.row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="15">
|
||||||
|
<el-card shadow="never" class="panel-card">
|
||||||
|
<div slot="header" class="card-header">
|
||||||
|
<div>
|
||||||
|
<div class="screen-title">{{ currentScreen ? currentScreen.screenCode : '请选择看板' }}</div>
|
||||||
|
<div class="screen-subtitle">{{ currentScreenSummary }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="currentScreen">
|
||||||
|
<el-button type="primary" plain size="mini" icon="el-icon-plus" @click="openDeviceDialog">添加设备</el-button>
|
||||||
|
<el-button type="warning" plain size="mini" icon="el-icon-delete" @click="resetConfig">清空绑定</el-button>
|
||||||
|
<el-button type="primary" plain size="mini" icon="el-icon-monitor" @click="openBoard">打开看板</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="!currentScreen" class="empty-block">
|
||||||
|
请选择左侧看板,开始配置设备和点位绑定。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<el-collapse v-model="activeMachines">
|
||||||
|
<el-collapse-item
|
||||||
|
v-for="machine in machineConfigs"
|
||||||
|
:key="machine.machineCode"
|
||||||
|
:name="machine.machineCode"
|
||||||
|
>
|
||||||
|
<template slot="title">
|
||||||
|
<div class="machine-title-row">
|
||||||
|
<span>{{ machine.machineCode }}</span>
|
||||||
|
<span class="machine-name">{{ machine.machineName || '--' }}</span>
|
||||||
|
<el-button type="text" size="mini" class="machine-remove" @click.stop="removeMachine(machine.machineCode)">移除设备</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-table :data="machine.bindings" border>
|
||||||
|
<el-table-column label="字段名称" prop="fieldName" min-width="140" />
|
||||||
|
<el-table-column label="字段键" prop="bindingField" min-width="140" />
|
||||||
|
<el-table-column label="当前点位" min-width="220">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ getPointSummary(scope.row) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="预览值" min-width="160">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ getPreviewValue(scope.row) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" width="120">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="text" size="mini" @click="openBindingEditor(machine, scope.row)">配置点位</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</template>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-dialog :title="screenDialogTitle" :visible.sync="screenDialogOpen" width="640px" append-to-body>
|
||||||
|
<el-form ref="screenForm" :model="screenForm" :rules="screenRules" label-width="96px">
|
||||||
|
<el-form-item label="看板编码" prop="screenCode">
|
||||||
|
<el-input v-model="screenForm.screenCode" placeholder="请输入看板编码" :disabled="!!screenForm.screenId" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="责任人" prop="ownerName">
|
||||||
|
<el-input v-model="screenForm.ownerName" placeholder="请输入责任人" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所属车间" prop="workshopId">
|
||||||
|
<el-select v-model="screenForm.workshopId" placeholder="请选择车间" filterable style="width: 100%" @change="handleWorkshopChange">
|
||||||
|
<el-option v-for="item in workshopOptions" :key="item.workshopId" :label="item.workshopName" :value="item.workshopId" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注">
|
||||||
|
<el-input v-model="screenForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitScreenForm">确 定</el-button>
|
||||||
|
<el-button @click="screenDialogOpen = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog title="添加设备" :visible.sync="deviceDialogOpen" width="1000px" append-to-body>
|
||||||
|
<el-form :model="deviceQuery" size="small" :inline="true" label-width="80px">
|
||||||
|
<el-form-item label="设备编码">
|
||||||
|
<el-input v-model="deviceQuery.machineryCode" placeholder="请输入设备编码,支持模糊搜索" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="设备名称">
|
||||||
|
<el-input v-model="deviceQuery.machineryName" placeholder="请输入设备名称,支持模糊搜索" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="getDeviceList">查询</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetDeviceQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-table
|
||||||
|
v-loading="deviceLoading"
|
||||||
|
:data="deviceList"
|
||||||
|
border
|
||||||
|
height="420"
|
||||||
|
@selection-change="handleDeviceSelectionChange"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="55" />
|
||||||
|
<el-table-column label="设备编码" prop="machineryCode" min-width="140" />
|
||||||
|
<el-table-column label="设备名称" prop="machineryName" min-width="160" />
|
||||||
|
<el-table-column label="设备型号" prop="machinerySpec" min-width="160" />
|
||||||
|
<el-table-column label="所属车间" prop="workshopName" min-width="140" />
|
||||||
|
</el-table>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="appendSelectedDevices">确 定</el-button>
|
||||||
|
<el-button @click="deviceDialogOpen = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog title="配置点位" :visible.sync="editorOpen" width="760px" append-to-body>
|
||||||
|
<el-form :model="editForm" label-width="96px">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="设备编码">
|
||||||
|
<el-input :value="editMachine.machineCode" readonly />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="字段名称">
|
||||||
|
<el-input :value="editForm.fieldName" readonly />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-form-item label="测量点">
|
||||||
|
<el-input :value="getPointSummary(editForm)" readonly placeholder="请选择测量点" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label-width="0">
|
||||||
|
<el-button icon="el-icon-search" @click="openPointDialog">选择点位</el-button>
|
||||||
|
<el-button type="text" @click="clearPoint">清空</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="当前预览">
|
||||||
|
<el-input :value="getPreviewValue(editForm)" readonly />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitBindingEdit">确 定</el-button>
|
||||||
|
<el-button @click="editorOpen = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog title="选择测量点" :visible.sync="pointDialogOpen" width="1000px" append-to-body>
|
||||||
|
<el-form :model="pointQuery" size="small" :inline="true" label-width="84px">
|
||||||
|
<el-form-item label="测量点编码">
|
||||||
|
<el-input v-model="pointQuery.pointCode" placeholder="请输入测量点编码" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="测量点名称">
|
||||||
|
<el-input v-model="pointQuery.pointName" placeholder="请输入测量点名称" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="设备编码">
|
||||||
|
<el-input v-model="pointQuery.deviceCode" placeholder="请输入设备编码" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="getPointList">搜索</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetPointQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-table v-loading="pointLoading" :data="pointList" border height="420">
|
||||||
|
<el-table-column label="测量点编码" prop="pointCode" min-width="130" />
|
||||||
|
<el-table-column label="测量点名称" prop="pointName" min-width="160" />
|
||||||
|
<el-table-column label="设备编码" prop="deviceCode" min-width="120" />
|
||||||
|
<el-table-column label="最新值" min-width="140">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ formatPointLatest(scope.row) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="最新时间" prop="latestTime" min-width="170" />
|
||||||
|
<el-table-column label="操作" align="center" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="text" size="mini" @click="selectPoint(scope.row)">选择</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listMeasurePoint, getMeasurePointLatest } from '@/api/mes/md/measurepoint'
|
||||||
|
import { listAllWorkshop } from '@/api/mes/md/workshop'
|
||||||
|
import { listMachinery } from '@/api/mes/dv/machinery'
|
||||||
|
import {
|
||||||
|
addBoardScreen,
|
||||||
|
delBoardScreen,
|
||||||
|
getBoardScreenConfig,
|
||||||
|
listBoardScreen,
|
||||||
|
resetBoardScreenConfig,
|
||||||
|
saveBoardScreenConfig,
|
||||||
|
updateBoardScreen
|
||||||
|
} from '@/api/mes/board/screen'
|
||||||
|
|
||||||
|
const FIELD_OPTIONS = [
|
||||||
|
{ bindingField: 'device_status', fieldName: '设备状态' },
|
||||||
|
{ bindingField: 'run_mode', fieldName: '运行模式' },
|
||||||
|
{ bindingField: 'today_run_time', fieldName: '今日开机时长' },
|
||||||
|
{ bindingField: 'today_piece_count', fieldName: '今日计件数' },
|
||||||
|
{ bindingField: 'batch_code', fieldName: '批次号' }
|
||||||
|
]
|
||||||
|
|
||||||
|
function buildFieldMap() {
|
||||||
|
return FIELD_OPTIONS.reduce((result, item) => {
|
||||||
|
result[item.bindingField] = item.fieldName
|
||||||
|
return result
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
|
||||||
|
const FIELD_NAME_MAP = buildFieldMap()
|
||||||
|
|
||||||
|
function createBindingSkeleton(machine, field) {
|
||||||
|
return {
|
||||||
|
bindingId: null,
|
||||||
|
screenId: null,
|
||||||
|
screenCode: '',
|
||||||
|
machineryId: machine.machineryId,
|
||||||
|
machineryCode: machine.machineryCode,
|
||||||
|
bindingField: field.bindingField,
|
||||||
|
fieldName: field.fieldName,
|
||||||
|
pointId: null,
|
||||||
|
pointCode: '',
|
||||||
|
pointName: '',
|
||||||
|
sortNum: FIELD_OPTIONS.findIndex(item => item.bindingField === field.bindingField) + 1,
|
||||||
|
enableFlag: 'Y'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMachineConfig(machine) {
|
||||||
|
return {
|
||||||
|
machineryId: machine.machineryId,
|
||||||
|
machineCode: machine.machineryCode,
|
||||||
|
machineName: machine.machineryName || '',
|
||||||
|
bindings: FIELD_OPTIONS.map(field => createBindingSkeleton(machine, field))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupBindings(bindings, deviceNameMap) {
|
||||||
|
const grouped = {}
|
||||||
|
;(bindings || []).forEach(item => {
|
||||||
|
const machineCode = item.machineryCode
|
||||||
|
if (!machineCode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!grouped[machineCode]) {
|
||||||
|
grouped[machineCode] = createMachineConfig({
|
||||||
|
machineryId: item.machineryId,
|
||||||
|
machineryCode: item.machineryCode,
|
||||||
|
machineryName: deviceNameMap[item.machineryCode] || ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const target = grouped[machineCode].bindings.find(binding => binding.bindingField === item.bindingField)
|
||||||
|
if (target) {
|
||||||
|
Object.assign(target, item, {
|
||||||
|
fieldName: FIELD_NAME_MAP[item.bindingField] || item.bindingField
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return Object.keys(grouped).sort().map(key => grouped[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectPointCodes(machineConfigs) {
|
||||||
|
const pointCodeMap = {}
|
||||||
|
;(machineConfigs || []).forEach(machine => {
|
||||||
|
(machine.bindings || []).forEach(binding => {
|
||||||
|
if (binding.pointCode) {
|
||||||
|
pointCodeMap[binding.pointCode] = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return Object.keys(pointCodeMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ScreenBinding',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
screenLoading: false,
|
||||||
|
saveLoading: false,
|
||||||
|
pointLoading: false,
|
||||||
|
deviceLoading: false,
|
||||||
|
screenDialogOpen: false,
|
||||||
|
deviceDialogOpen: false,
|
||||||
|
editorOpen: false,
|
||||||
|
pointDialogOpen: false,
|
||||||
|
workshopOptions: [],
|
||||||
|
screenList: [],
|
||||||
|
pointList: [],
|
||||||
|
deviceList: [],
|
||||||
|
selectedDeviceRows: [],
|
||||||
|
currentScreen: null,
|
||||||
|
machineConfigs: [],
|
||||||
|
activeMachines: [],
|
||||||
|
latestMap: {},
|
||||||
|
deviceNameMap: {},
|
||||||
|
queryParams: {
|
||||||
|
screenCode: '',
|
||||||
|
ownerName: '',
|
||||||
|
workshopId: null
|
||||||
|
},
|
||||||
|
screenForm: {
|
||||||
|
screenId: null,
|
||||||
|
screenCode: '',
|
||||||
|
ownerName: '',
|
||||||
|
workshopId: null,
|
||||||
|
workshopCode: '',
|
||||||
|
workshopName: '',
|
||||||
|
remark: ''
|
||||||
|
},
|
||||||
|
screenRules: {
|
||||||
|
screenCode: [{ required: true, message: '看板编码不能为空', trigger: 'blur' }],
|
||||||
|
ownerName: [{ required: true, message: '责任人不能为空', trigger: 'blur' }],
|
||||||
|
workshopId: [{ required: true, message: '所属车间不能为空', trigger: 'change' }]
|
||||||
|
},
|
||||||
|
deviceQuery: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 200,
|
||||||
|
machineryCode: '',
|
||||||
|
machineryName: ''
|
||||||
|
},
|
||||||
|
pointQuery: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 200,
|
||||||
|
pointCode: '',
|
||||||
|
pointName: '',
|
||||||
|
deviceCode: '',
|
||||||
|
enableFlag: 'Y'
|
||||||
|
},
|
||||||
|
editMachine: {},
|
||||||
|
editForm: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
currentScreenSummary() {
|
||||||
|
if (!this.currentScreen) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const workshopName = this.currentScreen.workshopName || '--'
|
||||||
|
const ownerName = this.currentScreen.ownerName || '--'
|
||||||
|
return `车间:${workshopName},责任人:${ownerName}`
|
||||||
|
},
|
||||||
|
screenDialogTitle() {
|
||||||
|
return this.screenForm.screenId ? '编辑看板' : '新增看板'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getWorkshopOptions()
|
||||||
|
this.getDeviceList()
|
||||||
|
this.getScreenList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getWorkshopOptions() {
|
||||||
|
listAllWorkshop().then(response => {
|
||||||
|
this.workshopOptions = Array.isArray(response) ? response : (response.data || [])
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getScreenList() {
|
||||||
|
this.screenLoading = true
|
||||||
|
listBoardScreen(this.queryParams).then(response => {
|
||||||
|
this.screenList = response.rows || []
|
||||||
|
if (!this.screenList.length) {
|
||||||
|
this.currentScreen = null
|
||||||
|
this.machineConfigs = []
|
||||||
|
this.activeMachines = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const nextCurrent = this.currentScreen
|
||||||
|
? this.screenList.find(item => item.screenId === this.currentScreen.screenId)
|
||||||
|
: this.screenList[0]
|
||||||
|
this.handleCurrentScreenChange(nextCurrent)
|
||||||
|
}).finally(() => {
|
||||||
|
this.screenLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetQuery() {
|
||||||
|
this.queryParams = {
|
||||||
|
screenCode: '',
|
||||||
|
ownerName: '',
|
||||||
|
workshopId: null
|
||||||
|
}
|
||||||
|
this.getScreenList()
|
||||||
|
},
|
||||||
|
handleCurrentScreenChange(row) {
|
||||||
|
if (!row || (this.currentScreen && this.currentScreen.screenId === row.screenId && this.machineConfigs.length)) {
|
||||||
|
this.currentScreen = row || null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.currentScreen = row
|
||||||
|
this.loadCurrentConfig()
|
||||||
|
},
|
||||||
|
loadCurrentConfig() {
|
||||||
|
if (!this.currentScreen) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
getBoardScreenConfig(this.currentScreen.screenId).then(response => {
|
||||||
|
const bindings = response.data || []
|
||||||
|
this.machineConfigs = groupBindings(bindings, this.deviceNameMap)
|
||||||
|
this.activeMachines = this.machineConfigs.map(item => item.machineCode)
|
||||||
|
this.refreshPreview()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openScreenDialog(row) {
|
||||||
|
if (this.$refs.screenForm) {
|
||||||
|
this.$refs.screenForm.resetFields()
|
||||||
|
}
|
||||||
|
if (row) {
|
||||||
|
this.screenForm = { ...row }
|
||||||
|
} else {
|
||||||
|
this.screenForm = {
|
||||||
|
screenId: null,
|
||||||
|
screenCode: '',
|
||||||
|
ownerName: '',
|
||||||
|
workshopId: null,
|
||||||
|
workshopCode: '',
|
||||||
|
workshopName: '',
|
||||||
|
remark: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.screenDialogOpen = true
|
||||||
|
},
|
||||||
|
handleWorkshopChange(workshopId) {
|
||||||
|
const workshop = this.workshopOptions.find(item => item.workshopId === workshopId)
|
||||||
|
this.screenForm.workshopCode = workshop ? workshop.workshopCode : ''
|
||||||
|
this.screenForm.workshopName = workshop ? workshop.workshopName : ''
|
||||||
|
},
|
||||||
|
submitScreenForm() {
|
||||||
|
this.$refs.screenForm.validate(valid => {
|
||||||
|
if (!valid) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const request = this.screenForm.screenId ? updateBoardScreen(this.screenForm) : addBoardScreen(this.screenForm)
|
||||||
|
request.then(() => {
|
||||||
|
this.screenDialogOpen = false
|
||||||
|
this.$modal.msgSuccess(this.screenForm.screenId ? '修改成功' : '新增成功')
|
||||||
|
this.getScreenList()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
removeScreen(row) {
|
||||||
|
this.$modal.confirm(`是否确认删除看板 ${row.screenCode}?`).then(() => {
|
||||||
|
return delBoardScreen(row.screenId)
|
||||||
|
}).then(() => {
|
||||||
|
this.$modal.msgSuccess('删除成功')
|
||||||
|
this.getScreenList()
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
getDeviceList() {
|
||||||
|
this.deviceLoading = true
|
||||||
|
listMachinery(this.deviceQuery).then(response => {
|
||||||
|
this.deviceList = response.rows || []
|
||||||
|
;(response.rows || []).forEach(item => {
|
||||||
|
this.deviceNameMap[item.machineryCode] = item.machineryName
|
||||||
|
})
|
||||||
|
}).finally(() => {
|
||||||
|
this.deviceLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetDeviceQuery() {
|
||||||
|
this.deviceQuery.machineryCode = ''
|
||||||
|
this.deviceQuery.machineryName = ''
|
||||||
|
this.getDeviceList()
|
||||||
|
},
|
||||||
|
openDeviceDialog() {
|
||||||
|
this.selectedDeviceRows = []
|
||||||
|
this.deviceDialogOpen = true
|
||||||
|
this.getDeviceList()
|
||||||
|
},
|
||||||
|
handleDeviceSelectionChange(rows) {
|
||||||
|
this.selectedDeviceRows = rows || []
|
||||||
|
},
|
||||||
|
appendSelectedDevices() {
|
||||||
|
if (!this.selectedDeviceRows.length) {
|
||||||
|
this.$modal.msgWarning('请先选择设备')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const codeMap = {}
|
||||||
|
let changed = false
|
||||||
|
this.machineConfigs.forEach(item => {
|
||||||
|
codeMap[item.machineCode] = true
|
||||||
|
})
|
||||||
|
this.selectedDeviceRows.forEach(item => {
|
||||||
|
if (codeMap[item.machineryCode]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.deviceNameMap[item.machineryCode] = item.machineryName
|
||||||
|
this.machineConfigs.push(createMachineConfig(item))
|
||||||
|
changed = true
|
||||||
|
})
|
||||||
|
if (!changed) {
|
||||||
|
this.$modal.msgWarning('所选设备已存在')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.machineConfigs.sort((a, b) => a.machineCode.localeCompare(b.machineCode))
|
||||||
|
this.activeMachines = this.machineConfigs.map(item => item.machineCode)
|
||||||
|
this.persistConfig({
|
||||||
|
successMessage: '设备添加成功',
|
||||||
|
onSuccess: () => {
|
||||||
|
this.deviceDialogOpen = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
removeMachine(machineCode) {
|
||||||
|
this.machineConfigs = this.machineConfigs.filter(item => item.machineCode !== machineCode)
|
||||||
|
this.activeMachines = this.machineConfigs.map(item => item.machineCode)
|
||||||
|
this.persistConfig({
|
||||||
|
successMessage: '设备移除成功'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openBindingEditor(machine, binding) {
|
||||||
|
this.editMachine = { ...machine }
|
||||||
|
this.editForm = JSON.parse(JSON.stringify(binding))
|
||||||
|
this.editorOpen = true
|
||||||
|
},
|
||||||
|
openPointDialog() {
|
||||||
|
this.pointDialogOpen = true
|
||||||
|
this.getPointList()
|
||||||
|
},
|
||||||
|
getPointList() {
|
||||||
|
this.pointLoading = true
|
||||||
|
listMeasurePoint(this.pointQuery).then(response => {
|
||||||
|
this.pointList = response.rows || []
|
||||||
|
}).finally(() => {
|
||||||
|
this.pointLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetPointQuery() {
|
||||||
|
this.pointQuery.pointCode = ''
|
||||||
|
this.pointQuery.pointName = ''
|
||||||
|
this.pointQuery.deviceCode = ''
|
||||||
|
this.getPointList()
|
||||||
|
},
|
||||||
|
selectPoint(row) {
|
||||||
|
this.editForm.pointId = row.pointId
|
||||||
|
this.editForm.pointCode = row.pointCode
|
||||||
|
this.editForm.pointName = row.pointName
|
||||||
|
this.pointDialogOpen = false
|
||||||
|
},
|
||||||
|
clearPoint() {
|
||||||
|
this.editForm.pointId = null
|
||||||
|
this.editForm.pointCode = ''
|
||||||
|
this.editForm.pointName = ''
|
||||||
|
},
|
||||||
|
submitBindingEdit() {
|
||||||
|
const machine = this.machineConfigs.find(item => item.machineCode === this.editMachine.machineCode)
|
||||||
|
if (!machine) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const target = machine.bindings.find(item => item.bindingField === this.editForm.bindingField)
|
||||||
|
if (target) {
|
||||||
|
Object.assign(target, this.editForm)
|
||||||
|
}
|
||||||
|
this.editorOpen = false
|
||||||
|
this.refreshPreview()
|
||||||
|
this.persistConfig({
|
||||||
|
successMessage: '点位配置已保存'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
persistConfig({ successMessage, onSuccess } = {}) {
|
||||||
|
if (!this.currentScreen) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const bindings = []
|
||||||
|
this.machineConfigs.forEach(machine => {
|
||||||
|
machine.bindings.forEach(binding => {
|
||||||
|
bindings.push({
|
||||||
|
bindingId: binding.bindingId,
|
||||||
|
screenId: this.currentScreen.screenId,
|
||||||
|
screenCode: this.currentScreen.screenCode,
|
||||||
|
machineryId: machine.machineryId,
|
||||||
|
machineryCode: machine.machineCode,
|
||||||
|
bindingField: binding.bindingField,
|
||||||
|
pointId: binding.pointId,
|
||||||
|
pointCode: binding.pointCode || '',
|
||||||
|
pointName: binding.pointName || '',
|
||||||
|
sortNum: binding.sortNum,
|
||||||
|
enableFlag: 'Y'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.saveLoading = true
|
||||||
|
saveBoardScreenConfig({
|
||||||
|
screenId: this.currentScreen.screenId,
|
||||||
|
screenCode: this.currentScreen.screenCode,
|
||||||
|
bindings
|
||||||
|
}).then(response => {
|
||||||
|
this.machineConfigs = groupBindings(response.data || [], this.deviceNameMap)
|
||||||
|
this.activeMachines = this.machineConfigs.map(item => item.machineCode)
|
||||||
|
this.refreshPreview()
|
||||||
|
if (typeof onSuccess === 'function') {
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
this.$modal.msgSuccess(successMessage || response.msg || '保存成功')
|
||||||
|
this.getScreenList()
|
||||||
|
}).finally(() => {
|
||||||
|
this.saveLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetConfig() {
|
||||||
|
if (!this.currentScreen) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$modal.confirm('是否确认清空当前看板的设备绑定和点位配置?').then(() => {
|
||||||
|
return resetBoardScreenConfig(this.currentScreen.screenId)
|
||||||
|
}).then(() => {
|
||||||
|
this.machineConfigs = []
|
||||||
|
this.activeMachines = []
|
||||||
|
this.latestMap = {}
|
||||||
|
this.$modal.msgSuccess('已清空绑定配置')
|
||||||
|
this.getScreenList()
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
refreshPreview() {
|
||||||
|
const pointCodes = collectPointCodes(this.machineConfigs)
|
||||||
|
if (!pointCodes.length) {
|
||||||
|
this.latestMap = {}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Promise.all(pointCodes.map(pointCode => {
|
||||||
|
return getMeasurePointLatest(pointCode).then(response => {
|
||||||
|
const payload = response && response.data !== undefined ? response.data : response
|
||||||
|
return {
|
||||||
|
pointCode,
|
||||||
|
value: payload.latestValue !== undefined ? payload.latestValue : payload.value,
|
||||||
|
latestTime: payload.latestTime || payload.collectTime || payload.time || ''
|
||||||
|
}
|
||||||
|
}).catch(() => ({
|
||||||
|
pointCode,
|
||||||
|
value: '',
|
||||||
|
latestTime: ''
|
||||||
|
}))
|
||||||
|
})).then(list => {
|
||||||
|
this.latestMap = list.reduce((result, item) => {
|
||||||
|
result[item.pointCode] = item
|
||||||
|
return result
|
||||||
|
}, {})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getPointSummary(binding) {
|
||||||
|
if (!binding.pointCode) {
|
||||||
|
return '未配置测量点'
|
||||||
|
}
|
||||||
|
return `${binding.pointCode} / ${binding.pointName || '--'}`
|
||||||
|
},
|
||||||
|
getPreviewValue(binding) {
|
||||||
|
if (!binding.pointCode) {
|
||||||
|
return '--'
|
||||||
|
}
|
||||||
|
const latest = this.latestMap[binding.pointCode] || {}
|
||||||
|
const value = latest.value
|
||||||
|
return value === undefined || value === null || value === '' ? '--' : value
|
||||||
|
},
|
||||||
|
formatPointLatest(row) {
|
||||||
|
const value = row.latestValue === undefined || row.latestValue === null || row.latestValue === '' ? '--' : row.latestValue
|
||||||
|
if (!row.unit || value === '--') {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return `${value}${row.unit}`
|
||||||
|
},
|
||||||
|
openBoard() {
|
||||||
|
if (!this.currentScreen) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const routeData = this.$router.resolve({
|
||||||
|
path: '/board/workshop',
|
||||||
|
query: {
|
||||||
|
screenCode: this.currentScreen.screenCode
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.open(routeData.href, '_blank')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.board-screen-page {
|
||||||
|
min-width: 1200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-card {
|
||||||
|
min-height: 680px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-subtitle {
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-block {
|
||||||
|
min-height: 520px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.machine-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.machine-name {
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.machine-remove {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user