Files
fastbee/vue/src/views/iot/product/product-things-model.vue
2022-06-08 15:10:22 +08:00

605 lines
25 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>
<div style="padding-left:20px;">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-if="productInfo.status==1">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-plus" size="mini" @click="handleSelect" v-if="productInfo.status==1">导入通用物模型</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-plus" size="mini" @click="handleOpenThingsModel">查看物模型</el-button>
</el-col>
<el-col :span="1.5">
<el-link type="danger" style="padding-top:5px" :underline="false">注意标识符不能重复</el-link>
</el-col>
<right-toolbar @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="modelList" border>
<el-table-column label="名称" align="center" prop="modelName" />
<el-table-column label="标识符" align="center" prop="identifier" />
<el-table-column label="首页显示" align="center" prop="isTop" width="100">
<template slot-scope="scope">
<dict-tag :options="dict.type.iot_yes_no" :value="scope.row.isTop" />
</template>
</el-table-column>
<el-table-column label="实时监测" align="center" prop="isMonitor" width="100">
<template slot-scope="scope">
<dict-tag :options="dict.type.iot_yes_no" :value="scope.row.isMonitor" />
</template>
</el-table-column>
<el-table-column label="物模型类别" align="center" prop="type">
<template slot-scope="scope">
<dict-tag :options="dict.type.iot_things_type" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="数据类型" align="center" prop="datatype">
<template slot-scope="scope">
<dict-tag :options="dict.type.iot_data_type" :value="scope.row.datatype" />
</template>
</el-table-column>
<el-table-column label="数据定义" align="left" header-align="center" prop="specs" min-width="150" class-name="specsColor">
<template slot-scope="scope">
<div v-html="formatSpecsDisplay(scope.row.specs)"></div>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-if="productInfo.status!=2">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-if="productInfo.status!=2">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改物模型对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="模型名称" prop="modelName">
<el-input v-model="form.modelName" placeholder="请输入物模型名称,例如:温度" style="width:385px;" />
</el-form-item>
<el-form-item label="标识符" prop="identifier">
<el-input v-model="form.identifier" placeholder="请输入标识符例如temperature" style="width:385px;" />
</el-form-item>
<el-form-item label="模型类别" prop="type">
<el-radio-group v-model="form.type" @change="typeChange(form.type)">
<el-radio-button label="1">属性</el-radio-button>
<el-radio-button label="2">功能</el-radio-button>
<el-radio-button label="3">事件</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="首页显示" prop="isTop" v-show="form.type != 3">
<el-switch v-model="form.isTop" active-text="" inactive-text="" :active-value="1" :inactive-value="0" active-color="#13ce66">
</el-switch>
</el-form-item>
<el-form-item label="实时监测" prop="isMonitor" v-show="form.type == 1">
<el-switch v-model="form.isMonitor" active-text="" inactive-text="" :active-value="1" :inactive-value="0" active-color="#13ce66" @change="changeMonitor(form.isMonitor)">
</el-switch>
</el-form-item>
<el-divider></el-divider>
<el-form-item label="数据类型" prop="datatype">
<el-select v-model="form.datatype" placeholder="请选择数据类型" @change="dataTypeChange" style="width:175px;">
<el-option key="integer" label="整数" value="integer"></el-option>
<el-option key="decimal" label="小数" value="decimal"></el-option>
<el-option key="bool" label="布尔" value="bool" :disabled="form.isMonitor==1"></el-option>
<el-option key="enum" label="枚举" value="enum" :disabled="form.isMonitor==1"></el-option>
<el-option key="string" label="字符串" value="string" :disabled="form.isMonitor==1"></el-option>
<el-option key="array" label="数组" value="array" :disabled="form.isMonitor==1"></el-option>
</el-select>
</el-form-item>
<div v-if="form.datatype == 'integer' || form.datatype == 'decimal'">
<el-form-item label="取值范围">
<el-row>
<el-col :span="9">
<el-input v-model="form.specs.min" placeholder="最小值" type="number" />
</el-col>
<el-col :span="2" align="center"></el-col>
<el-col :span="9">
<el-input v-model="form.specs.max" placeholder="最大值" type="number" />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="单位">
<el-input v-model="form.specs.unit" placeholder="请输入单位,例如:℃" style="width:385px;" />
</el-form-item>
<el-form-item label="步长">
<el-input v-model="form.specs.step" placeholder="请输入步长例如1" type="number" style="width:385px;" />
</el-form-item>
</div>
<div v-if="form.datatype == 'bool'">
<el-form-item label="布尔值" prop="">
<el-row style="margin-bottom:10px;">
<el-col :span="9">
<el-input v-model="form.specs.falseText" placeholder="例如:关闭" />
</el-col>
<el-col :span="10" :offset="1"> 0 值对应文本</el-col>
</el-row>
<el-row>
<el-col :span="9">
<el-input v-model="form.specs.trueText" placeholder="例如:打开" />
</el-col>
<el-col :span="10" :offset="1"> 1 值对应文本</el-col>
</el-row>
</el-form-item>
</div>
<div v-if="form.datatype == 'enum'">
<el-form-item label="枚举项" prop="">
<el-row v-for="(item,index) in form.specs.enumList" :key="'enum'+index" style="margin-bottom:10px;">
<el-col :span="9">
<el-input v-model="item.value" placeholder="参数值例如0" type="number" />
</el-col>
<el-col :span="11" :offset="1">
<el-input v-model="item.text" placeholder="参数描述,例如:中速档位" />
</el-col>
<el-col :span="2" :offset="1" v-if="index!=0"><a style="color:#F56C6C" @click="removeEnumItem(index)">删除</a></el-col>
</el-row>
<div>+ <a style="color:#409EFF" @click="addEnumItem()">添加枚举项</a></div>
</el-form-item>
</div>
<div v-if="form.datatype == 'string'">
<el-form-item label="最大长度" prop="">
<el-row>
<el-col :span="9">
<el-input v-model="form.specs.maxLength" placeholder="例如1024" type="number"/>
</el-col>
<el-col :span="14" :offset="1">字符串的最大长度</el-col>
</el-row>
</el-form-item>
</div>
<div v-if="form.datatype == 'array'">
<el-form-item label="数组类型" prop="">
<el-radio-group v-model="form.specs.arrayType">
<el-radio label="int">int整数</el-radio>
<el-radio label="double">double小数</el-radio>
<el-radio label="string">string字符串</el-radio>
</el-radio-group>
</el-form-item>
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 导入通用物模型对话框 -->
<el-dialog :title="title" :visible.sync="openSelect" width="800px" append-to-body>
<product-select-template ref="productSelectTemplate" @idsToParentEvent="getChildData($event)" />
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="importSelect"> </el-button>
<el-button @click="cancelSelect"> </el-button>
</div>
</el-dialog>
<!-- 物模型JSON -->
<el-dialog :title="title" :visible.sync="openThingsModel" width="600px" append-to-body>
<div style="border:1px solid #ccc;margin-top:-15px;height:600px; overflow:scroll;">
<json-viewer :value="thingsModel" :expand-depth=10 copyable>
<template v-slot:copy>
复制
</template>
</json-viewer>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="info" @click="handleCloseThingsModel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<style>
.specsColor {
background-color: #fcfcfc;
}
</style>
<script>
import productSelectTemplate from "./product-select-template";
import JsonViewer from 'vue-json-viewer'
import 'vue-json-viewer/style.css'
import {
listModel,
getModel,
delModel,
addModel,
updateModel,
importModel
} from "@/api/iot/model";
export default {
name: "product-things-model",
dicts: ["iot_things_type", "iot_data_type", "iot_yes_no"],
components: {
productSelectTemplate,
JsonViewer
},
props: {
product: {
type: Object,
default: null
}
},
watch: {
// 获取到父组件传递的productId后刷新列表
product: function (newVal, oldVal) {
this.productInfo = newVal;
if (this.productInfo && this.productInfo.productId != 0) {
this.queryParams.productId = this.productInfo.productId;
this.getList();
}
}
},
data() {
return {
// 物模型
thingsModel: {},
// 父组件接收的产品信息
productInfo: {},
// 子组件选中的id数组
templateIds: [],
// 遮罩层
loading: false,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 产品物模型表格数据
modelList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
openSelect: false,
openThingsModel: false,
// 查询参数
queryParams: {
productId: 0,
},
// 表单参数
form: {},
// 表单校验
rules: {
modelName: [{
required: true,
message: "物模型名称不能为空",
trigger: "blur"
}],
identifier: [{
required: true,
message: "标识符,产品下唯一不能为空",
trigger: "blur",
}, ],
type: [{
required: true,
message: "模型类别不能为空",
trigger: "change"
}, ],
datatype: [{
required: true,
message: "数据类型不能为空",
trigger: "change"
}, ],
specs: [{
required: true,
message: "数据定义不能为空",
trigger: "blur"
}, ],
},
};
},
created() {
},
methods: {
/** 查询产品物模型列表 */
getList() {
this.loading = true;
listModel(this.queryParams).then((response) => {
this.modelList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
templateId: null,
templateName: null,
userId: null,
userName: null,
tenantId: null,
tenantName: null,
identifier: null,
type: 1,
datatype: "integer",
isSys: null,
isTop: null,
isMonitor: null,
delFlag: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: null,
specs: {
enumList: [{
value: "",
text: ""
}],
arrayType: "int"
},
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加物模型";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const modelId = row.modelId;;
getModel(modelId).then((response) => {
let tempForm = response.data;
this.open = true;
this.title = "修改物模型";
// Json转对象
tempForm.specs = JSON.parse(tempForm.specs);
if (!tempForm.specs.enumList) {
tempForm.specs.enumList = [{
value: "",
text: ""
}];
}
if (!tempForm.specs.arrayType) {
tempForm.specs.arrayType = "int";
}
this.form=tempForm;
});
},
/**查看物模型 */
handleOpenThingsModel() {
this.title = "物模型";
// 生成物模型
this.thingsModel = {
properties: [],
functions: [],
events: []
}
for (var i = 0; i < this.modelList.length; i++) {
let thingsItem = {};
thingsItem.id = this.modelList[i].identifier;
thingsItem.name = this.modelList[i].modelName;
if (this.modelList[i].type == 1) {
//属性
thingsItem.isTop = this.modelList[i].isTop;
thingsItem.isMonitor = this.modelList[i].isMonitor;
thingsItem.datatype = JSON.parse(this.modelList[i].specs);
this.thingsModel.properties.push(thingsItem);
} else if (this.modelList[i].type == 2) {
// 功能
thingsItem.isTop = this.modelList[i].isTop;
thingsItem.datatype = JSON.parse(this.modelList[i].specs);
this.thingsModel.functions.push(thingsItem);
} else if (this.modelList[i].type == 3) {
// 事件
thingsItem.datatype = JSON.parse(this.modelList[i].specs);
this.thingsModel.events.push(thingsItem);
}
}
this.openThingsModel = true;
},
/**关闭物模型 */
handleCloseThingsModel() {
this.openThingsModel = false;
},
/** 选择物模型 */
handleSelect() {
this.openSelect = true;
this.title = "导入通用物模型";
this.form.type = 1;
this.form.datatype = "integer"
this.form.specs = {
enumList: [],
};
},
// 取消导入通用物模型按钮
cancelSelect() {
this.openSelect = false;
this.$refs.productSelectTemplate.$refs.selectTemplateTable.clearSelection();
},
// 获取子组件的值
getChildData(data) {
this.templateIds = data;
},
// 导入通用物模型按钮
importSelect() {
if (this.templateIds != null && this.templateIds.length > 0) {
var importData = {
productId: this.productInfo.productId,
productName: this.productInfo.productName,
templateIds: this.templateIds
}
importModel(importData).then(response => {
this.$modal.msgSuccess(response.msg);
this.openSelect = false;
this.$refs.productSelectTemplate.$refs.selectTemplateTable.clearSelection();
this.getList();
});
}
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate((valid) => {
if (valid) {
if (this.form.modelId != null) {
// 格式化specs
this.form.specs = this.formatThingsSpecs();
if (this.form.type == 2) {
this.form.isMonitor = 0;
} else if (this.form.type == 3) {
this.form.isMonitor = 0;
this.form.isTop = 0;
}
updateModel(this.form).then((response) => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
// 格式化specs
this.form.specs = this.formatThingsSpecs();
this.form.productId = this.productInfo.productId;
this.form.productName = this.productInfo.productName;
if (this.form.type == 2) {
this.form.isMonitor = 0;
} else if (this.form.type == 3) {
this.form.isMonitor = 0;
this.form.isTop = 0;
}
addModel(this.form).then((response) => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const modelIds = row.modelId;
this.$modal
.confirm('是否确认删除物模型编号为"' + modelIds + '"的数据项?')
.then(function () {
return delModel(modelIds);
})
.then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download(
"iot/model/export", {
...this.queryParams,
},
`model_${new Date().getTime()}.xlsx`
);
},
// 类型改变
typeChange(label) {
if (label == 2 || label == 3) {
this.form.isMonitor = 0;
}
},
// 实时监测改变
changeMonitor(isMonitor) {
if (isMonitor == 1 && this.form.datatype != "integer" && this.form.datatype != "decimal") {
this.form.datatype = "integer";
}
},
// 格式化物模型
formatThingsSpecs() {
var data = {};
data.type = this.form.datatype;
if (this.form.datatype == "integer" || this.form.datatype == "decimal") {
data.min = Number(this.form.specs.min);
data.max = Number(this.form.specs.max);
data.unit = this.form.specs.unit;
data.step = Number(this.form.specs.step);
} else if (this.form.datatype == "string") {
data.maxLength = Number(this.form.specs.maxLength);
} else if (this.form.datatype == "bool") {
data.falseText = this.form.specs.falseText;
data.trueText = this.form.specs.trueText;
} else if (this.form.datatype == "array") {
data.arrayType = this.form.specs.arrayType;
} else if (this.form.datatype == "enum") {
data.enumList = this.form.specs.enumList;
}
return JSON.stringify(data);
},
/** 切换为枚举项 */
dataTypeChange(val) {
// if (val == "enum") {
// this.form.specs.enumList = [{
// value: "",
// text: ""
// }];
// }
},
/** 添加枚举项 */
addEnumItem() {
this.form.specs.enumList.push({
value: "",
text: ""
});
},
/** 删除枚举项 */
removeEnumItem(index) {
this.form.specs.enumList.splice(index, 1);
},
/** 格式化显示数据定义 */
formatSpecsDisplay(json) {
let specs = JSON.parse(json);
if (specs.type === "integer" || specs.type === "decimal") {
return "<span style='width:50%;display:inline-block;'>最大值:<span style=\"color:#F56C6C\">" + specs.max +
"</span></span>最小值:<span style=\"color:#F56C6C\">" + specs.min +
"</span><br /><span style='width:50%;display:inline-block;'>步长:<span style=\"color:#F56C6C\">" + specs.step +
"</span></span>单位:<span style=\"color:#F56C6C\">" + specs.unit;
} else if (specs.type === "string") {
return "最大长度:<span style=\"color:#F56C6C\">" + specs.maxLength + "</span>";
} else if (specs.type === "array") {
return "数组类型:<span style=\"color:#F56C6C\">" + specs.arrayType + "</span>";
} else if (specs.type === "enum") {
let items = "";
for (let i = 0; i < specs.enumList.length; i++) {
items = items + "<span style='width:50%;display:inline-block;'>" + specs.enumList[i].value + "<span style='color:#F56C6C'>" + specs.enumList[i].text + "</span></span>"
if (i > 0 && i % 2 != 0) {
items = items + "<br />"
}
}
return items;
} else if (specs.type === "bool") {
return "<span style='width:50%;display:inline-block;'>0<span style=\"color:#F56C6C\">" + specs.falseText +
"</span></span>1<span style=\"color:#F56C6C\">" + specs.trueText
}
},
},
};
</script>