Files
2023-03-29 11:11:06 +08:00

732 lines
22 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 class="app-container">
<el-form
v-show="showSearch"
ref="queryRef"
:inline="true"
:model="queryParams"
label-position="left"
label-width="100px"
>
<el-form-item label="物模型名称" prop="modelName">
<el-input
v-model="queryParams.modelName"
clearable
placeholder="请输入物模型名称"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="产品" prop="productId">
<el-select
v-model="queryParams.productId"
:remote-method="getProductOptions"
filterable
placeholder="请选择产品"
remote
remote-show-suffix
>
<el-option
v-for="item in productOptions"
:key="item.productId"
:label="item.productName"
:value="item.productId"
/>
</el-select>
</el-form-item>
<el-form-item label="租户" prop="tenantId">
<!-- <el-input-->
<!-- v-model="queryParams.tenantId"-->
<!-- clearable-->
<!-- placeholder="请输入租户ID"-->
<!-- @keyup.enter="handleQuery"-->
<!-- />-->
<el-select
v-model="queryParams.tenantId"
:remote-method="getTenantOptions"
filterable
remote
remote-show-suffix
>
<el-option
v-for="item in tenantOptions"
:key="item.tenantId"
:label="item.tenantName"
:value="item.tenantId"
/>
</el-select>
</el-form-item>
<el-form-item label="标识符,产品下唯一" prop="identifier">
<el-input
v-model="queryParams.identifier"
clearable
placeholder="请输入标识符,产品下唯一"
@keyup.enter="handleQuery"
/>
</el-form-item>
<!-- <el-form-item label="是否首页显示" prop="isTop">-->
<!-- <el-input-->
<!-- v-model="queryParams.isTop"-->
<!-- clearable-->
<!-- placeholder="请输入是否首页显示"-->
<!-- @keyup.enter="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="是否实时监测" prop="isMonitor">-->
<!-- <el-input-->
<!-- v-model="queryParams.isMonitor"-->
<!-- clearable-->
<!-- placeholder="请输入是否实时监测"-->
<!-- @keyup.enter="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item>
<el-button icon="Search" type="primary" @click="handleQuery"
>搜索
</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
v-hasPermi="['thingsmodel:model:add']"
icon="Plus"
plain
type="primary"
@click="handleAdd"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['thingsmodel:model:edit']"
:disabled="single"
icon="Edit"
plain
type="success"
@click="handleUpdate"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['thingsmodel:model:remove']"
:disabled="multiple"
icon="Delete"
plain
type="danger"
@click="handleDelete"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['thingsmodel:model:export']"
icon="Download"
plain
type="warning"
@click="handleExport"
>导出
</el-button>
</el-col>
<right-toolbar
v-model:showSearch="showSearch"
@queryTable="getList"
></right-toolbar>
</el-row>
<el-table
v-loading="loading"
:data="modelList"
@selection-change="handleSelectionChange"
>
<el-table-column align="center" type="selection" width="55" />
<el-table-column align="center" label="物模型ID" prop="modelId" />
<el-table-column align="center" label="物模型名称" prop="modelName" />
<el-table-column align="center" label="产品ID" prop="productId" />
<el-table-column align="center" label="租户ID" prop="tenantId" />
<el-table-column
align="center"
label="标识符,产品下唯一"
prop="identifier"
/>
<el-table-column align="center" label="模型类别" prop="type">
<template #default="{ row }">
<model-type-tags :type="row.type" />
</template>
</el-table-column>
<el-table-column align="center" label="数据类型" prop="datatype">
<template #default="{ row }">
<!-- {{ dataTypeMap.get(row.datatype) ?? "未知" }}-->
<dict-tag :options="dataTypeDict" :value="[row.datatype]" />
</template>
</el-table-column>
<el-table-column
align="center"
header-align="center"
label="数据定义"
min-width="150"
prop="specs"
>
<template #default="{ row }">
<!-- {{ formatSpecsDisplay(row.specs) }}-->
<div v-html="formatSpecsDisplay(row.specs)"></div>
</template>
</el-table-column>
<!-- <el-table-column align="center" label="是否首页显示" prop="isTop" />-->
<!-- <el-table-column align="center" label="是否实时监测" prop="isMonitor" />-->
<el-table-column align="center" label="备注" prop="remark" />
<el-table-column
align="center"
class-name="small-padding fixed-width"
label="操作"
>
<template #default="scope">
<el-button
v-hasPermi="['thingsmodel:model:edit']"
icon="Edit"
link
type="primary"
@click="handleUpdate(scope.row)"
>修改
</el-button>
<el-button
v-hasPermi="['thingsmodel:model:remove']"
icon="Delete"
link
type="primary"
@click="handleDelete(scope.row)"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNum"
:total="total"
@pagination="getList"
/>
<!-- 添加或修改物模型对话框 -->
<el-dialog v-model="open" :title="title" append-to-body width="600px">
<el-form
ref="modelRef"
:model="form"
:rules="rules"
label-position="left"
label-width="160px"
>
<el-form-item label="物模型名称" prop="modelName">
<el-input v-model="form.modelName" placeholder="请输入物模型名称" />
</el-form-item>
<el-form-item label="产品" prop="productId">
<el-select
v-model="form.productId"
:remote-method="getProductOptions"
filterable
placeholder="请选择产品"
remote
remote-show-suffix
>
<el-option
v-for="item in productOptions"
:key="item.productId"
:label="item.productName"
:value="item.productId"
/>
</el-select>
<!-- <el-input v-model="form.productId" placeholder="请输入产品ID" />-->
</el-form-item>
<el-form-item label="租户" prop="tenantId">
<!-- <el-input v-model="form.tenantId" placeholder="请输入租户ID" />-->
<el-select
v-model="form.tenantId"
:remote-method="getTenantOptions"
filterable
remote
remote-show-suffix
>
<el-option
v-for="item in tenantOptions"
:key="item.tenantId"
:label="item.tenantName"
:value="item.tenantId"
/>
</el-select>
</el-form-item>
<el-form-item label="标识符,产品下唯一" prop="identifier">
<el-input
v-model="form.identifier"
placeholder="请输入标识符,产品下唯一"
/>
</el-form-item>
<!-- <el-form-item label="是否首页显示" prop="isTop">-->
<!-- <el-input v-model="form.isTop" placeholder="请输入是否首页显示" />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="是否实时监测" prop="isMonitor">-->
<!-- <el-input v-model="form.isMonitor" placeholder="请输入是否实时监测" />-->
<!-- </el-form-item>-->
<el-form-item label="备注" prop="remark">
<el-input
v-model="form.remark"
placeholder="请输入内容"
type="textarea"
/>
</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-divider />
<el-form-item label="数据类型" prop="datatype">
<el-select
v-model="form.datatype"
placeholder="请选择数据类型"
style="width: 175px"
@change="dataTypeChange"
>
<el-option key="integer" label="整数" value="integer"></el-option>
<el-option key="decimal" label="小数" value="decimal"></el-option>
<el-option
key="bool"
:disabled="form.type === 1"
label="布尔"
value="bool"
></el-option>
<el-option
key="enum"
:disabled="form.type === 1"
label="枚举"
value="enum"
></el-option>
<el-option
key="string"
:disabled="form.type === 1"
label="字符串"
value="string"
></el-option>
<el-option
key="array"
:disabled="form.type === 1"
label="数组"
value="array"
></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"
style="width: 385px"
type="number"
/>
</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 :offset="1" :span="10"> 0 值对应文本)</el-col>
</el-row>
<el-row>
<el-col :span="9">
<el-input
v-model="form.specs.trueText"
placeholder="例如:打开"
/>
</el-col>
<el-col :offset="1" :span="10"> 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 :offset="1" :span="11">
<el-input
v-model="item.text"
placeholder="参数描述,例如:中速档位"
/>
</el-col>
<el-col v-if="index !== 0" :offset="1" :span="2"
><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 :offset="1" :span="14">字符串的最大长度</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>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script name="Model" setup>
import {
addModel,
delModel,
getModel,
listModel,
updateModel,
} from "@/api/thingsmodel/model";
import { formatSpecsDisplay } from "@/utils/thingsmodel";
import { listProduct } from "@/api/product/product";
import { listTenant } from "@/api/system/tenant";
import ModelTypeTags from "@/views/components/model-type-tags";
import { dataTypeDict } from "../../../constant/dict";
import { ref } from "vue";
const { proxy } = getCurrentInstance();
const modelList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const productOptions = ref([]);
const tenantOptions = ref([]);
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
modelName: null,
productId: null,
tenantId: null,
identifier: null,
type: null,
datatype: null,
specs: null,
isTop: null,
isMonitor: null,
},
rules: {
modelName: [
{ required: true, message: "物模型名称不能为空", trigger: "blur" },
],
productId: [{ required: true, message: "产品ID不能为空", trigger: "blur" }],
tenantId: [{ required: true, message: "租户ID不能为空", 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" }],
isTop: [
{ required: true, message: "是否首页显示不能为空", trigger: "blur" },
],
isMonitor: [
{ required: true, message: "是否实时监测不能为空", trigger: "blur" },
],
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询物模型列表 */
function getList() {
loading.value = true;
listModel(queryParams.value).then((response) => {
modelList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
// 取消按钮
function cancel() {
open.value = false;
reset();
}
// 表单重置
function reset() {
form.value = {
modelId: null,
modelName: null,
productId: null,
tenantId: null,
identifier: null,
type: 1,
datatype: "integer",
specs: {
enumList: [
{
value: "",
text: "",
},
],
arrayType: "int",
},
isTop: 0,
isMonitor: 0,
createBy: null,
createTime: null,
remark: null,
};
proxy.resetForm("modelRef");
}
const dataTypeChange = () => {};
// 类型改变
const typeChange = (label) => {
// if (label === 2 || label === 3) {
// form.value.isMonitor = 0;
// }
if (
label === 1 &&
form.value.datatype !== "integer" &&
form.value.datatype !== "decimal"
) {
form.value.datatype = "integer";
}
};
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.modelId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
// 格式化物模型
const formatThingsSpecs = () => {
let _data = {};
_data.type = form.value.datatype;
if (form.value.datatype === "integer" || form.value.datatype === "decimal") {
_data.min = Number(form.value.specs.min);
_data.max = Number(form.value.specs.max);
_data.unit = form.value.specs.unit;
_data.step = Number(form.value.specs.step);
} else if (form.value.datatype === "string") {
_data.maxLength = Number(form.value.specs.maxLength);
} else if (form.value.datatype === "bool") {
_data.falseText = form.value.specs.falseText;
_data.trueText = form.value.specs.trueText;
} else if (form.value.datatype === "array") {
_data.arrayType = form.value.specs.arrayType;
} else if (form.value.datatype === "enum") {
_data.enumList = form.value.specs.enumList;
}
console.log(_data);
return JSON.stringify(_data);
// return _data;
};
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加物模型";
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const _modelId = row.modelId || ids.value;
getModel(_modelId).then((response) => {
let tempForm = response.data;
open.value = true;
title.value = "修改物模型";
// Json转对象
tempForm.specs = JSON.parse(tempForm.specs);
if (!tempForm.specs.enumList) {
tempForm.specs.enumList = [
{
value: "",
text: "",
},
];
}
if (!tempForm.specs.arrayType) {
tempForm.specs.arrayType = "int";
}
form.value = tempForm;
// form.value = response.data;
// open.value = true;
// title.value = "修改物模型";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["modelRef"].validate((valid) => {
if (valid) {
if (form.value.modelId != null) {
form.value.specs = formatThingsSpecs();
updateModel(form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
form.value.specs = formatThingsSpecs();
addModel(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const _modelIds = row.modelId || ids.value;
proxy.$modal
.confirm('是否确认删除物模型编号为"' + _modelIds + '"的数据项?')
.then(function () {
return delModel(_modelIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download(
"thingsmodel/model/export",
{
...queryParams.value,
},
`model_${new Date().getTime()}.xlsx`
);
}
const productOptionsLoading = ref(true);
function getProductOptions(keyword) {
productOptionsLoading.value = true;
listProduct({
productName: keyword,
pageNum: 1,
pageSize: 20,
}).then((resp) => {
productOptions.value = resp.rows;
productOptionsLoading.value = false;
});
}
const getTenantOptions = async (keyword) => {
const response = await listTenant({
pageNum: 1,
pageSize: 20,
tenantName: keyword,
});
tenantOptions.value = response.rows;
};
getTenantOptions();
getProductOptions();
getList();
</script>