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

922 lines
24 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="setDeviceConfigureConfirm"
>应用</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,
capitalize,
split,
toUpper,
} from "lodash";
export default {
props: {
server: {
default: {
id: 0,
url: "",
port: "",
},
},
},
components: {
DeviceConfigure: () => import("./deviceConfigure"),
},
data() {
return {
active: "",
timing:null,
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 (逻辑值)",
},
{
value: "uint",
label: "uint",
},
{
value: "short",
label: "short",
},
{
value: "ushort",
label: "ushort",
},
{
value: "long",
label: "long",
},
{
value: "ulong",
label: "ulong",
},
{
value: "double",
label: "double",
},
{
value: "byte",
label: "byte",
},
{
value: "sbyte",
label: "sbyte",
},
],
},
},
{
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 (逻辑值)",
},
{
value: "uint",
label: "uint",
},
{
value: "short",
label: "short",
},
{
value: "ushort",
label: "ushort",
},
{
value: "long",
label: "long",
},
{
value: "ulong",
label: "ulong",
},
{
value: "double",
label: "double",
},
{
value: "byte",
label: "byte",
},
{
value: "sbyte",
label: "sbyte",
},
],
span: 12,
},
},
"@RequestInterval": {
title: "采集周期(ms)",
},
"@Length": {
title: "长度",
},
"@Description": {
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, key, value }) {
let type = undefined;
if (row["@DataTypeCode"][0] === "u") {
type = split(row["@DataTypeCode"], "")
type[1] = toUpper(type[0] + type[1])
type = type.join("")
} else {
type = capitalize(row["@DataTypeCode"])
}
if (key === "@Value") {
this.$api.SET_DEVICE_POINT_VALUE(
"http://" + this.serverData.url + ":" + this.serverData.port,
this.deviceData[this.deviceActiveStatus].name,
row["@Address"],
type,
value
).then(res=>{
if(!res.IsSuccess){
this.$message({
message: res.Message,
type: "error",
});
}
})
}
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)
let 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 = ""
clearInterval(this.timing) //当切换设备时先关闭定时器,防止一直执行上一设备的定时器
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信息
let devicePointAddress = []
if (conf.RequestNode !== undefined && conf.RequestNode.length > 0) {
this.devicePointData = each(conf.RequestNode, (o, i) => {
let type = undefined;
if (o["@DataTypeCode"][0] === "u") {
type = split(o["@DataTypeCode"], "")
type[1] = toUpper(type[0] + type[1])
type = type.join("")
} else {
type = capitalize(o["@DataTypeCode"])
}
devicePointAddress.push({
key: i,
value: o["@Address"],
type:
o["@DataTypeCode"][0] === "u"
? replace(o["@DataTypeCode"])
: capitalize(o["@DataTypeCode"]),
})
assign(o, {
id: i + 1,
showBindButton: true,
showSendButton: true,
showCopyButton: true,
showRemoveButton: true,
});
});
if (devicePointAddress.length > 0) {
this.getDevicePoint(devicePointAddress);
}
}
}
},
addDevice() {
const that = this;
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,
});
that.getDevice();
this.$message({
message: "新加设备成功",
type: "success",
});
});
},
async delDevice() {
const deviceConfigure = await this.$api.GET_HSLSERVER_CONFIGURE(
"http://" + this.serverData.url + ":" + this.serverData.port,
);
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,
{ 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();
},
getDevicePoint(devicePointAddress) {
clearInterval(this.timing)
this.timing = setInterval(() => {
each(devicePointAddress, async (item) => {
try {
this.$api
.GET_DEVICE_POINT_VALUE(
"http://" + this.serverData.url + ":" + this.serverData.port,
this.deviceData[this.deviceActiveStatus].name,
item.value,
item.type
)
.then((res) => {
this.$set(
this.devicePointData[item.key],
"@Value",
res.Content
);
});
} catch (e) {
console.log(e);
}
});
}, 10000);
},
async devicePointBandingNode({ index, row }, done) {
this.$delete(this.devicePointData[index], "@Binding")
this.$set(this.devicePointData[index], "@Binding", row.nodeCode)
done();
},
setDeviceConfigureConfirm(){
this.$confirm('是否要应用该配置信息,更改配置后需要重启改服务才能使服务生效?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.setDeviceConfigure()
}).catch(() => {
this.$message({
type: 'info',
message: '已取消应用服务配置'
});
});
},
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
);
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");
unset(item, "@Value");
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,
{ 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
);
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);
}
},
clearTime(){
clearInterval(this.timing)
this.timing = null
}
},
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>