feat(auth): 统一数据库运维菜单路由并添加装置单位及监测点限值配置功能
- 统一数据库监控菜单路径到 /system-ops/dbms 入口 - 添加 isDbmsMenu 函数处理多种数据库菜单路径匹配 - 在动态路由中增加多个数据库监控路径的重定向规则 - 添加设备单位配置功能包括新增 EquipmentUnitForm 接口定义 - 添加监测点限值配置功能包括新增 OverlimitDetail 接口定义 - 在装置表单中添加单位配置按钮并集成单位调试功能 - 在监测点表单中添加限值配置按钮并集成限值调试功能 - 添加电压等级变更时的默认容量和变比同步逻辑 - 配置监测点表单中的线路类型选择选项 - 添加装置表单中比率输入组的高度紧凑样式 - 新增数据库运维静态路由配置和别名支持
This commit is contained in:
@@ -4,11 +4,22 @@
|
||||
<div>
|
||||
<div class="section-title">装置配置</div>
|
||||
</div>
|
||||
<div v-if="!readonly" class="form-actions">
|
||||
<el-button type="primary" :icon="Check" :loading="saving" @click="emit('save')">保存装置</el-button>
|
||||
<el-button type="danger" plain :icon="Delete" :disabled="!localForm.id" @click="emit('delete')">
|
||||
删除装置
|
||||
<div class="form-actions">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
:icon="Setting"
|
||||
:disabled="!localForm.id"
|
||||
@click="emit('open-unit-debug', localForm.id || '', isUnitReadonly)"
|
||||
>
|
||||
{{ unitActionLabel }}
|
||||
</el-button>
|
||||
<template v-if="!readonly">
|
||||
<el-button type="primary" :icon="Check" :loading="saving" @click="emit('save')">保存装置</el-button>
|
||||
<el-button type="danger" plain :icon="Delete" :disabled="!localForm.id" @click="emit('delete')">
|
||||
删除装置
|
||||
</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -70,7 +81,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, watch } from 'vue'
|
||||
import { Check, Delete } from '@element-plus/icons-vue'
|
||||
import { Check, Delete, Setting } from '@element-plus/icons-vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type { AddLedger } from '@/api/tools/addLedger/interface'
|
||||
|
||||
@@ -89,6 +100,7 @@ const props = defineProps<{
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:form': [form: AddLedger.EquipmentForm]
|
||||
'open-unit-debug': [devId: string, readonly: boolean]
|
||||
save: []
|
||||
delete: []
|
||||
}>()
|
||||
@@ -152,6 +164,8 @@ watch(
|
||||
)
|
||||
|
||||
const isSimpleMode = computed(() => props.mode === 'simple')
|
||||
const isUnitReadonly = computed(() => Boolean(props.readonly))
|
||||
const unitActionLabel = computed(() => (isUnitReadonly.value ? '单位查询' : '单位配置'))
|
||||
const formRules = computed<FormRules<AddLedger.EquipmentForm>>(() => ({
|
||||
name: [{ required: true, message: '请输入装置名称', trigger: 'blur' }],
|
||||
mac: [{ required: true, message: '请输入装置网络参数', trigger: 'blur' }],
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
:device-type-options="deviceTypeOptions"
|
||||
:device-model-options="deviceModelOptions"
|
||||
:mode="mode"
|
||||
@open-unit-debug="devId => emit('open-unit-debug', devId, false)"
|
||||
@save="emit('save-equipment')"
|
||||
@delete="emit('delete')"
|
||||
/>
|
||||
@@ -90,6 +91,7 @@
|
||||
:device-model-options="deviceModelOptions"
|
||||
:mode="mode"
|
||||
readonly
|
||||
@open-unit-debug="devId => emit('open-unit-debug', devId, true)"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -123,6 +125,7 @@
|
||||
:saving="saving"
|
||||
:line-no-options="lineNoOptions"
|
||||
:mode="mode"
|
||||
@open-overlimit-debug="lineId => emit('open-overlimit-debug', lineId, false)"
|
||||
@save="emit('save-line')"
|
||||
@delete="emit('delete')"
|
||||
/>
|
||||
@@ -133,6 +136,7 @@
|
||||
:line-no-options="allLineNoOptions"
|
||||
:mode="mode"
|
||||
readonly
|
||||
@open-overlimit-debug="lineId => emit('open-overlimit-debug', lineId, true)"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -211,6 +215,8 @@ const emit = defineEmits<{
|
||||
'save-project': []
|
||||
'save-equipment': []
|
||||
'save-line': []
|
||||
'open-unit-debug': [devId: string, readonly: boolean]
|
||||
'open-overlimit-debug': [lineId: string, readonly: boolean]
|
||||
delete: []
|
||||
'add-project': []
|
||||
'add-equipment': []
|
||||
|
||||
@@ -4,11 +4,22 @@
|
||||
<div>
|
||||
<div class="section-title">监测点配置</div>
|
||||
</div>
|
||||
<div v-if="!readonly" class="form-actions">
|
||||
<el-button type="primary" :icon="Check" :loading="saving" @click="emit('save')">保存测点</el-button>
|
||||
<el-button type="danger" plain :icon="Delete" :disabled="!lineId" @click="emit('delete')">
|
||||
删除测点
|
||||
<div class="form-actions">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
:icon="View"
|
||||
:disabled="!lineId"
|
||||
@click="emit('open-overlimit-debug', lineId, isOverlimitReadonly)"
|
||||
>
|
||||
{{ overlimitActionLabel }}
|
||||
</el-button>
|
||||
<template v-if="!readonly">
|
||||
<el-button type="primary" :icon="Check" :loading="saving" @click="emit('save')">保存测点</el-button>
|
||||
<el-button type="danger" plain :icon="Delete" :disabled="!lineId" @click="emit('delete')">
|
||||
删除测点
|
||||
</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +55,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="电压等级" prop="vol_grade">
|
||||
<el-select v-model="localForm.vol_grade" clearable placeholder="请选择电压等级">
|
||||
<el-select v-model="localForm.vol_grade" clearable placeholder="请选择电压等级" @change="handleVoltageChange">
|
||||
<el-option
|
||||
v-for="item in voltageOptions"
|
||||
:key="item.value"
|
||||
@@ -53,6 +64,11 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!isSimpleMode" label="线路类型" prop="lineType">
|
||||
<el-select v-model="localForm.lineType" clearable placeholder="请选择线路类型">
|
||||
<el-option v-for="item in lineTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!isSimpleMode" label="安装位置" prop="position">
|
||||
<el-input v-model="localForm.position" maxlength="80" clearable placeholder="请输入安装位置" />
|
||||
</el-form-item>
|
||||
@@ -150,7 +166,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, watch } from 'vue'
|
||||
import { Check, Delete } from '@element-plus/icons-vue'
|
||||
import { Check, Delete, View } from '@element-plus/icons-vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type { AddLedger } from '@/api/tools/addLedger/interface'
|
||||
|
||||
@@ -168,10 +184,17 @@ const props = defineProps<{
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:form': [form: AddLedger.LineForm]
|
||||
'open-overlimit-debug': [lineId: string, readonly: boolean]
|
||||
save: []
|
||||
delete: []
|
||||
}>()
|
||||
|
||||
type LineVoltageDefault = {
|
||||
capacity: number
|
||||
ptRatio?: number
|
||||
pt2Ratio?: number
|
||||
}
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const syncingFromProp = ref(false)
|
||||
const localForm = reactive<AddLedger.LineForm>({
|
||||
@@ -192,6 +215,7 @@ const localForm = reactive<AddLedger.LineForm>({
|
||||
basic_capacity: undefined,
|
||||
protocol_capacity: undefined,
|
||||
dev_capacity: undefined,
|
||||
lineType: 0,
|
||||
monitor_obj: '',
|
||||
is_govern: 0,
|
||||
monitor_user: '',
|
||||
@@ -204,17 +228,63 @@ const conTypeOptions: AddLedger.SelectOption<number>[] = [
|
||||
{ label: 'V 型接线', value: 2 }
|
||||
]
|
||||
|
||||
const lineTypeOptions: AddLedger.SelectOption<number>[] = [
|
||||
{ label: '主网', value: 0 },
|
||||
{ label: '配网', value: 1 }
|
||||
]
|
||||
|
||||
const voltageOptions: AddLedger.SelectOption<number>[] = [
|
||||
{ label: '0.38kV', value: 0.38 },
|
||||
{ label: '6kV', value: 6 },
|
||||
{ label: '10kV', value: 10 },
|
||||
{ label: '20kV', value: 20 },
|
||||
{ label: '35kV', value: 35 },
|
||||
{ label: '66kV', value: 66 },
|
||||
{ label: '110kV', value: 110 },
|
||||
{ label: '220kV', value: 220 },
|
||||
{ label: '500kV', value: 500 }
|
||||
{ label: '330kV', value: 330 },
|
||||
{ label: '500kV', value: 500 },
|
||||
{ label: '750kV', value: 750 },
|
||||
{ label: '1000kV', value: 1000 }
|
||||
]
|
||||
|
||||
const voltageDefaultMap = new Map<number, LineVoltageDefault>([
|
||||
[0.38, { capacity: 10, ptRatio: 380, pt2Ratio: 380 }],
|
||||
[6, { capacity: 100, ptRatio: 6000, pt2Ratio: 100 }],
|
||||
[10, { capacity: 100, ptRatio: 10000, pt2Ratio: 100 }],
|
||||
[20, { capacity: 200, ptRatio: 20000, pt2Ratio: 100 }],
|
||||
[35, { capacity: 250, ptRatio: 35000, pt2Ratio: 100 }],
|
||||
[66, { capacity: 500, ptRatio: 66000, pt2Ratio: 100 }],
|
||||
[110, { capacity: 750, ptRatio: 110000, pt2Ratio: 100 }],
|
||||
[220, { capacity: 2000, ptRatio: 220000, pt2Ratio: 100 }],
|
||||
[330, { capacity: 3000, ptRatio: 330000, pt2Ratio: 100 }],
|
||||
[500, { capacity: 4500, ptRatio: 500000, pt2Ratio: 100 }],
|
||||
[750, { capacity: 7000, ptRatio: 750000, pt2Ratio: 100 }],
|
||||
[1000, { capacity: 9000, ptRatio: 1000000, pt2Ratio: 100 }]
|
||||
])
|
||||
|
||||
const lineId = computed(() => localForm.line_id || localForm.id || '')
|
||||
const isSimpleMode = computed(() => props.mode === 'simple')
|
||||
const isOverlimitReadonly = computed(() => Boolean(props.readonly))
|
||||
const overlimitActionLabel = computed(() => (isOverlimitReadonly.value ? '限值查询' : '限值配置'))
|
||||
|
||||
const applyVoltageDefault = (voltage?: number) => {
|
||||
const preset = voltageDefaultMap.get(Number(voltage)) || { capacity: 10, ptRatio: undefined, pt2Ratio: undefined }
|
||||
|
||||
// 电压等级切换时按参考表同步默认容量和变比,保留用户后续手动调整入口。
|
||||
localForm.short_circuit_capacity = preset.capacity
|
||||
localForm.basic_capacity = preset.capacity
|
||||
localForm.protocol_capacity = preset.capacity
|
||||
localForm.dev_capacity = preset.capacity
|
||||
localForm.pt_ratio = preset.ptRatio
|
||||
localForm.pt2_ratio = preset.pt2Ratio
|
||||
localForm.ct_ratio = 300
|
||||
localForm.ct2_ratio = 5
|
||||
}
|
||||
|
||||
const handleVoltageChange = (value?: number) => {
|
||||
applyVoltageDefault(value)
|
||||
}
|
||||
|
||||
const syncLocalForm = (form: AddLedger.LineForm) => {
|
||||
localForm.id = form.id || ''
|
||||
@@ -234,6 +304,7 @@ const syncLocalForm = (form: AddLedger.LineForm) => {
|
||||
localForm.basic_capacity = form.basic_capacity
|
||||
localForm.protocol_capacity = form.protocol_capacity
|
||||
localForm.dev_capacity = form.dev_capacity
|
||||
localForm.lineType = form.lineType ?? 0
|
||||
localForm.monitor_obj = form.monitor_obj || ''
|
||||
localForm.is_govern = form.is_govern ?? 0
|
||||
localForm.monitor_user = form.monitor_user || ''
|
||||
|
||||
@@ -76,6 +76,10 @@
|
||||
row-gap: 2px;
|
||||
}
|
||||
|
||||
.ledger-line-form :deep(.ratio-form-item) {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.ledger-form.form-three :deep(.el-form-item),
|
||||
.ledger-form.form-simple :deep(.el-form-item) {
|
||||
width: 100%;
|
||||
@@ -105,6 +109,10 @@
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.ledger-line-form .ratio-input-group {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.ratio-input-group :deep(.ratio-field) {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
@@ -55,6 +55,12 @@ const expectations = [
|
||||
/\.ledger-line-form \.ratio-input-group :deep\(\.ratio-field\) \{[\s\S]*min-height:\s*32px;[\s\S]*margin-bottom:\s*0;[\s\S]*\}/.test(
|
||||
formStyleSource
|
||||
)
|
||||
],
|
||||
[
|
||||
'line form ratio group keeps compact single-row height',
|
||||
/\.ledger-line-form :deep\(\.ratio-form-item\)[\s\S]*height:\s*32px;[\s\S]*\.ledger-line-form \.ratio-input-group \{[\s\S]*height:\s*32px;[\s\S]*\}/.test(
|
||||
formStyleSource
|
||||
)
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/* eslint-env node */
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const currentDir = path.dirname(fileURLToPath(import.meta.url))
|
||||
const pageDir = path.resolve(currentDir, '..')
|
||||
|
||||
const lineFormSource = fs.readFileSync(path.join(pageDir, 'components', 'LineForm.vue'), 'utf8')
|
||||
const ledgerDataSource = fs.readFileSync(path.join(pageDir, 'utils', 'ledgerData.ts'), 'utf8')
|
||||
|
||||
const expectations = [
|
||||
['voltage preset table is maintained in LineForm', /const voltageDefaultMap = new Map<number, LineVoltageDefault>/.test(lineFormSource)],
|
||||
['0.38kV preset fills 10MVA capacities and 380:380 PT', /\[0\.38,\s*\{ capacity: 10, ptRatio: 380, pt2Ratio: 380 \}\]/.test(lineFormSource)],
|
||||
['6kV preset fills 100MVA capacities and 6000:100 PT', /\[6,\s*\{ capacity: 100, ptRatio: 6000, pt2Ratio: 100 \}\]/.test(lineFormSource)],
|
||||
['1000kV preset fills 9000MVA capacities and 1000000:100 PT', /\[1000,\s*\{ capacity: 9000, ptRatio: 1000000, pt2Ratio: 100 \}\]/.test(lineFormSource)],
|
||||
['voltage options include image reference levels', /const voltageOptions:[\s\S]*0\.38[\s\S]*6[\s\S]*10[\s\S]*20[\s\S]*35[\s\S]*66[\s\S]*110[\s\S]*220[\s\S]*330[\s\S]*500[\s\S]*750[\s\S]*1000/.test(lineFormSource)],
|
||||
['voltage change applies CT default 300:5', /localForm\.ct_ratio = 300[\s\S]*localForm\.ct2_ratio = 5/.test(lineFormSource)],
|
||||
['voltage change applies four capacity fields together', /localForm\.short_circuit_capacity = preset\.capacity[\s\S]*localForm\.basic_capacity = preset\.capacity[\s\S]*localForm\.protocol_capacity = preset\.capacity[\s\S]*localForm\.dev_capacity = preset\.capacity/.test(lineFormSource)],
|
||||
['voltage change applies PT ratio from preset', /localForm\.pt_ratio = preset\.ptRatio[\s\S]*localForm\.pt2_ratio = preset\.pt2Ratio/.test(lineFormSource)],
|
||||
['voltage select change triggers defaults', /@change="handleVoltageChange"/.test(lineFormSource)],
|
||||
['prop sync does not call voltage defaults', /const syncLocalForm = \(form: AddLedger\.LineForm\) => \{(?![\s\S]*applyVoltageDefault)[\s\S]*?\n\}/.test(lineFormSource)],
|
||||
['empty line defaults to 10kV', /vol_grade:\s*10/.test(ledgerDataSource)],
|
||||
['empty line defaults CT ratio to 300:5', /ct_ratio:\s*300[\s\S]*ct2_ratio:\s*5/.test(ledgerDataSource)],
|
||||
['empty line resolves 10kV voltage default', /const lineVoltageDefault = resolveLineVoltageDefault\(10\)/.test(ledgerDataSource)],
|
||||
['empty line loads 10kV PT ratio from voltage defaults', /pt_ratio:\s*lineVoltageDefault\.ptRatio[\s\S]*pt2_ratio:\s*lineVoltageDefault\.pt2Ratio/.test(ledgerDataSource)],
|
||||
['empty line loads 10kV capacity defaults', /short_circuit_capacity:\s*lineVoltageDefault\.capacity[\s\S]*basic_capacity:\s*lineVoltageDefault\.capacity[\s\S]*protocol_capacity:\s*lineVoltageDefault\.capacity[\s\S]*dev_capacity:\s*lineVoltageDefault\.capacity/.test(ledgerDataSource)],
|
||||
['line detail replaces legacy 1:1 ratio placeholders from voltage defaults', /const shouldUseVoltageRatioDefault =[\s\S]*left === undefined \|\| right === undefined \|\| \(left === 1 && right === 1\)/.test(ledgerDataSource)],
|
||||
['line detail replaces legacy 10MVA placeholders from voltage defaults', /const shouldUseVoltageCapacityDefault =[\s\S]*value === undefined \|\| value === 10/.test(ledgerDataSource)],
|
||||
['line detail normalization applies voltage defaults to loaded records', /const lineVoltageDefault = resolveLineVoltageDefault\(volGrade\)[\s\S]*ct_ratio: shouldUseVoltageRatioDefault\(ctRatio, ct2Ratio\) \? 300 : ctRatio[\s\S]*pt_ratio: shouldUseVoltageRatioDefault\(ptRatio, pt2Ratio\) \? lineVoltageDefault\.ptRatio : ptRatio[\s\S]*short_circuit_capacity: shouldUseVoltageCapacityDefault\(shortCircuitCapacity\)[\s\S]*\? lineVoltageDefault\.capacity[\s\S]*: shortCircuitCapacity/.test(ledgerDataSource)]
|
||||
]
|
||||
|
||||
const failures = expectations.filter(([, matched]) => !matched)
|
||||
|
||||
if (failures.length) {
|
||||
console.error('addLedger line voltage default contract check failed:')
|
||||
for (const [name] of failures) {
|
||||
console.error(`- ${name}`)
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log('addLedger line voltage default contract check passed')
|
||||
@@ -0,0 +1,66 @@
|
||||
/* eslint-env node */
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const currentDir = path.dirname(fileURLToPath(import.meta.url))
|
||||
const pageDir = path.resolve(currentDir, '..')
|
||||
const apiDir = path.resolve(pageDir, '..', '..', '..', 'api', 'tools', 'addLedger')
|
||||
|
||||
const apiSource = fs.readFileSync(path.join(apiDir, 'index.ts'), 'utf8')
|
||||
const interfaceSource = fs.readFileSync(path.join(apiDir, 'interface', 'index.ts'), 'utf8')
|
||||
const contextPanelSource = fs.readFileSync(path.join(pageDir, 'components', 'LedgerContextPanel.vue'), 'utf8')
|
||||
const equipmentFormSource = fs.readFileSync(path.join(pageDir, 'components', 'EquipmentForm.vue'), 'utf8')
|
||||
const lineFormSource = fs.readFileSync(path.join(pageDir, 'components', 'LineForm.vue'), 'utf8')
|
||||
const pageSource = fs.readFileSync(path.join(pageDir, 'index.vue'), 'utf8')
|
||||
|
||||
const expectations = [
|
||||
['API exposes equipment unit query endpoint', /\/equipment\/unit['"]/.test(apiSource)],
|
||||
['API exposes equipment unit save endpoint', /\/equipment\/unit\/save['"]/.test(apiSource)],
|
||||
['interfaces include equipment unit form type', /interface EquipmentUnitForm/.test(interfaceSource)],
|
||||
['line form type carries overlimit detail', /overlimit\?:\s*OverlimitDetail/.test(interfaceSource)],
|
||||
['equipment form opens unit debug dialog', /open-unit-debug/.test(equipmentFormSource)],
|
||||
['equipment form switches unit action label by readonly state', /unitActionLabel[\s\S]*\?\s*['"]单位查询['"]\s*:\s*['"]单位配置['"]/.test(equipmentFormSource)],
|
||||
['line form switches overlimit action label by readonly state', /overlimitActionLabel[\s\S]*\?\s*['"]限值查询['"]\s*:\s*['"]限值配置['"]/.test(lineFormSource)],
|
||||
[
|
||||
'equipment unit debug action is visible outside readonly edit actions',
|
||||
/<div class="form-actions">[\s\S]*open-unit-debug[\s\S]*<template v-if="!readonly">/.test(equipmentFormSource)
|
||||
],
|
||||
[
|
||||
'line overlimit action is visible outside readonly edit actions',
|
||||
/<div class="form-actions">[\s\S]*open-overlimit-debug[\s\S]*<template v-if="!readonly">/.test(lineFormSource)
|
||||
],
|
||||
['context panel wires editable unit config event', /open-unit-debug="devId\s*=>\s*emit\('open-unit-debug',\s*devId,\s*false\)"/.test(contextPanelSource)],
|
||||
['context panel wires readonly unit query event', /open-unit-debug="devId\s*=>\s*emit\('open-unit-debug',\s*devId,\s*true\)"/.test(contextPanelSource)],
|
||||
['context panel wires editable overlimit config event', /open-overlimit-debug="lineId\s*=>\s*emit\('open-overlimit-debug',\s*lineId,\s*false\)"/.test(contextPanelSource)],
|
||||
['context panel wires readonly overlimit query event', /open-overlimit-debug="lineId\s*=>\s*emit\('open-overlimit-debug',\s*lineId,\s*true\)"/.test(contextPanelSource)],
|
||||
[
|
||||
'equipment unit debug dialog uses two-column internal scroll form',
|
||||
/unit-debug-form[\s\S]*grid-template-columns:\s*repeat\(2,\s*minmax\(0,\s*1fr\)\)/.test(pageSource) &&
|
||||
/unit-debug-form[\s\S]*overflow-y:\s*auto/.test(pageSource)
|
||||
],
|
||||
[
|
||||
'overlimit debug dialog uses two-column internal scroll form instead of table',
|
||||
/class="overlimit-debug-form"/.test(pageSource) &&
|
||||
/overlimit-debug-form[\s\S]*grid-template-columns:\s*repeat\(2,\s*minmax\(0,\s*1fr\)\)/.test(pageSource) &&
|
||||
/overlimit-debug-form[\s\S]*overflow-y:\s*auto/.test(pageSource) &&
|
||||
!/<el-table v-else :data="overlimitDebug\.rows"/.test(pageSource)
|
||||
],
|
||||
[
|
||||
'overlimit debug dialog filters id and resolves chinese labels',
|
||||
/\.filter\(\(\[key,\s*value\]\)\s*=>\s*key\s*!==\s*['"]id['"][\s\S]*resolveOverlimitDebugLabel/.test(pageSource) &&
|
||||
/const overlimitDebugLabelMap[\s\S]*频率偏差限值[\s\S]*电压波动限值/.test(pageSource)
|
||||
]
|
||||
]
|
||||
|
||||
const failures = expectations.filter(([, matched]) => !matched)
|
||||
|
||||
if (failures.length) {
|
||||
console.error('addLedger unit and overlimit debug contract check failed:')
|
||||
for (const [name] of failures) {
|
||||
console.error(`- ${name}`)
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log('addLedger unit and overlimit debug contract check passed')
|
||||
@@ -54,6 +54,8 @@
|
||||
@save-project="handleSaveProject"
|
||||
@save-equipment="handleSaveEquipment"
|
||||
@save-line="handleSaveLine"
|
||||
@open-unit-debug="handleOpenUnitDebug"
|
||||
@open-overlimit-debug="handleOpenOverlimitDebug"
|
||||
@delete="handleDeleteNode"
|
||||
@add-project="handleAddProject"
|
||||
@add-equipment="handleAddEquipment"
|
||||
@@ -77,6 +79,53 @@
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="unitDebug.visible" :title="unitDebug.readonly ? '设备单位查询' : '设备单位配置'" width="760px" destroy-on-close>
|
||||
<el-form
|
||||
v-loading="unitDebug.loading"
|
||||
:model="unitDebug.form"
|
||||
label-width="150px"
|
||||
class="unit-debug-form"
|
||||
:disabled="unitDebug.loading || unitDebug.readonly"
|
||||
>
|
||||
<el-form-item v-for="item in unitDebugFields" :key="item.key" :label="item.label">
|
||||
<el-input v-model="unitDebug.form[item.key]" clearable maxlength="32" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="unitDebug.visible = false">{{ unitDebug.readonly ? '关闭' : '取消' }}</el-button>
|
||||
<el-button v-if="!unitDebug.readonly" type="primary" :loading="unitDebug.saving" @click="handleSaveUnitDebug">
|
||||
保存单位
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="overlimitDebug.visible"
|
||||
:title="overlimitDebug.readonly ? '监测点限值查询' : '监测点限值配置'"
|
||||
width="860px"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-empty v-if="!overlimitDebug.rows.length" description="当前监测点详情未返回限值数据" />
|
||||
<el-form v-else label-width="150px" class="overlimit-debug-form" :disabled="overlimitDebug.readonly">
|
||||
<el-form-item v-for="row in overlimitDebug.rows" :key="row.key" :label="row.label">
|
||||
<el-input
|
||||
v-if="!overlimitDebug.readonly"
|
||||
v-model="row.value"
|
||||
clearable
|
||||
maxlength="32"
|
||||
@change="value => handleOverlimitValueChange(row.key, value)"
|
||||
/>
|
||||
<span v-else class="debug-readonly-value">{{ row.value }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="overlimitDebug.visible = false">{{ overlimitDebug.readonly ? '关闭' : '取消' }}</el-button>
|
||||
<el-button v-if="!overlimitDebug.readonly" type="primary" @click="handleSaveOverlimitDebug">
|
||||
保存限值
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -87,10 +136,12 @@ import { CirclePlus } from '@element-plus/icons-vue'
|
||||
import {
|
||||
deleteAddLedgerNode,
|
||||
getAddLedgerDetail,
|
||||
getAddLedgerEquipmentUnit,
|
||||
getAddLedgerTree,
|
||||
getAvailableLineNos,
|
||||
saveAddLedgerEngineering,
|
||||
saveAddLedgerEquipment,
|
||||
saveAddLedgerEquipmentUnit,
|
||||
saveAddLedgerLine,
|
||||
saveAddLedgerProject
|
||||
} from '@/api/tools/addLedger'
|
||||
@@ -155,6 +206,59 @@ const projectForm = ref<AddLedger.ProjectForm>(createEmptyProjectForm())
|
||||
const equipmentForm = ref<AddLedger.EquipmentForm>(createEmptyEquipmentForm())
|
||||
const lineForm = ref<AddLedger.LineForm>(createEmptyLineForm())
|
||||
|
||||
const unitDebugFields: Array<{ key: keyof AddLedger.EquipmentUnitForm; label: string }> = [
|
||||
{ key: 'unitFrequency', label: '频率单位' },
|
||||
{ key: 'unitFrequencyDev', label: '频率偏差单位' },
|
||||
{ key: 'phaseVoltage', label: '相电压单位' },
|
||||
{ key: 'lineVoltage', label: '线电压单位' },
|
||||
{ key: 'voltageDev', label: '电压上偏差单位' },
|
||||
{ key: 'uvoltageDev', label: '电压下偏差单位' },
|
||||
{ key: 'ieffective', label: '电流有效值单位' },
|
||||
{ key: 'singleP', label: '单相有功功率单位' },
|
||||
{ key: 'singleViewP', label: '单相视在功率单位' },
|
||||
{ key: 'singleNoP', label: '单相无功功率单位' },
|
||||
{ key: 'totalActiveP', label: '总有功功率单位' },
|
||||
{ key: 'totalViewP', label: '总视在功率单位' },
|
||||
{ key: 'totalNoP', label: '总无功功率单位' },
|
||||
{ key: 'vfundEffective', label: '基波电压有效值单位' },
|
||||
{ key: 'ifund', label: '基波电流单位' },
|
||||
{ key: 'fundActiveP', label: '基波有功功率单位' },
|
||||
{ key: 'fundNoP', label: '基波无功功率单位' },
|
||||
{ key: 'vdistortion', label: '电压总谐波畸变率单位' },
|
||||
{ key: 'vharmonicRate', label: '谐波电压含有率单位' },
|
||||
{ key: 'iharmonic', label: '谐波电流单位' },
|
||||
{ key: 'pharmonic', label: '谐波有功功率单位' },
|
||||
{ key: 'iiharmonic', label: '间谐波电流单位' },
|
||||
{ key: 'positiveV', label: '正序电压单位' },
|
||||
{ key: 'noPositiveV', label: '零序/负序电压单位' }
|
||||
]
|
||||
|
||||
const unitDebug = reactive({
|
||||
visible: false,
|
||||
loading: false,
|
||||
saving: false,
|
||||
readonly: false,
|
||||
form: { devId: '' } as AddLedger.EquipmentUnitForm
|
||||
})
|
||||
|
||||
const overlimitDebug = reactive({
|
||||
visible: false,
|
||||
readonly: false,
|
||||
rows: [] as Array<{ key: string; label: string; value: string }>
|
||||
})
|
||||
|
||||
const overlimitDebugLabelMap: Record<string, string> = {
|
||||
freqDev: '频率偏差限值',
|
||||
voltageFluctuation: '电压波动限值',
|
||||
voltageDev: '电压上偏差限值',
|
||||
uvoltageDev: '电压下偏差限值',
|
||||
ubalance: '三相电压不平衡限值',
|
||||
shortUbalance: '短时电压不平衡限值',
|
||||
flicker: '闪变限值',
|
||||
uaberrance: '电压总谐波畸变率限值',
|
||||
iNeg: '负序电流限值'
|
||||
}
|
||||
|
||||
const draftIds = {
|
||||
engineering: '__draft_engineering__',
|
||||
project: '__draft_project__',
|
||||
@@ -847,6 +951,90 @@ const handleSaveLine = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleOpenUnitDebug = async (devIdFromForm = '', readonly = false) => {
|
||||
const devId = devIdFromForm || equipmentForm.value.id || selectedNode.value?.id || ''
|
||||
if (!devId) {
|
||||
ElMessage.warning('请先选择或保存设备后再查看单位配置')
|
||||
return
|
||||
}
|
||||
|
||||
unitDebug.visible = true
|
||||
unitDebug.loading = true
|
||||
unitDebug.readonly = readonly
|
||||
unitDebug.form = { devId }
|
||||
try {
|
||||
const response = await getAddLedgerEquipmentUnit({ devId })
|
||||
unitDebug.form = {
|
||||
...(response.data || {}),
|
||||
devId
|
||||
}
|
||||
} finally {
|
||||
unitDebug.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSaveUnitDebug = async () => {
|
||||
if (unitDebug.readonly) return
|
||||
if (!unitDebug.form.devId) return
|
||||
|
||||
unitDebug.saving = true
|
||||
try {
|
||||
await saveAddLedgerEquipmentUnit(unitDebug.form)
|
||||
ElMessage.success('设备单位保存成功')
|
||||
unitDebug.visible = false
|
||||
} finally {
|
||||
unitDebug.saving = false
|
||||
}
|
||||
}
|
||||
|
||||
const formatDebugValue = (value: unknown) => {
|
||||
if (value === null || value === undefined || value === '') return '--'
|
||||
return String(value)
|
||||
}
|
||||
|
||||
const resolveOverlimitDebugLabel = (key: string) => {
|
||||
const fixedLabel = overlimitDebugLabelMap[key]
|
||||
if (fixedLabel) return fixedLabel
|
||||
|
||||
const harmonicMatch = key.match(/^(uharm|iharm|inuharm)_?(\d+)$/)
|
||||
if (!harmonicMatch) return key
|
||||
|
||||
const [, type, order] = harmonicMatch
|
||||
if (type === 'uharm') return `${order}次谐波电压限值`
|
||||
if (type === 'iharm') return `${order}次谐波电流限值`
|
||||
return `${order}次间谐波电流限值`
|
||||
}
|
||||
|
||||
const handleOpenOverlimitDebug = (lineIdFromForm = '', readonly = false) => {
|
||||
const lineId = lineIdFromForm || lineForm.value.line_id || lineForm.value.id || selectedNode.value?.id || ''
|
||||
if (!lineId) {
|
||||
ElMessage.warning('请先选择或保存测点后再查看限值配置')
|
||||
return
|
||||
}
|
||||
|
||||
const overlimit = lineForm.value.overlimit || {}
|
||||
overlimitDebug.readonly = readonly
|
||||
overlimitDebug.rows = Object.entries(overlimit)
|
||||
.filter(([key, value]) => key !== 'id' && value !== undefined && value !== null && value !== '')
|
||||
.map(([key, value]) => ({
|
||||
key,
|
||||
label: resolveOverlimitDebugLabel(key),
|
||||
value: formatDebugValue(value)
|
||||
}))
|
||||
overlimitDebug.visible = true
|
||||
}
|
||||
|
||||
const handleOverlimitValueChange = (key: string, value: string) => {
|
||||
lineForm.value.overlimit = {
|
||||
...(lineForm.value.overlimit || {}),
|
||||
[key]: value
|
||||
}
|
||||
}
|
||||
|
||||
const handleSaveOverlimitDebug = () => {
|
||||
ElMessage.warning('限值由保存测点后自动重新计算,请保存测点以更新限值')
|
||||
}
|
||||
|
||||
const resolveActiveNodeId = () => {
|
||||
if (activeLevel.value === 0) return engineeringForm.value.id
|
||||
if (activeLevel.value === 1) return projectForm.value.id
|
||||
@@ -991,10 +1179,46 @@ onMounted(async () => {
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.unit-debug-form,
|
||||
.overlimit-debug-form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
max-height: 58vh;
|
||||
overflow-y: auto;
|
||||
column-gap: 18px;
|
||||
row-gap: 10px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
.unit-debug-form :deep(.el-form-item),
|
||||
.overlimit-debug-form :deep(.el-form-item) {
|
||||
min-width: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.unit-debug-form :deep(.el-input),
|
||||
.overlimit-debug-form :deep(.el-input) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.debug-readonly-value {
|
||||
min-width: 0;
|
||||
line-height: 32px;
|
||||
color: var(--el-text-color-primary);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.add-ledger-layout {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: minmax(260px, 0.45fr) minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.unit-debug-form,
|
||||
.overlimit-debug-form {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,6 +6,36 @@ export type LedgerContextIds = {
|
||||
deviceId: string
|
||||
}
|
||||
|
||||
type LineVoltageDefault = {
|
||||
capacity: number
|
||||
ptRatio?: number
|
||||
pt2Ratio?: number
|
||||
}
|
||||
|
||||
const lineVoltageDefaultMap = new Map<number, LineVoltageDefault>([
|
||||
[0.38, { capacity: 10, ptRatio: 380, pt2Ratio: 380 }],
|
||||
[6, { capacity: 100, ptRatio: 6000, pt2Ratio: 100 }],
|
||||
[10, { capacity: 100, ptRatio: 10000, pt2Ratio: 100 }],
|
||||
[20, { capacity: 200, ptRatio: 20000, pt2Ratio: 100 }],
|
||||
[35, { capacity: 250, ptRatio: 35000, pt2Ratio: 100 }],
|
||||
[66, { capacity: 500, ptRatio: 66000, pt2Ratio: 100 }],
|
||||
[110, { capacity: 750, ptRatio: 110000, pt2Ratio: 100 }],
|
||||
[220, { capacity: 2000, ptRatio: 220000, pt2Ratio: 100 }],
|
||||
[330, { capacity: 3000, ptRatio: 330000, pt2Ratio: 100 }],
|
||||
[500, { capacity: 4500, ptRatio: 500000, pt2Ratio: 100 }],
|
||||
[750, { capacity: 7000, ptRatio: 750000, pt2Ratio: 100 }],
|
||||
[1000, { capacity: 9000, ptRatio: 1000000, pt2Ratio: 100 }]
|
||||
])
|
||||
|
||||
const resolveLineVoltageDefault = (voltage?: number): LineVoltageDefault => {
|
||||
return lineVoltageDefaultMap.get(Number(voltage)) || { capacity: 10, ptRatio: undefined, pt2Ratio: undefined }
|
||||
}
|
||||
|
||||
const shouldUseVoltageRatioDefault = (left?: number, right?: number) =>
|
||||
left === undefined || right === undefined || (left === 1 && right === 1)
|
||||
|
||||
const shouldUseVoltageCapacityDefault = (value?: number) => value === undefined || value === 10
|
||||
|
||||
export function generateGuidText() {
|
||||
return window.crypto.randomUUID().replace(/-/g, '')
|
||||
}
|
||||
@@ -50,6 +80,8 @@ export function createEmptyEquipmentForm(parentProjectId = '', parentEngineering
|
||||
}
|
||||
|
||||
export function createEmptyLineForm(parentDeviceId = ''): AddLedger.LineForm {
|
||||
const lineVoltageDefault = resolveLineVoltageDefault(10)
|
||||
|
||||
return {
|
||||
id: '',
|
||||
line_id: '',
|
||||
@@ -58,16 +90,17 @@ export function createEmptyLineForm(parentDeviceId = ''): AddLedger.LineForm {
|
||||
name: '',
|
||||
line_no: undefined,
|
||||
conType: undefined,
|
||||
vol_grade: undefined,
|
||||
vol_grade: 10,
|
||||
position: '',
|
||||
ct_ratio: undefined,
|
||||
ct2_ratio: undefined,
|
||||
pt_ratio: undefined,
|
||||
pt2_ratio: undefined,
|
||||
short_circuit_capacity: undefined,
|
||||
basic_capacity: undefined,
|
||||
protocol_capacity: undefined,
|
||||
dev_capacity: undefined,
|
||||
ct_ratio: 300,
|
||||
ct2_ratio: 5,
|
||||
pt_ratio: lineVoltageDefault.ptRatio,
|
||||
pt2_ratio: lineVoltageDefault.pt2Ratio,
|
||||
short_circuit_capacity: lineVoltageDefault.capacity,
|
||||
basic_capacity: lineVoltageDefault.capacity,
|
||||
protocol_capacity: lineVoltageDefault.capacity,
|
||||
dev_capacity: lineVoltageDefault.capacity,
|
||||
lineType: 0,
|
||||
monitor_obj: '',
|
||||
is_govern: 0,
|
||||
monitor_user: '',
|
||||
@@ -211,6 +244,16 @@ export const normalizeLineDetail = (
|
||||
): AddLedger.LineForm => {
|
||||
const data = (detail || {}) as Record<string, unknown>
|
||||
const lineId = resolveString(data, 'line_id', 'lineId', 'id') || node?.id || generateGuidText()
|
||||
const volGrade = resolveNumber(data, 'vol_grade', 'volGrade') ?? 10
|
||||
const lineVoltageDefault = resolveLineVoltageDefault(volGrade)
|
||||
const ctRatio = resolveNumber(data, 'ct_ratio', 'ctRatio')
|
||||
const ct2Ratio = resolveNumber(data, 'ct2_ratio', 'ct2Ratio')
|
||||
const ptRatio = resolveNumber(data, 'pt_ratio', 'ptRatio')
|
||||
const pt2Ratio = resolveNumber(data, 'pt2_ratio', 'pt2Ratio')
|
||||
const shortCircuitCapacity = resolveNumber(data, 'short_circuit_capacity', 'shortCircuitCapacity')
|
||||
const basicCapacity = resolveNumber(data, 'basic_capacity', 'basicCapacity')
|
||||
const protocolCapacity = resolveNumber(data, 'protocol_capacity', 'protocolCapacity')
|
||||
const devCapacity = resolveNumber(data, 'dev_capacity', 'devCapacity')
|
||||
|
||||
return {
|
||||
id: resolveString(data, 'id') || lineId,
|
||||
@@ -220,20 +263,24 @@ export const normalizeLineDetail = (
|
||||
name: resolveString(data, 'name') || node?.name || '',
|
||||
line_no: resolveNumber(data, 'line_no', 'lineNo'),
|
||||
conType: resolveNumber(data, 'conType'),
|
||||
vol_grade: resolveNumber(data, 'vol_grade', 'volGrade'),
|
||||
vol_grade: volGrade,
|
||||
position: resolveString(data, 'position'),
|
||||
ct_ratio: resolveNumber(data, 'ct_ratio', 'ctRatio'),
|
||||
ct2_ratio: resolveNumber(data, 'ct2_ratio', 'ct2Ratio'),
|
||||
pt_ratio: resolveNumber(data, 'pt_ratio', 'ptRatio'),
|
||||
pt2_ratio: resolveNumber(data, 'pt2_ratio', 'pt2Ratio'),
|
||||
short_circuit_capacity: resolveNumber(data, 'short_circuit_capacity', 'shortCircuitCapacity'),
|
||||
basic_capacity: resolveNumber(data, 'basic_capacity', 'basicCapacity'),
|
||||
protocol_capacity: resolveNumber(data, 'protocol_capacity', 'protocolCapacity'),
|
||||
dev_capacity: resolveNumber(data, 'dev_capacity', 'devCapacity'),
|
||||
ct_ratio: shouldUseVoltageRatioDefault(ctRatio, ct2Ratio) ? 300 : ctRatio,
|
||||
ct2_ratio: shouldUseVoltageRatioDefault(ctRatio, ct2Ratio) ? 5 : ct2Ratio,
|
||||
pt_ratio: shouldUseVoltageRatioDefault(ptRatio, pt2Ratio) ? lineVoltageDefault.ptRatio : ptRatio,
|
||||
pt2_ratio: shouldUseVoltageRatioDefault(ptRatio, pt2Ratio) ? lineVoltageDefault.pt2Ratio : pt2Ratio,
|
||||
short_circuit_capacity: shouldUseVoltageCapacityDefault(shortCircuitCapacity)
|
||||
? lineVoltageDefault.capacity
|
||||
: shortCircuitCapacity,
|
||||
basic_capacity: shouldUseVoltageCapacityDefault(basicCapacity) ? lineVoltageDefault.capacity : basicCapacity,
|
||||
protocol_capacity: shouldUseVoltageCapacityDefault(protocolCapacity) ? lineVoltageDefault.capacity : protocolCapacity,
|
||||
dev_capacity: shouldUseVoltageCapacityDefault(devCapacity) ? lineVoltageDefault.capacity : devCapacity,
|
||||
lineType: resolveNumber(data, 'lineType', 'line_type') ?? 0,
|
||||
monitor_obj: resolveString(data, 'monitor_obj', 'monitorObj'),
|
||||
is_govern: resolveNumber(data, 'is_govern', 'isGovern') ?? 0,
|
||||
monitor_user: resolveString(data, 'monitor_user', 'monitorUser'),
|
||||
is_important: resolveNumber(data, 'is_important', 'isImportant') ?? 0
|
||||
is_important: resolveNumber(data, 'is_important', 'isImportant') ?? 0,
|
||||
overlimit: (data.overlimit || data.overLimit) as AddLedger.OverlimitDetail | undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user