20260118:优化计算公式-新增计算模型页面正则,样式;隐藏产品管理页面轮询任务
This commit is contained in:
parent
271e2102db
commit
0a309d5fec
@ -69,16 +69,16 @@
|
|||||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||||
|
|
||||||
<!-- 添加或修改物模型对话框 -->
|
<!-- 添加或修改物模型对话框 -->
|
||||||
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="600px" append-to-body v-dialogDrag>
|
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="800px" append-to-body v-dialogDrag>
|
||||||
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-form-item label="物模型名称" prop="modelName">
|
<el-form-item label="物模型名称" prop="modelName">
|
||||||
<el-input v-model="form.modelName" placeholder="请输入物模型名称" style="width: 385px" />
|
<el-input v-model="form.modelName" placeholder="请输入物模型名称" style="width: 580px" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="标识符" prop="identifier">
|
<el-form-item label="标识符" prop="identifier">
|
||||||
<el-input v-model="form.identifier" placeholder="请输入标识符" style="width: 385px" :disabled="!!form.modelId" />
|
<el-input v-model="form.identifier" placeholder="请输入标识符" style="width: 580px" :disabled="!!form.modelId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="排序" prop="modelOrder">
|
<el-form-item label="排序" prop="modelOrder">
|
||||||
<el-input v-model="form.modelOrder" placeholder="请输入排序" type="number" style="width: 385px" />
|
<el-input v-model="form.modelOrder" placeholder="请输入排序" type="number" style="width: 580px" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="模型特性" prop="property">
|
<el-form-item label="模型特性" prop="property">
|
||||||
<el-checkbox name="isChart" label="图表展示" v-model="form.isChart" :true-label="1" :false-label="0"></el-checkbox>
|
<el-checkbox name="isChart" label="图表展示" v-model="form.isChart" :true-label="1" :false-label="0"></el-checkbox>
|
||||||
@ -107,10 +107,10 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="单位">
|
<el-form-item label="单位">
|
||||||
<el-input v-model="specsForm.unit" placeholder="请输入单位,如:℃、%" style="width: 385px" />
|
<el-input v-model="specsForm.unit" placeholder="请输入单位,如:℃、%" style="width: 580px" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="步长">
|
<el-form-item label="步长">
|
||||||
<el-input v-model="specsForm.step" placeholder="请输入步长" type="number" style="width: 385px" />
|
<el-input v-model="specsForm.step" placeholder="请输入步长" type="number" style="width: 580px" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -125,7 +125,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item label="计算公式" prop="formula">
|
<el-form-item label="计算公式" prop="formula" class="formula-form-item">
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
<span slot="label">{{$t('device.device-edit.148398-83')}}</span>
|
<span slot="label">{{$t('device.device-edit.148398-83')}}</span>
|
||||||
<el-tooltip style="cursor: pointer" effect="light" placement="top">
|
<el-tooltip style="cursor: pointer" effect="light" placement="top">
|
||||||
@ -202,10 +202,11 @@
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
/* 公式编辑器容器 */
|
/* 公式编辑器容器 */
|
||||||
.formula-editor-container {
|
.formula-editor-container {
|
||||||
width: 420px;
|
width: 100%;
|
||||||
|
max-width: 580px;
|
||||||
border: 1px solid #e4e7ed;
|
border: 1px solid #e4e7ed;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 14px;
|
padding: 16px;
|
||||||
background: linear-gradient(to bottom, #fafbfc, #ffffff);
|
background: linear-gradient(to bottom, #fafbfc, #ffffff);
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
@ -225,7 +226,7 @@
|
|||||||
|
|
||||||
.operator-buttons {
|
.operator-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: nowrap;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,9 +262,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
max-height: 80px;
|
max-height: 120px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 2px 0;
|
padding: 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.var-tag {
|
.var-tag {
|
||||||
@ -325,6 +326,47 @@
|
|||||||
.clear-btn:hover {
|
.clear-btn:hover {
|
||||||
background-color: #fef0f0;
|
background-color: #fef0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 计算公式错误提示样式 - 更加醒目(仅针对计算公式一栏) */
|
||||||
|
::v-deep .formula-form-item.is-error .el-form-item__error {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(135deg, #f56c6c 0%, #e64242 100%);
|
||||||
|
padding: 10px 16px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-top: 10px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: 0 4px 12px rgba(245, 108, 108, 0.4);
|
||||||
|
animation: shake 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .formula-form-item.is-error .el-form-item__error::before {
|
||||||
|
content: "⚠";
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }
|
||||||
|
20%, 40%, 60%, 80% { transform: translateX(4px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 公式编辑器容器错误状态 */
|
||||||
|
::v-deep .formula-form-item.is-error .formula-editor-container {
|
||||||
|
border-color: #f56c6c;
|
||||||
|
border-width: 2px;
|
||||||
|
box-shadow: 0 0 0 3px rgba(245, 108, 108, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 公式输入框错误状态边框 */
|
||||||
|
::v-deep .formula-form-item.is-error .el-textarea__inner {
|
||||||
|
border-color: #f56c6c;
|
||||||
|
border-width: 2px;
|
||||||
|
box-shadow: 0 0 0 3px rgba(245, 108, 108, 0.2);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -392,7 +434,10 @@ export default {
|
|||||||
{ pattern: /^[a-zA-Z][a-zA-Z0-9_]*$/, message: '以字母开头,只含字母、数字、下划线', trigger: 'blur' },
|
{ pattern: /^[a-zA-Z][a-zA-Z0-9_]*$/, message: '以字母开头,只含字母、数字、下划线', trigger: 'blur' },
|
||||||
],
|
],
|
||||||
datatype: [{ required: true, message: '请选择数据类型', trigger: 'change' }],
|
datatype: [{ required: true, message: '请选择数据类型', trigger: 'change' }],
|
||||||
formula: [{ required: true, message: '请输入计算公式', trigger: 'blur' }],
|
formula: [
|
||||||
|
{ required: true, message: '请输入计算公式', trigger: 'none' },
|
||||||
|
{ validator: this.validateFormula, trigger: 'none' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -411,6 +456,93 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/** 校验计算公式格式 */
|
||||||
|
validateFormula(rule, value, callback) {
|
||||||
|
if (!value) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 去除空格后校验
|
||||||
|
const formula = value.replace(/\s+/g, '');
|
||||||
|
|
||||||
|
// 1. 校验是否包含非法字符(只允许:数字、小数点、运算符、括号、大括号变量、sqrt)
|
||||||
|
// 合法字符:0-9 . + - * / % ^ ( ) { } 字母(用于变量和sqrt)
|
||||||
|
const validCharsPattern = /^[0-9a-zA-Z_+\-*/%^(){}.\s]+$/;
|
||||||
|
if (!validCharsPattern.test(formula)) {
|
||||||
|
callback(new Error('公式包含非法字符'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 校验变量格式:{标识符},标识符以字母开头,只含字母、数字、下划线
|
||||||
|
const variablePattern = /\{([^}]*)\}/g;
|
||||||
|
let match;
|
||||||
|
while ((match = variablePattern.exec(formula)) !== null) {
|
||||||
|
const varName = match[1];
|
||||||
|
if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(varName)) {
|
||||||
|
callback(new Error(`变量格式错误: {${varName}},标识符需以字母开头,只含字母、数字、下划线`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 校验括号是否匹配
|
||||||
|
let parenthesesCount = 0;
|
||||||
|
let braceCount = 0;
|
||||||
|
for (const char of formula) {
|
||||||
|
if (char === '(') parenthesesCount++;
|
||||||
|
if (char === ')') parenthesesCount--;
|
||||||
|
if (char === '{') braceCount++;
|
||||||
|
if (char === '}') braceCount--;
|
||||||
|
if (parenthesesCount < 0) {
|
||||||
|
callback(new Error('括号不匹配:存在多余的右括号'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (braceCount < 0) {
|
||||||
|
callback(new Error('变量大括号不匹配:存在多余的右大括号'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parenthesesCount !== 0) {
|
||||||
|
callback(new Error('括号不匹配:左右括号数量不一致'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (braceCount !== 0) {
|
||||||
|
callback(new Error('变量大括号不匹配:左右大括号数量不一致'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 校验不能以运算符开头(除了负号和左括号)
|
||||||
|
if (/^[*/%^)]/.test(formula)) {
|
||||||
|
callback(new Error('公式不能以 * / % ^ ) 开头'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 校验不能以运算符结尾(除了右括号和右大括号)
|
||||||
|
if (/[+\-*/%^(]$/.test(formula)) {
|
||||||
|
callback(new Error('公式不能以运算符结尾'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 校验不能有连续的运算符(除了负号可以跟在其他运算符后面)
|
||||||
|
if (/[+\-*/%^]{2,}/.test(formula.replace(/([+*/%^(])-/g, '$1NEG'))) {
|
||||||
|
callback(new Error('公式中不能有连续的运算符'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 校验sqrt后面必须跟左括号或数字或变量
|
||||||
|
if (/sqrt(?![({0-9])/.test(formula)) {
|
||||||
|
callback(new Error('sqrt后面必须跟括号、数字或变量'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. 校验公式必须包含至少一个变量
|
||||||
|
if (!/\{[a-zA-Z][a-zA-Z0-9_]*\}/.test(formula)) {
|
||||||
|
callback(new Error('计算公式必须包含至少一个物模型变量,如:{temperature}'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
|
||||||
/** 查询设备计算物模型列表 */
|
/** 查询设备计算物模型列表 */
|
||||||
getList() {
|
getList() {
|
||||||
if (!this.queryParams.deviceId) return;
|
if (!this.queryParams.deviceId) return;
|
||||||
|
|||||||
@ -216,8 +216,8 @@
|
|||||||
<product-modbus ref="productModbus" :product="form" @sendPollType="sendPollType" />
|
<product-modbus ref="productModbus" :product="form" @sendPollType="sendPollType" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<!-- 轮询任务 -->
|
<!-- 轮询任务(已隐藏) -->
|
||||||
<el-tab-pane
|
<!-- <el-tab-pane
|
||||||
name="productModbusTask"
|
name="productModbusTask"
|
||||||
:disabled="form.productId == 0"
|
:disabled="form.productId == 0"
|
||||||
v-if="form.deviceType !== 3 && form.deviceType !== 2 && polltype === 0 && (form.protocolCode == 'MODBUS-RTU' || form.protocolCode == 'MODBUS-TCP')"
|
v-if="form.deviceType !== 3 && form.deviceType !== 2 && polltype === 0 && (form.protocolCode == 'MODBUS-RTU' || form.protocolCode == 'MODBUS-TCP')"
|
||||||
@ -225,7 +225,7 @@
|
|||||||
>
|
>
|
||||||
<span slot="label">{{ $t('product.product-edit.473153-84') }}</span>
|
<span slot="label">{{ $t('product.product-edit.473153-84') }}</span>
|
||||||
<product-modbus-task ref="productModbusTask" :product="form" @getSendData="getData($event)" />
|
<product-modbus-task ref="productModbusTask" :product="form" @getSendData="getData($event)" />
|
||||||
</el-tab-pane>
|
</el-tab-pane> -->
|
||||||
|
|
||||||
<el-tab-pane label="" name="productAuthorize" :disabled="form.productId == 0" v-if="form.deviceType !== 3">
|
<el-tab-pane label="" name="productAuthorize" :disabled="form.productId == 0" v-if="form.deviceType !== 3">
|
||||||
<span slot="label" v-hasPermi="['iot:authorize:query']">{{ $t('product.product-edit.473153-40') }}</span>
|
<span slot="label" v-hasPermi="['iot:authorize:query']">{{ $t('product.product-edit.473153-40') }}</span>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user