Vue.component("watch-dual-crn-card", {
|
template: `
|
<div class="mc-root">
|
<div class="mc-toolbar">
|
<div class="mc-title">双工位堆垛机监控</div>
|
<div class="mc-search">
|
<input class="mc-input" v-model="searchCrnNo" placeholder="请输入堆垛机号" />
|
<button type="button" class="mc-btn mc-btn-ghost" @click="getDualCrnStateInfo">查询</button>
|
</div>
|
</div>
|
|
<div v-if="!readOnly" class="mc-control-toggle">
|
<button type="button" class="mc-btn mc-btn-ghost" @click="openControl">
|
{{ showControl ? '收起控制中心' : '打开控制中心' }}
|
</button>
|
</div>
|
|
<div v-if="showControl" class="mc-control">
|
<div class="mc-control-grid">
|
<label class="mc-field">
|
<span class="mc-field-label">堆垛机号</span>
|
<input class="mc-input" v-model="controlParam.crnNo" placeholder="例如 2" />
|
</label>
|
<label class="mc-field">
|
<span class="mc-field-label">工位</span>
|
<select class="mc-select" v-model="controlParam.station">
|
<option :value="1">工位1</option>
|
<option :value="2">工位2</option>
|
</select>
|
</label>
|
<label class="mc-field">
|
<span class="mc-field-label">源库位</span>
|
<input class="mc-input" v-model="controlParam.sourceLocNo" placeholder="输入源点" />
|
</label>
|
<label class="mc-field">
|
<span class="mc-field-label">目标库位</span>
|
<input class="mc-input" v-model="controlParam.targetLocNo" placeholder="输入目标点" />
|
</label>
|
<div class="mc-action-row">
|
<button type="button" class="mc-btn" @click="controlCommandTransport">取放货</button>
|
<button type="button" class="mc-btn mc-btn-ghost" @click="controlCommandPickup">取货</button>
|
<button type="button" class="mc-btn mc-btn-ghost" @click="controlCommandPutdown">放货</button>
|
<button type="button" class="mc-btn mc-btn-ghost" @click="controlCommandMove">移动</button>
|
<button type="button" class="mc-btn mc-btn-soft" @click="controlCommandTaskComplete">任务完成</button>
|
</div>
|
</div>
|
</div>
|
|
<div class="mc-collapse">
|
<div
|
v-for="item in displayCrnList"
|
:key="item.crnNo"
|
:class="['mc-item', { 'is-open': isActive(item.crnNo) }]"
|
>
|
<button type="button" class="mc-head" @click="toggleItem(item)">
|
<div class="mc-head-main">
|
<div class="mc-head-title">{{ item.crnNo }}号双工位堆垛机</div>
|
<div class="mc-head-subtitle">工位1 {{ orDash(item.taskNo) }} | 工位2 {{ orDash(item.taskNoTwo) }}</div>
|
</div>
|
<div class="mc-head-right">
|
<span :class="['mc-badge', 'is-' + getStatusTone(item)]">{{ getStatusLabel(item) }}</span>
|
<span class="mc-chevron">{{ isActive(item.crnNo) ? '▾' : '▸' }}</span>
|
</div>
|
</button>
|
|
<div v-if="isActive(item.crnNo)" class="mc-body">
|
<div class="mc-inline-actions" v-if="!readOnly">
|
<button type="button" class="mc-link" @click.stop="editTaskNo(item, 1)">编辑工位1任务号</button>
|
<button type="button" class="mc-link" @click.stop="editTaskNo(item, 2)">编辑工位2任务号</button>
|
</div>
|
<div class="mc-detail-grid">
|
<div v-for="entry in buildDetailEntries(item)" :key="entry.label" class="mc-detail-cell">
|
<div class="mc-detail-label">{{ entry.label }}</div>
|
<div class="mc-detail-value">{{ entry.value }}</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<div v-if="displayCrnList.length === 0" class="mc-empty">当前没有可展示的双工位堆垛机数据</div>
|
</div>
|
|
<div class="mc-footer">
|
<button type="button" class="mc-page-btn" :disabled="currentPage <= 1" @click="handlePageChange(currentPage - 1)">上一页</button>
|
<span>{{ currentPage }} / {{ totalPages }}</span>
|
<button type="button" class="mc-page-btn" :disabled="currentPage >= totalPages" @click="handlePageChange(currentPage + 1)">下一页</button>
|
</div>
|
</div>
|
`,
|
props: {
|
param: { type: Object, default: function () { return {}; } },
|
items: { type: Array, default: null },
|
autoRefresh: { type: Boolean, default: true },
|
readOnly: { type: Boolean, default: false }
|
},
|
data: function () {
|
return {
|
crnList: [],
|
activeNames: "",
|
searchCrnNo: "",
|
showControl: false,
|
controlParam: {
|
crnNo: "",
|
sourceLocNo: "",
|
targetLocNo: "",
|
station: 1
|
},
|
pageSize: 12,
|
currentPage: 1,
|
timer: null
|
};
|
},
|
computed: {
|
sourceList: function () {
|
return Array.isArray(this.items) ? this.items : this.crnList;
|
},
|
filteredCrnList: function () {
|
var keyword = String(this.searchCrnNo || "").trim();
|
if (!keyword) {
|
return this.sourceList;
|
}
|
return this.sourceList.filter(function (item) {
|
return String(item.crnNo) === keyword;
|
});
|
},
|
displayCrnList: function () {
|
var start = (this.currentPage - 1) * this.pageSize;
|
return this.filteredCrnList.slice(start, start + this.pageSize);
|
},
|
totalPages: function () {
|
return Math.max(1, Math.ceil(this.filteredCrnList.length / this.pageSize) || 1);
|
}
|
},
|
watch: {
|
items: function () {
|
this.afterDataRefresh();
|
},
|
param: {
|
deep: true,
|
immediate: true,
|
handler: function (newVal) {
|
if (newVal && newVal.crnNo && newVal.crnNo !== 0) {
|
this.focusCrn(newVal.crnNo);
|
}
|
}
|
}
|
},
|
created: function () {
|
MonitorCardKit.ensureStyles();
|
if (this.autoRefresh) {
|
this.timer = setInterval(this.getDualCrnStateInfo, 1000);
|
}
|
},
|
beforeDestroy: function () {
|
if (this.timer) {
|
clearInterval(this.timer);
|
this.timer = null;
|
}
|
},
|
methods: {
|
orDash: function (value) {
|
return MonitorCardKit.orDash(value);
|
},
|
getStatusLabel: function (item) {
|
return MonitorCardKit.deviceStatusLabel(item && item.deviceStatus);
|
},
|
getStatusTone: function (item) {
|
return MonitorCardKit.statusTone(this.getStatusLabel(item));
|
},
|
isActive: function (crnNo) {
|
return String(this.activeNames) === String(crnNo);
|
},
|
toggleItem: function (item) {
|
var next = String(item.crnNo);
|
this.activeNames = this.activeNames === next ? "" : next;
|
},
|
focusCrn: function (crnNo) {
|
this.searchCrnNo = String(crnNo);
|
var index = this.filteredCrnList.findIndex(function (item) {
|
return String(item.crnNo) === String(crnNo);
|
});
|
this.currentPage = index >= 0 ? Math.floor(index / this.pageSize) + 1 : 1;
|
this.activeNames = String(crnNo);
|
},
|
afterDataRefresh: function () {
|
if (this.currentPage > this.totalPages) {
|
this.currentPage = this.totalPages;
|
}
|
if (this.activeNames) {
|
var exists = this.filteredCrnList.some(function (item) {
|
return String(item.crnNo) === String(this.activeNames);
|
}, this);
|
if (!exists) {
|
this.activeNames = "";
|
}
|
}
|
},
|
handlePageChange: function (page) {
|
if (page < 1 || page > this.totalPages) {
|
return;
|
}
|
this.currentPage = page;
|
},
|
getDualCrnStateInfo: function () {
|
if (this.$root && this.$root.sendWs) {
|
this.$root.sendWs(JSON.stringify({
|
url: "/dualcrn/table/crn/state",
|
data: {}
|
}));
|
}
|
},
|
setDualCrnList: function (res) {
|
if (res && res.code === 200) {
|
this.crnList = res.data || [];
|
this.afterDataRefresh();
|
}
|
},
|
openControl: function () {
|
this.showControl = !this.showControl;
|
},
|
buildDetailEntries: function (item) {
|
return [
|
{ label: "模式", value: this.orDash(item.mode) },
|
{ label: "异常码", value: this.orDash(item.warnCode) },
|
{ label: "工位1任务号", value: this.orDash(item.taskNo) },
|
{ label: "工位2任务号", value: this.orDash(item.taskNoTwo) },
|
{ label: "设备工位1任务号", value: this.orDash(item.deviceTaskNo) },
|
{ label: "设备工位2任务号", value: this.orDash(item.deviceTaskNoTwo) },
|
{ label: "工位1状态", value: this.orDash(item.status) },
|
{ label: "工位2状态", value: this.orDash(item.statusTwo) },
|
{ label: "工位1是否有物", value: MonitorCardKit.yesNo(item.loading) },
|
{ label: "工位2是否有物", value: MonitorCardKit.yesNo(item.loadingTwo) },
|
{ label: "工位1货叉定位", value: this.orDash(item.forkOffset) },
|
{ label: "工位2货叉定位", value: this.orDash(item.forkOffsetTwo) },
|
{ label: "工位1任务接收", value: this.orDash(item.taskReceive) },
|
{ label: "工位2任务接收", value: this.orDash(item.taskReceiveTwo) },
|
{ label: "工位1下发数据", value: this.orDash(item.taskSend) },
|
{ label: "工位2下发数据", value: this.orDash(item.taskSendTwo) },
|
{ label: "列", value: this.orDash(item.bay) },
|
{ label: "层", value: this.orDash(item.lev) },
|
{ label: "载货台定位", value: this.orDash(item.liftPos) },
|
{ label: "走行定位", value: this.orDash(item.walkPos) },
|
{ label: "走行速度", value: this.orDash(item.xspeed) },
|
{ label: "升降速度", value: this.orDash(item.yspeed) },
|
{ label: "叉牙速度", value: this.orDash(item.zspeed) },
|
{ label: "扩展数据", value: this.orDash(item.extend) }
|
];
|
},
|
postControl: function (url, payload) {
|
$.ajax({
|
url: baseUrl + url,
|
headers: {
|
token: localStorage.getItem("token")
|
},
|
contentType: "application/json",
|
method: "post",
|
data: JSON.stringify(payload),
|
success: function (res) {
|
if (res && res.code === 200) {
|
MonitorCardKit.showMessage(this, res.msg || "操作成功", "success");
|
} else {
|
MonitorCardKit.showMessage(this, (res && res.msg) || "操作失败", "warning");
|
}
|
}.bind(this)
|
});
|
},
|
editTaskNo: function (item, station) {
|
var currentValue = station === 1 ? item.taskNo : item.taskNoTwo;
|
this.$prompt("请输入工位" + station + "任务号", "编辑任务号", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
inputValue: currentValue == null ? "" : String(currentValue),
|
inputPattern: /^\d+$/,
|
inputErrorMessage: "任务号必须是非负整数"
|
}).then(function (result) {
|
$.ajax({
|
url: baseUrl + "/dualcrn/command/updateTaskNo",
|
headers: {
|
token: localStorage.getItem("token")
|
},
|
contentType: "application/json",
|
method: "post",
|
data: JSON.stringify({
|
crnNo: item.crnNo,
|
station: station,
|
taskNo: Number(result.value)
|
}),
|
success: function (res) {
|
if (res && res.code === 200) {
|
MonitorCardKit.showMessage(this, "任务号更新成功", "success");
|
} else {
|
MonitorCardKit.showMessage(this, (res && res.msg) || "任务号更新失败", "warning");
|
}
|
}.bind(this)
|
});
|
}.bind(this)).catch(function () {});
|
},
|
controlCommandTransport: function () {
|
this.postControl("/dualcrn/command/take", this.controlParam);
|
},
|
controlCommandPickup: function () {
|
this.postControl("/dualcrn/command/pick", this.controlParam);
|
},
|
controlCommandPutdown: function () {
|
this.postControl("/dualcrn/command/put", this.controlParam);
|
},
|
controlCommandMove: function () {
|
this.postControl("/dualcrn/command/move", this.controlParam);
|
},
|
controlCommandTaskComplete: function () {
|
this.postControl("/dualcrn/command/taskComplete", this.controlParam);
|
}
|
}
|
});
|