<template>
|
<div class="autoTest">
|
|
<!-- 菜单栏 strat -->
|
<div class="menu">
|
<div class="menu-left">
|
<div class="menu-left-name">自动化测试</div>
|
<div class="menu-left-triangle"></div>
|
</div>
|
<div class="menu-right">
|
<div class="link menu-right-item" @click="onGetProductList">选择产品型号</div>
|
<div class="link menu-right-item" v-if="!showLeft" @click="showLeft = true">显示预置指令</div>
|
<div class="link menu-right-item" v-if="showLeft" @click="showLeft = false">隐藏预置指令</div>
|
<div class="link menu-right-item" @click="onFinishWork()">结束工作</div>
|
</div>
|
</div>
|
<!-- 菜单栏 end -->
|
|
<!-- 内容 strat -->
|
<div class="content">
|
<transition name="slide-fade">
|
<div class="left" v-if="showLeft">
|
<div class="title">
|
<span>预置指令</span>
|
<div class="title-slot">
|
<button @click="type = '1'" :class="'title-button link ' + (type == '1' ? 'actived' : '')">测试指令</button>
|
<button @click="type = '2'" :class="'title-button link ' + (type == '2' ? 'actived' : '')">设置指令</button>
|
</div>
|
</div>
|
<div class="content scrollList">
|
<div class="list-item" v-for="item, index in commandList" :key="index">
|
<span class="pro text" :title="`${item.proName}(${item.proType})`">{{ item.proName }}({{ item.proType
|
}})</span>
|
<span class="name text" :title="item.name">{{ item.name }}</span>
|
<span class="value text" :title="item.value">{{ item.value }}</span>
|
<button class="action link" @click="inputValue = item.value"><i class="iconfont icon-shuru" /> 输入</button>
|
<button class="action link" :disabled="!connStatus" @click="sendMessage(item.value)"><i class="iconfont icon-fasong" /> 发送</button>
|
</div>
|
</div>
|
</div>
|
</transition>
|
<div class="right">
|
<div class="title">
|
<span>串口通信已连接</span>
|
<span :class="'connStatus ' + (connStatus ? 'connected' : 'blink disConnected')"></span>
|
<div class="title-slot">
|
<button v-if="!connStatus" @click="setWebSocketConn" class="title-button link"><i
|
class="iconfont icon-lianjie" />
|
连接串口通信</button>
|
<button v-if="connStatus" @click="closeWebSocketConn" class="title-button link"><i
|
class="iconfont icon-lianjie" />
|
断开串口通信</button>
|
<button @click="messageList = []" class="title-button link"><i class="iconfont icon-qingkong" />
|
清空通信记录</button>
|
</div>
|
</div>
|
<div class="messageList scrollList" id="messages">
|
<div v-for="item, index in messageList" :key="index" :class="`messageItem ${item.type}`">
|
<span class="name" v-if="item.type == 'receive'">收</span>
|
<span :class="`content ${item.type}`">{{ item.content }}</span>
|
<span class="name" v-if="item.type == 'send'">发</span>
|
</div>
|
</div>
|
<div class="sendBox">
|
<input v-model="inputValue" placeholder="请输入指令"></input>
|
<button class="send link" :disabled="!connStatus" @click="sendInputMessage"><i class="iconfont icon-fasong" /> 发送</button>
|
<button class="clear link" @click="inputValue = null"><i class="iconfont icon-qingkong" /> 清空</button>
|
</div>
|
</div>
|
</div>
|
<!-- 内容 end -->
|
|
|
<!-- 产品型号列表 strat -->
|
<Dialog :visible="showProductList">
|
<div class="product-list">
|
<div class="close link" @click="showProductList = false"><i class="close iconfont icon-shanchu" /></div>
|
<div class="title">选择产品型号</div>
|
<div class="product-list-wrap scrollList">
|
<div class="product-list-item" v-for="item, index in productList" :key="index">
|
<span class="name">{{ item.name }}</span>
|
<span class="type">{{ item.type }}</span>
|
<span class="action link" @click="onSelectProduct(item)">选择</span>
|
</div>
|
</div>
|
</div>
|
</Dialog>
|
<!-- 产品型号列表 end -->
|
</div>
|
</template>
|
|
<script>
|
import Dialog from '../components/Dialog.vue'
|
|
export default {
|
name: "autoTest",
|
components: {
|
Dialog,
|
},
|
data() {
|
return {
|
isAlert: false, // 确认框状态
|
showLeft: true,
|
type: null,
|
showProductList: false,
|
productList: [],
|
connStatus: false,
|
productId: null,
|
productName: null,
|
productType: null,
|
commandList: [],
|
messageList: [],
|
inputValue: null,
|
|
}
|
},
|
computed: {
|
|
},
|
watch: {
|
productId: function (newVal, oldVal) {
|
this.onGetCommandList()
|
},
|
type: function (newVal, oldVal) {
|
this.onGetCommandList()
|
},
|
messageList: {
|
deep: true,
|
handler: function (newVal, oldVal) {
|
setTimeout(() => {
|
var div = document.getElementById('messages')
|
div.scrollTop = div.scrollHeight
|
}, 100)
|
}
|
}
|
},
|
mounted() {
|
// 恢复登录态
|
this.onGetLoginInfo()
|
// 切换指令类型
|
this.type = '1'
|
// 链接网串中间件
|
this.setWebSocketConn()
|
// 通过事件总线接收扫描结果
|
this.$bus.$off('scanResult')
|
this.$bus.$on('scanResult', (val) => {
|
console.log('[repair] 总线接收 =>', val)
|
this.handleScanVal(val)
|
})
|
// 通过事件总线接收弹窗状态
|
this.$bus.$off('isAlert')
|
this.$bus.$on('isAlert', (val) => {
|
this.isAlert = val
|
})
|
},
|
beforeDestroy() {
|
this.$bus.$off('isAlert')
|
this.$bus.$off('scanResult')
|
},
|
methods: {
|
// 获取登录信息
|
onGetLoginInfo() {
|
var that = this;
|
var params = {
|
workId: localStorage.getItem("workId"),
|
};
|
that
|
.$axiosAdmin({
|
method: "get",
|
url: "station/workOrder/getWorkLast",
|
params: params,
|
})
|
.then((res) => {
|
if (res.success && res.content.workType == 6) {
|
} else {
|
localStorage.clear()
|
this.goto('start')
|
}
|
})
|
.catch((err) => {
|
console.log(err);
|
});
|
},
|
// 跳转路由
|
goto: function (path) {
|
if (path != this.$route.name) {
|
this.$router.push({
|
name: path,
|
});
|
}
|
},
|
// 扫码结果处理
|
handleScanVal: function (val) {
|
console.log('[repair] 扫码处理 =>', val)
|
if (this.isAlert) {
|
return
|
}
|
// 扫码注销
|
if (val == '102007') {
|
this.$alert.close()
|
this.onFinishWork()
|
return
|
}
|
// 扫码提交
|
if (val == '102001' || val == '102006') {
|
if (this.activeTab == 0) {
|
this.handleSubmit(val)
|
}
|
return
|
}
|
// 扫码取消
|
if (val == '102002') {
|
if (this.activeTab == 0) {
|
this.handleCancel(val)
|
}
|
return
|
}
|
// 进入工作台
|
if (this.activeTab == 0) {
|
this.onGetDeviceInfo(0, val)
|
return
|
}
|
// 进入作业人员
|
if (this.activeTab == 1) {
|
if (val.substr(0, 3) == '101') {
|
this.handleAddPeople(val)
|
} else {
|
this.$notify({
|
title: '添加失败',
|
message: '请扫描正确的人员二维码。',
|
type: 'error'
|
})
|
return
|
}
|
return
|
}
|
},
|
// 结束工作
|
onFinishWork: function () {
|
var that = this;
|
this.$alert.show({
|
modelTitle: "结束工作",
|
modelContent: '确认后将退出工作状态,是否结束当前工作?',
|
callBack: () => {
|
that
|
.$axiosAdmin({
|
method: "post",
|
url: "station/workOrder/logout",
|
params: {
|
workId: localStorage.getItem('workId'),
|
},
|
})
|
.then((res) => {
|
if (res.success == true) {
|
this.$notify({
|
title: '结束工作成功',
|
message: `已退出工作台,请重新认领工作任务。`,
|
type: 'success'
|
})
|
this.goto('start')
|
localStorage.clear()
|
} else {
|
this.$notify({
|
title: '结束工作失败',
|
message: res.content,
|
type: 'error'
|
})
|
}
|
})
|
.catch((err) => {
|
console.log(err);
|
});
|
},
|
cancleBack: () => {
|
this.$alert.close()
|
this.$bus.$off('scanResult')
|
this.$bus.$on('scanResult', (val) => {
|
console.log('[repair] 总线接收 =>', val)
|
this.handleScanVal(val)
|
})
|
}
|
})
|
},
|
// 获取产品列表
|
onGetProductList: function () {
|
var that = this;
|
that
|
.$axiosAdmin({
|
method: "get",
|
url: "station/assemblyStep/all",
|
})
|
.then((res) => {
|
if (res.success == true) {
|
that.productList = res.content;
|
that.showProductList = true
|
}
|
})
|
.catch((err) => {
|
console.log(err);
|
});
|
},
|
// 选择产品
|
onSelectProduct: function (item) {
|
this.productId = item.id
|
this.productName = item.name
|
this.productType = item.type
|
this.showProductList = false
|
},
|
// 获取产品预置指令
|
onGetCommandList: function () {
|
var that = this;
|
this.commandList = []
|
that
|
.$axiosAdmin({
|
method: "get",
|
url: "station/assemblyStep/getCommand",
|
params: {
|
proId: this.productId,
|
type: this.type,
|
},
|
})
|
.then((res) => {
|
if (res.success == true) {
|
that.commandList = JSON.parse(JSON.stringify(res.content));
|
}
|
})
|
.catch((err) => {
|
console.log(err);
|
});
|
},
|
// 创建网串中间件连接
|
setWebSocketConn: function () {
|
var that = this;
|
if ('WebSocket' in window) {
|
this.webSocketConn = new WebSocket('ws://localhost:65532')
|
this.webSocketConn.onopen = function () {
|
that.connStatus = true
|
that.messageList.push({
|
type: 'system',
|
content: '网串中间件已连接'
|
},)
|
}
|
this.webSocketConn.onmessage = function (evt) {
|
that.messageList.push({
|
type: 'receive',
|
content: evt.data
|
},)
|
}
|
this.webSocketConn.onclose = function () {
|
that.connStatus = false
|
that.messageList.push({
|
type: 'system',
|
content: '网串中间件已断开'
|
},)
|
if (that.sending) {
|
that.sending = false
|
that.messageList.push({
|
type: 'system',
|
content: '已停止队列发送'
|
},)
|
}
|
}
|
this.webSocketConn.onerror = function () {
|
that.messageList.push({
|
type: 'system',
|
content: '网串中间件连接异常'
|
},)
|
}
|
} else {
|
this.$alert('当前浏览器不支持websocket连接', "提示", {
|
confirmButtonText: "确定",
|
});
|
}
|
},
|
// 断开网串中间件连接
|
closeWebSocketConn: function () {
|
this.webSocketConn.close()
|
},
|
// 清空通信记录
|
clearMessageList: function () {
|
this.messageList.splice(0, this.messageList.length)
|
},
|
// 发送指令输入框内容
|
sendInputMessage: function () {
|
var that = this;
|
if (this.inputValue) {
|
this.webSocketConn.send(this.inputValue)
|
this.messageList.push({
|
type: 'send',
|
content: this.inputValue
|
},)
|
// this.inputValue = null
|
} else {
|
this.$alert('请输入指令内容', "提示", {
|
confirmButtonText: "确定",
|
})
|
}
|
},
|
// 发送指令
|
sendMessage: function (message) {
|
var that = this;
|
this.webSocketConn.send(message)
|
this.messageList.push({
|
type: 'send',
|
content: message
|
},)
|
},
|
},
|
destroyed() {
|
this.closeWebSocketConn()
|
}
|
};
|
</script>
|
|
<style lang="less" scope>
|
.autoTest {
|
height: 100%;
|
display: flex;
|
flex-direction: column;
|
overflow: hidden;
|
|
// 主菜单
|
.menu {
|
border-bottom: 1px solid #0089ff;
|
display: flex;
|
justify-content: space-between;
|
margin-bottom: 30px;
|
|
// 主菜单左侧标题栏
|
.menu-left {
|
display: flex;
|
|
.menu-left-name {
|
padding: 0 20px 0 30px;
|
border-radius: 10px 0 0 0;
|
height: 40px;
|
line-height: 40px;
|
background-color: #0089ff;
|
font-size: 20px;
|
}
|
|
.menu-left-triangle {
|
margin-left: -1px;
|
width: 30px;
|
height: 40px;
|
background: linear-gradient(60deg, #0089ff 50%, transparent 50%, transparent 100%);
|
}
|
}
|
|
// 主菜单右侧按钮栏
|
.menu-right {
|
display: flex;
|
|
// 主菜单右侧按钮栏按钮
|
.menu-right-item {
|
margin-left: 15px;
|
padding: 0 15px;
|
border-radius: 10px 10px 0 0;
|
height: 40px;
|
line-height: 40px;
|
background-color: #0089ff;
|
font-size: 20px;
|
}
|
}
|
}
|
|
// 主内容
|
.content {
|
flex-grow: 1;
|
display: flex;
|
justify-content: space-between;
|
|
.left {
|
background-color: #003366;
|
// width: 915px; // 一半宽度
|
width: 1200px;
|
margin-right: 30px;
|
border-radius: 10px;
|
overflow: hidden;
|
|
.content {
|
height: 792px;
|
display: block;
|
|
.list-item {
|
display: flex;
|
justify-content: flex-start;
|
align-items: center;
|
width: 100%;
|
height: 60px;
|
border-bottom: 1px solid #002244;
|
box-sizing: border-box;
|
padding: 0 30px;
|
font-size: 20px;
|
|
.name,
|
.pro {
|
width: 300px;
|
}
|
|
.value {
|
flex-grow: 1;
|
font-weight: 700;
|
}
|
|
.action {
|
display: block;
|
width: 104px;
|
height: 40px;
|
line-height: 40px;
|
text-align: center;
|
border-radius: 10px;
|
font-size: 16px;
|
font-weight: normal;
|
background-color: #002244;
|
color: #fff;
|
margin-right: 10px;
|
border: none;
|
outline: none;
|
}
|
|
.action:last-child {
|
margin-right: 0;
|
}
|
}
|
}
|
}
|
|
.right {
|
background-color: #003366;
|
flex-grow: 1;
|
border-radius: 10px;
|
display: flex;
|
flex-direction: column;
|
overflow: hidden;
|
|
.messageList {
|
height: 711px;
|
display: block;
|
|
.messageItem {
|
display: flex;
|
align-items: flex-start;
|
margin-bottom: 10px;
|
|
.content {
|
min-height: 40px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
border-radius: 5px;
|
max-width: 400px;
|
word-break: break-all;
|
overflow: hidden;
|
padding: 10px;
|
box-sizing: border-box;
|
}
|
|
.name {
|
display: inline-block;
|
width: 40px;
|
height: 40px;
|
line-height: 40px;
|
text-align: center;
|
margin: 0 10px;
|
font-size: 18px;
|
color: #fff;
|
border-radius: 5px;
|
background-color: #409eff;
|
}
|
|
.send {
|
background-color: #002244;
|
display: block;
|
text-align: left;
|
}
|
|
.receive {
|
display: block;
|
text-align: left;
|
background-color: #333;
|
}
|
}
|
|
.system {
|
justify-content: center;
|
color: #888;
|
font-size: 14px;
|
}
|
|
.send {
|
align-items: flex-start;
|
justify-content: flex-end;
|
}
|
|
.receive {
|
align-items: flex-start;
|
}
|
}
|
|
.sendBox {
|
height: 80px;
|
border-top: 1px solid #002244;
|
display: flex;
|
|
input {
|
flex-grow: 1;
|
border: none;
|
outline: none;
|
background-color: #003366;
|
padding: 0 20px;
|
font-size: 20px;
|
font-weight: 700;
|
color: #fff;
|
}
|
|
.send,
|
.clear {
|
width: 150px;
|
height: 80px;
|
line-height: 80px;
|
text-align: center;
|
font-size: 22px;
|
font-weight: 700;
|
color: #fff;
|
border: none;
|
outline: none;
|
background-color: #003366;
|
border-left: 1px solid #002244;
|
}
|
|
.send {
|
color: green;
|
}
|
|
.clear {
|
color: red;
|
}
|
}
|
}
|
|
.title {
|
text-align: left !important;
|
padding-left: 30px;
|
display: block;
|
font-size: 26px;
|
text-align: center;
|
height: 80px;
|
line-height: 80px;
|
border-bottom: 1px solid #002244;
|
box-sizing: border-box;
|
font-weight: 700;
|
position: relative;
|
|
.connStatus {
|
display: inline-block;
|
margin-left: 15px;
|
width: 15px;
|
height: 15px;
|
border-radius: 50%;
|
}
|
|
.connected {
|
background-color: #336666;
|
background-color: green;
|
}
|
|
.disConnected {
|
background-color: red;
|
}
|
|
.title-slot {
|
height: 80px;
|
position: absolute;
|
top: 0;
|
right: 20px;
|
display: flex;
|
align-items: center;
|
|
.title-button {
|
height: 40px;
|
line-height: 40px;
|
padding: 0 20px;
|
border-radius: 10px;
|
font-size: 16px;
|
font-weight: normal;
|
background-color: #002244;
|
color: #fff;
|
border: none;
|
outline: none;
|
margin-right: 10px;
|
}
|
|
.title-button:disabled {
|
background-color: #ccc;
|
cursor: not-allowed;
|
}
|
|
.actived {
|
background-color: #0089ff;
|
}
|
}
|
}
|
|
}
|
|
// 产品列表
|
.product-list {
|
width: 1150px;
|
height: 700px;
|
background-color: #003366;
|
position: relative;
|
|
.none {
|
width: 100%;
|
height: 450px;
|
line-height: 450px;
|
text-align: center;
|
font-size: 30px;
|
}
|
|
.title {
|
padding-left: 30px;
|
box-sizing: border-box;
|
font-size: 30px;
|
height: 80px;
|
line-height: 80px;
|
border-bottom: 1px solid #002244;
|
}
|
|
.close {
|
position: absolute;
|
display: block;
|
width: 80px;
|
height: 80px;
|
line-height: 80px;
|
text-align: center;
|
font-size: 30px;
|
right: 0;
|
top: 0;
|
color: #fff;
|
}
|
|
.product-list-wrap {
|
width: 100%;
|
height: 100%;
|
// background-color: red;
|
padding-bottom: 80px;
|
|
.product-list-item {
|
font-size: 24px;
|
height: 80px;
|
line-height: 80px;
|
border-bottom: 1px solid #002244;
|
box-sizing: border-box;
|
padding: 0 30px;
|
display: flex;
|
justify-content: space-between;
|
|
.name {
|
width: 500px;
|
}
|
|
.type {
|
width: 500px;
|
}
|
|
.action {
|
text-align: right;
|
width: 90px;
|
}
|
|
}
|
}
|
}
|
|
// 文字溢出隐藏加悬停提示
|
.text {
|
white-space: nowrap;
|
text-overflow: ellipsis;
|
overflow: hidden;
|
}
|
|
}
|
button:disabled {
|
color: #616161 !important;
|
cursor: not-allowed;
|
}
|
.scrollList {
|
overflow: scroll;
|
scrollbar-width: none;
|
/* Firefox */
|
-ms-overflow-style: none;
|
/* IE 10+ */
|
}
|
|
.scrollList::-webkit-scrollbar {
|
display: none;
|
/* Chrome Safari */
|
}
|
|
.slide-fade-enter-active {
|
transition: all .1s linear;
|
}
|
|
.slide-fade-leave-active {
|
transition: all .1s linear;
|
|
}
|
|
.slide-fade-enter,
|
.slide-fade-leave-to
|
|
/* .slide-fade-leave-active for below version 2.1.8 */
|
{
|
transform: translateX(-500px);
|
opacity: 0;
|
}
|
|
/* 定义keyframe动画,命名为blink */
|
@keyframes blink {
|
0% {
|
opacity: 1;
|
}
|
|
100% {
|
opacity: 0;
|
}
|
}
|
|
/* 添加兼容性前缀 */
|
@-webkit-keyframes blink {
|
0% {
|
opacity: 1;
|
}
|
|
100% {
|
opacity: 0;
|
}
|
}
|
|
@-moz-keyframes blink {
|
0% {
|
opacity: 1;
|
}
|
|
100% {
|
opacity: 0;
|
}
|
}
|
|
@-ms-keyframes blink {
|
0% {
|
opacity: 1;
|
}
|
|
100% {
|
opacity: 0;
|
}
|
}
|
|
@-o-keyframes blink {
|
0% {
|
opacity: 1;
|
}
|
|
100% {
|
opacity: 0;
|
}
|
}
|
|
/* 定义blink类*/
|
.blink {
|
color: red;
|
font-size: 46px;
|
animation: blink 1s linear infinite;
|
/* 其它浏览器兼容性前缀 */
|
-webkit-animation: blink 1s linear infinite;
|
-moz-animation: blink 1s linear infinite;
|
-ms-animation: blink 1s linear infinite;
|
-o-animation: blink 1s linear infinite;
|
}
|
</style>
|