Files
EdgeManager/src/views/edgeServer/edgeServerConfigure/device.vue

664 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-container>
<el-aside width="15%">
<div class="menu-box">
<el-card class="box-card">
<div slot="header" class="menu-header">
<div class="header-title">设备</div>
<el-dropdown size="small" style="vertical-align: middle;" @command="handleCommand">
<el-button type="primary" round>
<i class="el-icon-s-tools" style="font-size:14px;"></i><i class="el-icon-arrow-down el-icon--right"
style="font-size:14px;"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="add">新加设备</el-dropdown-item>
<el-dropdown-item command="del">删除设备</el-dropdown-item>
<el-dropdown-item>设备重启</el-dropdown-item>
<el-dropdown-item>导入配置</el-dropdown-item>
<el-dropdown-item>导出配置</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<el-menu :style="{ 'borderRight': 'none' }" :defaultActive="deviceActiveStatus" @select="getDeviceConfigure">
<el-menu-item class="serve-item" shadow="always" v-for="(item, i) in deviceData" :key="i" :index="i + ''">
<div style="position:relative;">
<div style="display:inline-block;">{{ item.name }}</div>
<div
:class="{ 'device-status': true, 'device-status-online': item.status, 'device-status-offline': !item.status }">
</div>
</div>
</el-menu-item>
</el-menu>
</el-card>
</div>
</el-aside>
<el-main :style="{ padding: '10px' }">
<el-card class="box-card">
<div slot="header" style=" position: relative;">
<div class="header-title">设备配置</div>
<el-button class="header-button" type="primary" @click="setDeviceConfigure">应用</el-button>
</div>
<device-configure ref="deviceConfigure" :defaultDeviceName="defaultDeviceName"
:defaultFormData="defaultFormData" />
</el-card>
<el-card class="box-card" style="margin-top:5px;">
<d2-crud ref="d2Crud" :columns="columns" :data="devicePointData" :rowHandle="rowHandle" add-title="新增"
edit-title="绑定" :add-template="addTemplate" :add-rules="addRules" :form-options="formOptions"
@row-add="addDevicePoint" @row-edit="devicePointBandingNode" @row-remove="delDevicePoint"
@dialog-cancel="handleDialogCancel" @banding="bandingNodeTemplate" @cell-data-change="handleCellDataChange"
@form-data-change="handleFormDataChange">
<el-button slot="header" style="margin-bottom: 5px" @click="addRow">新增</el-button>
</d2-crud>
</el-card>
</el-main>
</el-container>
</template>
<script>
import { each, assign, unset, filter, isArray, map } from 'lodash'
export default {
props: {
server: {
default: {
id: 0,
url: '',
port: ''
}
}
},
components: {
DeviceConfigure: () => import('./deviceConfigure')
},
data () {
return {
active: '',
columns: [
{
title: '序号',
key: 'id'
},
{
title: '名称',
key: '@Name',
component: {
size: 'small'
}
},
{
title: '绑定',
key: '@Binding'
},
{
title: '地址',
key: '@Address',
component: {
name: 'el-input',
size: 'small'
}
},
{
title: '类型',
key: '@DataTypeCode',
component: {
name: 'el-select',
size: 'small',
options: [
{
value: 'string',
label: 'string (字符串)'
},
{
value: 'int',
label: 'int (整数)'
},
{
value: 'float',
label: 'float (浮点数)'
},
{
value: 'bool',
label: 'bool (逻辑值)'
}
]
}
},
{
title: '采集周期',
key: '@RequestInterval',
component: {
name: 'el-input',
size: 'small'
}
},
{
title: '长度',
key: '@Length',
component: {
name: 'el-input',
size: 'small'
}
},
{
title: '说明',
key: '@Description',
component: {
name: 'el-input',
size: 'small'
}
},
{
title: '当前值',
key: '@Value',
component: {
name: 'el-input',
size: 'small'
}
}
],
rowHandle: {
minWidth: '200',
custom: [
{
text: '绑定',
size: 'mini',
emit: 'banding',
show (index, row) {
if (row.showBindButton) {
return true
}
return false
}
},
{
text: '发送',
size: 'mini',
show (index, row) {
if (row.showSendButton) {
return true
}
return false
}
},
{
text: '复制',
size: 'mini',
show (index, row) {
if (row.showCopyButton) {
return true
}
return false
}
}
],
remove: {
size: 'mini',
confirm: true,
show (index, row) {
if (row.showRemoveButton) {
return true
}
return false
}
}
},
formOptions: {
modal: false,
saveLoading: false,
showOverflowTooltip: true
},
addTemplate: {
'@Name': {
title: '名称'
},
'@Address': {
title: '地址'
},
'@DisplayName': {
title: '显示名称'
},
'@RequestType': {
title: '请求类型'
},
'@DataTypeCode': {
title: '数据类型',
component: {
name: 'el-select',
options: [
{
value: 'string',
label: 'string (字符串)'
},
{
value: 'int',
label: 'int (整数)'
},
{
value: 'float',
label: 'float (浮点数)'
},
{
value: 'bool',
label: 'bool (逻辑值)'
}
],
span: 12
}
},
'@RequestInterval': {
title: '采集周期(ms)'
},
'@Length': {
title: '长度'
},
'@Description': {
title: '说明'
},
'@Value': {
title: '当前值'
}
},
addRules: {
'@Name': [{ required: true, type: 'string', message: '请输入名称', trigger: 'blur' }],
'@Address': [{ required: true, type: 'string', message: '请输入地址', trigger: 'blur' }],
'@DisplayName': [{ required: true, type: 'string', message: '请输入显示名称', trigger: 'blur' }],
'@RequestType': [{ required: true, type: 'string', message: '请输入请求类型', trigger: 'blur' }],
'@DataTypeCode': [{ required: true, type: 'string', message: '请选择类型', trigger: 'blur' }],
'@RequestInterval': [{ required: true, message: '请输入采集周期(ms)', trigger: 'blur' }]
},
serverData: {},
devicePointData: [],
nodeCodeData: [],
workingSubclasses: [],
dialogVisible: false,
deviceActiveStatus: '0',
defaultDeviceName: '',
defaultFormData: {},
deviceData: [],
deviceConfigure: {}
}
},
watch: {
server: {
handler (val) {
this.serverData = val
this.getDevice()
if (val.id) {
this.getDeviceStatus()
}
},
immediate: true
}
},
methods: {
addRow () {
this.$refs.d2Crud.showDialog({
mode: 'add'
})
},
handleFormDataChange ({ key }) {
if (key === 'workingSubclass') {
const { workingSubclass } = this.$refs.d2Crud.formData
this.getCodesByWorkingSubclass(workingSubclass)
this.$refs.d2Crud.$forceUpdate()
}
},
handleCellDataChange ({ rowIndex, row }) {
this.devicePointData[rowIndex] = row
},
bandingNodeTemplate ({ index }) {
this.$refs.d2Crud.showDialog({
mode: 'edit',
rowIndex: index,
template: {
workingSubclass: {
title: '工序编码',
value: '',
component: {
name: 'el-select',
options: this.workingSubclasses,
span: 12
}
},
nodeCode: {
title: '节点名称',
value: '',
component: {
name: 'el-select',
options: this.nodeCodeData,
span: 12
}
}
}
})
},
handleDialogCancel (done) {
this.$message({
message: '用户取消保存',
type: 'warning'
})
done()
},
handleCommand (command) {
switch (command) {
case 'add':
this.addDevice()
break
case 'del':
this.delDevice()
break
}
},
async getCodesByWorkingSubclass (workingSubclass) {
try {
const nodeCode = await this.$api.QUERY_CODES(workingSubclass)
const nodeCodeData = []
each(nodeCode, (o) => {
nodeCodeData.push({ value: o, label: o })
}
)
this.nodeCodeData = nodeCodeData
this.$nextTick(() => {
this.$refs.d2Crud.handleFormTemplateMode('nodeCode').component.options = this.nodeCodeData
this.$refs.d2Crud.$forceUpdate()
})
} catch (e) {
console.log(e)
}
},
async getworkingSubclasses () {
try {
const workingSubclasses = await this.$api.QUERY_WORKING_SUBCLASSES()
const workingSubclassesData = []
each(workingSubclasses, (o) => {
workingSubclassesData.push({ value: o, label: o })
}
)
this.workingSubclasses = workingSubclassesData
} catch (e) {
console.log(e)
}
},
async getDevice () {
try {
this.deviceData = await this.$api.GET_DEVICE(this.serverData.id)
if (this.deviceData.length > 0) {
this.getDeviceConfigure(this.deviceActiveStatus)
} else {
this.devicePointData = [] // 如果没有设备,防止显示上一次打开的设备数据先清空数据
this.defaultDeviceName = ''
}
} catch (e) {
console.log(e)
}
},
async getDeviceConfigure (e) {
this.deviceActiveStatus = e
this.devicePointData = [] // 当切换设备时把保存configure、point的数据清空
this.defaultDeviceName = ''
const deviceData = await this.$api.GET_DEVICE_CONFIGURE(this.deviceData[e].id)
if (deviceData[0].conf) {
const conf = JSON.parse(deviceData[0].conf)
if (conf.DeviceTypeName !== undefined) {
this.defaultDeviceName = conf.DeviceTypeName
this.defaultFormData = conf
}
// 获取point信息
if (conf.RequestNode !== undefined && conf.RequestNode.length > 0) {
this.devicePointData = each(conf.RequestNode, (o, i) => (
assign(o, {
id: i + 1,
showBindButton: true,
showSendButton: true,
showCopyButton: true,
showRemoveButton: true
})
))
}
}
},
addDevice () {
this.$prompt('输入设备名称', '新加设备', {
confirmButtonText: '确定',
inputPattern: /^[\s\S]*.*[^\s][\s\S]*$/,
inputErrorMessage: '请输入设备名称'
}).then(({ value }) => {
this.$api.ADD_DEVICE({ action: 'add_device', name: value, server_id: this.serverData.id })
this.getDevice()
this.$message({
message: '新加设备成功',
type: 'success'
})
})
},
async delDevice () {
const deviceConfigure = await this.$api.GET_HSLSERVER_CONFIGURE('http://' + this.serverData.url + ':' + this.serverData.port, 'admin', process.env.VUE_APP_HSLSERVER_PASSWORD)
let deviceNode = deviceConfigure.Content.Settings.GroupNode[0].DeviceNode
if (deviceNode !== undefined && isArray(deviceNode)) {
deviceNode = filter(deviceNode, item => {
return item['@Name'] === this.deviceData[this.deviceActiveStatus].name ? null : item
})
deviceConfigure.Content.Settings.GroupNode[0].DeviceNode = deviceNode
} else {
unset(deviceConfigure, 'Content.Settings.GroupNode[0].DeviceNode')
}
try {
await this.$api.SET_HSLSERVER_CONFIGURE('http://' + this.serverData.url + ':' + this.serverData.port, 'admin', process.env.VUE_APP_HSLSERVER_PASSWORD, { data: deviceConfigure.Content })
await this.$api.DEL_DEVICE({ action: 'remove_device', id: this.deviceData[this.deviceActiveStatus].id })
this.$message({
message: '删除设备成功',
type: 'success'
})
this.getDevice()
} catch (e) {
console.log(e)
}
},
async addDevicePoint (row, done) {
this.formOptions.saveLoading = true
if (!this.$refs.deviceConfigure.defaultDeviceTypeNameValue) {
this.$message({
message: '请先应用设备配置',
type: 'error'
})
done(false)
} else {
if (row['@DataTypeCode'] === 'string' && !row['@Length']) {
this.$message({
message: '数据类型为string长度不能为空',
type: 'error'
})
this.formOptions.saveLoading = false
return false
}
assign(row, { id: this.devicePointData.length + 1, showBindButton: true, showCopyButton: true, showRemoveButton: true, showSendButton: true })
this.devicePointData.push(row)
done()
}
this.formOptions.saveLoading = false
},
async delDevicePoint ({ index, row }, done) {
this.$delete(this.devicePointData, index)
done()
},
async getDevicePoint () {
const data = { action: 'add_node', server_id: this.serverData.id, device_id: this.deviceData[this.deviceActiveStatus].id }
try {
this.devicePointData = await this.$api.GET_DEVICE_POINT(data)
} catch (e) {
console.log(e)
}
},
async devicePointBandingNode ({ index, row }, done) {
this.$set(this.devicePointData[index], '@Binding', row.nodeCode)
done()
},
async setDeviceConfigure () {
try {
// 验证表单
this.$refs.deviceConfigure.$refs.form.validate((valid) => {
if (!valid) {
return false
}
})
const deviceConfigure = await this.$api.GET_HSLSERVER_CONFIGURE('http://' + this.serverData.url + ':' + this.serverData.port, 'admin', process.env.VUE_APP_HSLSERVER_PASSWORD)
const deviceConfigureModelValue = this.$refs.deviceConfigure.deviceConfigureModelValue
if (this.devicePointData.length > 0) {
let devicePointData = this.devicePointData
devicePointData = each(devicePointData, (item) => {
if (item['@DataTypeCode'] !== 'string') {
unset(item, '@Length')
}
unset(item, 'id')
unset(item, 'showBindButton')
unset(item, 'showCopyButton')
unset(item, 'showRemoveButton')
unset(item, 'showSendButton')
item['@Binding'] = item['@Binding'] || ''
})
deviceConfigureModelValue.RequestNode = devicePointData
}
deviceConfigureModelValue['@Name'] = this.deviceData[this.deviceActiveStatus].name
let deviceNode = deviceConfigure.Content.Settings.GroupNode[0].DeviceNode || []
let isExist = false
if (deviceNode !== undefined) {
deviceNode = isArray(deviceNode) ? deviceNode : [deviceNode]
deviceNode = map(deviceNode, (item) => {
if (item['@Name'] === this.deviceData[this.deviceActiveStatus].name) {
isExist = true
item = deviceConfigureModelValue
}
return item
})
}
if (!isExist) {
deviceNode.push(deviceConfigureModelValue)
}
deviceConfigure.Content.Settings.GroupNode[0].DeviceNode = deviceNode
await this.$api.SET_HSLSERVER_CONFIGURE('http://' + this.serverData.url + ':' + this.serverData.port, 'admin', process.env.VUE_APP_HSLSERVER_PASSWORD, { data: deviceConfigure.Content })
deviceConfigureModelValue.DeviceTypeName = this.$refs.deviceConfigure.defaultDeviceTypeNameValue
const data = {
action: 'update_device',
conf: JSON.stringify(deviceConfigureModelValue),
id: this.deviceData[this.deviceActiveStatus].id
}
this.$api.SET_DEVICE_CONFIGURE(data)
this.$message({
message: '操作成功',
type: 'success'
})
this.$emit('changeServerConfig', 't')
} catch (e) {
console.log(e)
}
},
async getDeviceStatus () {
const res = await this.$api.GET_SERVER_DEVICE_STATUS('http://' + this.serverData.url + ':' + this.serverData.port, 'admin', process.env.VUE_APP_HSLSERVER_PASSWORD)
if (res) {
this.$emit('changeStatus', 'online')
const deviceStatus = {}
each(res.Content.__deviceList, (item) => {
deviceStatus[item.__name] = {
status: item.__requestEnable,
name: item.__name
}
})
each(this.deviceData, (item) => {
if (deviceStatus[item.name]) {
item.status = deviceStatus[item.name].status
}
})
} else {
this.$emit('changeStatus', false)
}
}
},
mounted () {
this.getDevice()
this.getworkingSubclasses()
this.getDeviceStatus()
}
}
</script>
<style scoped>
.menu-box {
box-sizing: border-box;
padding: 10px;
vertical-align: middle;
}
.el-dropdown {
vertical-align: top;
}
.el-dropdown+.el-dropdown {
margin-left: 15px;
}
.el-icon-arrow-down {
font-size: 12px;
}
.menu-header {
position: relative;
}
.header-title {
width: 60%;
display: inline-block;
font-weight: bold;
font-size: 20px;
color: black;
vertical-align: middle;
}
.header-button {
float: right;
vertical-align: middle;
}
.serve-item {
border: none;
margin-bottom: 10px;
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
overflow: hidden;
outline: 0;
border-radius: 4px;
}
.device-status {
width: 10px;
height: 10px;
border-radius: 50%;
right: 0;
position: absolute;
top: 50%;
transform: translate(0, -50%);
}
.device-status-online {
background-color: #67c23a;
}
.device-status-offline {
background-color: #ccc;
}
</style>