766 lines
21 KiB
Markdown
Raw Permalink Normal View History

# 前端UI参数配置指南
## 概述
本文档为前端开发人员提供二次回路巡检系统UI参数配置的详细指南包括表单字段、验证规则、数据格式和用户交互设计。
---
## 事件驱动配置表单
### 1. 基本信息字段
```typescript
interface EventDrivenConfigForm {
// 基本信息
configName: string; // 配置名称 [必填, 最大100字符]
inspectionPlanId: string; // 巡检计划ID [必填]
inspectionItemId?: string; // 巡检子项ID [可选]
// 触发配置
triggerExpression: string; // 触发表达式 [必填, 最大500字符]
triggerConditionDescription?: string; // 触发条件描述 [可选, 最大500字符]
// 时间配置
mandatoryWaitSeconds: number; // 强制等待时间 [1-3600秒, 默认30]
delayTriggerSeconds: number; // 延时触发时间 [0-3600秒, 默认0]
timeWindowSeconds: number; // 时间窗口 [1-3600秒, 默认60]
// 高级选项
enableTrueToFalseTrigger: boolean; // 支持true到false触发 [默认false]
priority: 'Low' | 'Medium' | 'High'; // 优先级 [默认Medium]
maxRetryCount: number; // 最大重试次数 [0-5, 默认1]
executionTimeoutSeconds: number; // 执行超时时间 [30-3600秒, 默认300]
isActive: boolean; // 是否启用 [默认true]
}
```
### 2. 表单验证规则
```typescript
const validationRules = {
configName: [
{ required: true, message: '配置名称不能为空' },
{ max: 100, message: '配置名称长度不能超过100个字符' }
],
inspectionPlanId: [
{ required: true, message: '请选择巡检计划' }
],
triggerExpression: [
{ required: true, message: '触发表达式不能为空' },
{ max: 500, message: '触发表达式长度不能超过500个字符' },
{ validator: validateExpression, message: '表达式语法错误' }
],
mandatoryWaitSeconds: [
{ type: 'number', min: 1, max: 3600, message: '强制等待时间必须在1-3600秒之间' }
],
delayTriggerSeconds: [
{ type: 'number', min: 0, max: 3600, message: '延时触发时间必须在0-3600秒之间' }
],
timeWindowSeconds: [
{ type: 'number', min: 1, max: 3600, message: '时间窗口必须在1-3600秒之间' }
]
};
```
### 3. UI组件配置
```vue
<template>
<el-form :model="form" :rules="rules" ref="formRef" label-width="140px">
<!-- 基本信息 -->
<el-form-item label="配置名称" prop="configName">
<el-input
v-model="form.configName"
placeholder="请输入配置名称"
maxlength="100"
show-word-limit
/>
</el-form-item>
<!-- 触发表达式编辑器 -->
<el-form-item label="触发表达式" prop="triggerExpression">
<expression-editor
v-model="form.triggerExpression"
:variables="availableVariables"
@validate="onExpressionValidate"
placeholder="例如: {16835_0} > 100 && {16836_0} < 200"
/>
<div class="expression-help">
<el-button type="text" @click="showExpressionHelp">表达式语法帮助</el-button>
<el-button type="text" @click="testExpression">测试表达式</el-button>
</div>
</el-form-item>
<!-- 时间配置 -->
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="强制等待时间" prop="mandatoryWaitSeconds">
<el-input-number
v-model="form.mandatoryWaitSeconds"
:min="1"
:max="3600"
controls-position="right"
/>
<span class="unit"></span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="延时触发时间" prop="delayTriggerSeconds">
<el-input-number
v-model="form.delayTriggerSeconds"
:min="0"
:max="3600"
controls-position="right"
/>
<span class="unit"></span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="时间窗口" prop="timeWindowSeconds">
<el-input-number
v-model="form.timeWindowSeconds"
:min="1"
:max="3600"
controls-position="right"
/>
<span class="unit"></span>
</el-form-item>
</el-col>
</el-row>
<!-- 高级选项 -->
<el-collapse>
<el-collapse-item title="高级选项" name="advanced">
<el-form-item label="触发方向">
<el-checkbox v-model="form.enableTrueToFalseTrigger">
支持从true到false的触发
</el-checkbox>
<div class="field-help">
勾选后表达式结果从true变为false时也会触发巡检
</div>
</el-form-item>
<el-form-item label="优先级" prop="priority">
<el-radio-group v-model="form.priority">
<el-radio label="Low"></el-radio>
<el-radio label="Medium"></el-radio>
<el-radio label="High"></el-radio>
</el-radio-group>
</el-form-item>
</el-collapse-item>
</el-collapse>
</el-form>
</template>
```
---
## 巡检项配置表单
### 1. 基本字段配置
```typescript
interface InspectionItemForm {
// 基本信息
itemName: string; // 项目名称 [必填, 最大200字符]
itemDescription?: string; // 项目描述 [可选, 最大1000字符]
inspectionType: InspectionType; // 巡检类型 [必填]
// 计算配置
calculationExpression?: string; // 自定义计算表达式 [可选, 最大1000字符]
expressionDurationRequirementSeconds: number; // 表达式持续时间要求 [0-3600秒, 默认0]
calculationMethod: CalculationMethod; // 计算方式 [必填]
timeWindowSeconds: number; // 时间窗口 [1-3600秒, 默认10]
// 阈值配置
voltageDeviationThreshold: number; // 电压偏差阈值 [0.1-100kV, 默认1.0]
currentDeviationThresholdPercent: number; // 电流偏差阈值百分比 [0.1-100%, 默认5.0]
phaseAngleDifferenceThreshold: number; // 相角差阈值 [0-180度, 默认10.0]
// 状态配置
isActive: boolean; // 是否启用 [默认true]
sortOrder: number; // 排序序号 [默认0]
}
```
### 2. 巡检类型选项
```typescript
const inspectionTypeOptions = [
{
value: 'VoltageCollectionConsistency',
label: '电压采集一致性判断',
description: '检查多个电压采集点的数值一致性',
icon: 'el-icon-lightning',
color: '#409EFF'
},
{
value: 'CurrentCollectionConsistency',
label: '电流采集一致性判断',
description: '检查电流采集的一致性和合理性',
icon: 'el-icon-connection',
color: '#67C23A'
},
{
value: 'PositionSignalVerification',
label: '位置信号采集校验',
description: '校验开关位置信号的正确性',
icon: 'el-icon-switch-button',
color: '#E6A23C'
},
{
value: 'ACCircuitPolarityVerification',
label: '交流回路极性校验',
description: '验证交流回路的极性正确性',
icon: 'el-icon-sort',
color: '#F56C6C'
},
{
value: 'CommunicationQualityAnalysis',
label: '通信质量分析',
description: '分析通信链路的质量和可靠性',
icon: 'el-icon-connection',
color: '#909399'
}
];
```
### 3. 表达式编辑器组件
```vue
<template>
<div class="expression-editor">
<!-- Monaco编辑器 -->
<div ref="editorContainer" class="editor-container"></div>
<!-- 工具栏 -->
<div class="editor-toolbar">
<el-button-group>
<el-button size="mini" @click="formatExpression">格式化</el-button>
<el-button size="mini" @click="validateExpression">验证</el-button>
<el-button size="mini" @click="testExpression">测试</el-button>
</el-button-group>
<el-dropdown @command="insertVariable">
<el-button size="mini">
插入变量<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="variable in variables"
:key="variable.code"
:command="variable.code"
>
{{ variable.code }} - {{ variable.description }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<!-- 验证结果 -->
<div v-if="validationResult" class="validation-result">
<el-alert
:type="validationResult.isValid ? 'success' : 'error'"
:title="validationResult.isValid ? '表达式语法正确' : '表达式语法错误'"
:description="validationResult.errors.join('; ')"
show-icon
:closable="false"
/>
</div>
<!-- 测试结果 -->
<div v-if="testResult" class="test-result">
<el-card>
<div slot="header">
<span>测试结果</span>
<el-tag :type="testResult.flag ? 'success' : 'danger'" style="float: right;">
{{ testResult.flag ? '正常' : '异常' }}
</el-tag>
</div>
<div>
<p><strong>计算结果:</strong> {{ testResult.result }}</p>
<p><strong>执行时间:</strong> {{ testResult.executionTimeMs }}ms</p>
<p><strong>变量值:</strong></p>
<ul>
<li v-for="(value, key) in testResult.variableValues" :key="key">
{{ key }}: {{ value }}
</li>
</ul>
</div>
</el-card>
</div>
</div>
</template>
<script>
import * as monaco from 'monaco-editor';
export default {
name: 'ExpressionEditor',
props: {
value: String,
variables: Array,
placeholder: String
},
data() {
return {
editor: null,
validationResult: null,
testResult: null
};
},
mounted() {
this.initEditor();
},
methods: {
initEditor() {
this.editor = monaco.editor.create(this.$refs.editorContainer, {
value: this.value || '',
language: 'javascript',
theme: 'vs',
minimap: { enabled: false },
scrollBeyondLastLine: false,
wordWrap: 'on',
automaticLayout: true
});
this.editor.onDidChangeModelContent(() => {
this.$emit('input', this.editor.getValue());
});
},
async validateExpression() {
const expression = this.editor.getValue();
try {
const response = await this.$http.post('/api/secondary-circuit/validate-expression', {
expression
});
this.validationResult = response.data.resultData;
this.$emit('validate', this.validationResult);
} catch (error) {
this.validationResult = {
isValid: false,
errors: [error.message]
};
}
},
async testExpression() {
const expression = this.editor.getValue();
try {
const response = await this.$http.post('/api/secondary-circuit/test-expression', {
expression,
timeWindowSeconds: 60
});
this.testResult = response.data.resultData;
} catch (error) {
this.$message.error('测试表达式失败: ' + error.message);
}
},
insertVariable(variableCode) {
const position = this.editor.getPosition();
this.editor.executeEdits('', [{
range: new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column),
text: `{${variableCode}}`
}]);
this.editor.focus();
}
}
};
</script>
```
---
## JavaScript代码编辑器
### 1. 代码编辑器配置
```vue
<template>
<div class="javascript-editor">
<div class="editor-header">
<h4>JavaScript代码编辑器</h4>
<div class="editor-actions">
<el-button size="mini" @click="loadTemplate">加载模板</el-button>
<el-button size="mini" @click="runCode">运行代码</el-button>
<el-button size="mini" type="primary" @click="saveCode">保存</el-button>
</div>
</div>
<div ref="codeEditor" class="code-editor"></div>
<!-- 数据预览 -->
<el-collapse v-model="activeCollapse">
<el-collapse-item title="数据预览" name="dataPreview">
<pre>{{ JSON.stringify(sampleData, null, 2) }}</pre>
</el-collapse-item>
<el-collapse-item title="执行结果" name="result" v-if="executionResult">
<div class="execution-result">
<el-tag :type="executionResult.flag ? 'success' : 'danger'">
{{ executionResult.flag ? '正常' : '异常' }}
</el-tag>
<p><strong>结果描述:</strong> {{ executionResult.resultDescription }}</p>
<p><strong>执行时间:</strong> {{ executionResult.executionTimeMs }}ms</p>
<div v-if="executionResult.details && executionResult.details.length">
<p><strong>执行详情:</strong></p>
<ul>
<li v-for="detail in executionResult.details" :key="detail">{{ detail }}</li>
</ul>
</div>
</div>
</el-collapse-item>
</el-collapse>
</div>
</template>
```
### 2. 代码模板
```javascript
const codeTemplates = {
basic: `// 基本阈值检查模板
function checkThreshold() {
let abnormalCount = 0;
for (let item of data) {
for (let key in item) {
if (item[key].value > 100) {
abnormalCount++;
}
}
}
return {
Flag: abnormalCount === 0,
ResultDescription: abnormalCount === 0 ?
"所有数据点正常" :
\`发现\${abnormalCount}个异常数据点\`
};
}
checkThreshold();`,
voltageConsistency: `// 电压一致性检查模板
function checkVoltageConsistency() {
let voltageValues = [];
// 收集所有电压值
for (let item of data) {
for (let key in item) {
if (key.endsWith('_0')) { // 遥测数据
voltageValues.push(item[key].value);
}
}
}
if (voltageValues.length < 2) {
return {
Flag: false,
ResultDescription: "电压数据点不足,无法进行一致性检查"
};
}
// 计算电压偏差
let maxVoltage = Math.max(...voltageValues);
let minVoltage = Math.min(...voltageValues);
let deviation = maxVoltage - minVoltage;
return {
Flag: deviation <= 5.0,
ResultDescription: \`电压偏差: \${deviation.toFixed(2)}V, \${deviation <= 5.0 ? '正常' : '异常'}\`
};
}
checkVoltageConsistency();`,
timeSeries: `// 时间序列分析模板
function analyzeTimeSeries() {
let timeSeriesData = {};
// 按变量代码分组数据
for (let item of data) {
for (let key in item) {
if (!timeSeriesData[key]) {
timeSeriesData[key] = [];
}
timeSeriesData[key].push({
value: item[key].value,
time: item[key].time
});
}
}
let results = [];
// 分析每个变量的趋势
for (let variable in timeSeriesData) {
let values = timeSeriesData[variable];
if (values.length >= 2) {
let trend = values[values.length - 1].value - values[0].value;
results.push({
variable: variable,
trend: trend,
isStable: Math.abs(trend) < 1.0
});
}
}
let unstableCount = results.filter(r => !r.isStable).length;
return {
Flag: unstableCount === 0,
ResultDescription: unstableCount === 0 ?
"所有变量趋势稳定" :
\`\${unstableCount}个变量趋势不稳定\`
};
}
analyzeTimeSeries();`
};
```
---
## 数据展示组件
### 1. 时间窗口数据表格
```vue
<template>
<div class="time-window-data">
<div class="data-header">
<h4>时间窗口数据</h4>
<el-button @click="refreshData" :loading="loading">刷新数据</el-button>
</div>
<el-table :data="tableData" border>
<el-table-column prop="variableCode" label="变量代码" width="120"/>
<el-table-column prop="variableName" label="变量名称" width="200"/>
<el-table-column prop="value" label="当前值" width="100">
<template slot-scope="scope">
<span :class="getValueClass(scope.row)">{{ scope.row.value }}</span>
</template>
</el-table-column>
<el-table-column prop="unit" label="单位" width="80"/>
<el-table-column prop="updateTime" label="更新时间" width="160"/>
<el-table-column prop="status" label="状态" width="100">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 'normal' ? 'success' : 'danger'">
{{ scope.row.status === 'normal' ? '正常' : '异常' }}
</el-tag>
</template>
</el-table-column>
</el-table>
</div>
</template>
```
### 2. 实时数据图表
```vue
<template>
<div class="realtime-chart">
<div ref="chart" class="chart-container"></div>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'RealtimeChart',
props: {
data: Array,
title: String
},
mounted() {
this.initChart();
},
methods: {
initChart() {
this.chart = echarts.init(this.$refs.chart);
const option = {
title: {
text: this.title || '实时数据'
},
tooltip: {
trigger: 'axis',
formatter: function (params) {
let result = params[0].name + '<br/>';
params.forEach(param => {
result += param.marker + param.seriesName + ': ' + param.value + '<br/>';
});
return result;
}
},
legend: {
data: []
},
xAxis: {
type: 'time',
splitLine: {
show: false
}
},
yAxis: {
type: 'value',
splitLine: {
show: true
}
},
series: []
};
this.chart.setOption(option);
this.updateChart();
},
updateChart() {
if (!this.data || !this.chart) return;
const series = this.processData(this.data);
this.chart.setOption({
legend: {
data: series.map(s => s.name)
},
series: series
});
},
processData(data) {
const seriesMap = {};
data.forEach(item => {
Object.keys(item).forEach(key => {
if (!seriesMap[key]) {
seriesMap[key] = {
name: key,
type: 'line',
data: []
};
}
seriesMap[key].data.push([
item[key].time,
item[key].value
]);
});
});
return Object.values(seriesMap);
}
},
watch: {
data: {
handler() {
this.updateChart();
},
deep: true
}
}
};
</script>
```
---
## 样式指南
### 1. CSS变量定义
```css
:root {
--primary-color: #409EFF;
--success-color: #67C23A;
--warning-color: #E6A23C;
--danger-color: #F56C6C;
--info-color: #909399;
--border-radius: 4px;
--box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
--transition: all 0.3s ease;
}
```
### 2. 组件样式
```css
.expression-editor {
border: 1px solid #DCDFE6;
border-radius: var(--border-radius);
overflow: hidden;
}
.editor-container {
height: 200px;
border-bottom: 1px solid #EBEEF5;
}
.editor-toolbar {
padding: 8px 12px;
background-color: #F5F7FA;
display: flex;
justify-content: space-between;
align-items: center;
}
.validation-result,
.test-result {
margin-top: 12px;
}
.field-help {
font-size: 12px;
color: var(--info-color);
margin-top: 4px;
}
.unit {
margin-left: 8px;
color: var(--info-color);
font-size: 12px;
}
```
---
## 最佳实践
### 1. 用户体验优化
- **实时验证**: 在用户输入时实时验证表达式语法
- **智能提示**: 提供变量代码和函数的智能提示
- **错误提示**: 清晰的错误信息和修复建议
- **数据预览**: 实时预览计算结果和数据变化
### 2. 性能优化
- **防抖处理**: 对频繁的验证和测试操作进行防抖
- **懒加载**: 大量数据的懒加载和虚拟滚动
- **缓存机制**: 缓存验证结果和测试数据
- **异步处理**: 长时间操作的异步处理和进度提示
### 3. 可访问性
- **键盘导航**: 支持完整的键盘操作
- **屏幕阅读器**: 提供适当的ARIA标签
- **颜色对比**: 确保足够的颜色对比度
- **焦点管理**: 合理的焦点顺序和视觉反馈
---
*本文档版本: 1.0*
*最后更新: 2024年*