Files
pqs-9100_client/frontend/src/views/machine/device/components/monitorPopup.vue

486 lines
19 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>
<!-- 基础信息弹出框 -->
<el-dialog
:model-value="dialogVisible"
:title="dialogTitle"
v-bind="dialogMiddle"
width="50%"
@close="close"
align-center
>
<div>
<el-form :model="formContent" ref="dialogFormRef" :rules="rules" label-width="140" class="form-two">
<el-form-item label="名称" prop="name">
<el-input clearable v-model="formContent.name" placeholder="请输入监测点名称" :disabled=" formContent.resultType!=null"/>
</el-form-item>
<el-form-item label="线路号" prop="num">
<el-select v-model="formContent.num" placeholder="请选择线路号" @change="handleMonNumChange" :disabled=" formContent.resultType!=null">
<el-option v-for="item in lineNum" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="母线名称" prop="busbar">
<el-input v-model="formContent.busbar" clearable placeholder="请输入所属母线" :disabled=" formContent.resultType!=null"/>
</el-form-item>
<!-- <el-form-item label="母线名称" prop="busbar">
<el-select
v-model="formContent.busbar"
clearable
placeholder="请选择所属母线"
filterable
allow-create
>
<el-option
v-for="item in selectOptions['busbar']"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item> -->
<el-form-item label="接线方式" prop="connection">
<el-select v-model="formContent.connection" clearable placeholder="请选择接线方式" :disabled=" formContent.resultType!=null">
<el-option
v-for="item in dictStore.getDictData('Dev_Connect')"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item required>
<template #label>
<div style="display: flex; align-items: center">
<el-icon style="color: var(--el-color-error)"><WarningFilled /></el-icon>
<span>PT变比</span>
</div>
</template>
<div class="ratio-input-group">
<el-form-item prop="ptPrimary" class="ratio-form-item">
<el-input v-model="ptPrimary" placeholder="一次侧" @input="handlePtInput" :disabled=" formContent.resultType!=null"/>
</el-form-item>
<div class="colon">:</div>
<el-form-item prop="ptSecondary" style="margin-left: 10px" class="ratio-form-item">
<el-input v-model="ptSecondary" placeholder="二次侧" @input="handlePtInput" :disabled=" formContent.resultType!=null"/>
</el-form-item>
</div>
</el-form-item>
<!-- 修改CT变比部分 -->
<el-form-item required>
<template #label>
<div style="display: flex; align-items: center">
<el-icon style="color: var(--el-color-error)"><WarningFilled /></el-icon>
<span>CT变比</span>
</div>
</template>
<div class="ratio-input-group">
<el-form-item prop="ctPrimary" class="ratio-form-item">
<el-input v-model="ctPrimary" placeholder="一次侧" @input="handleCtInput" :disabled=" formContent.resultType!=null"/>
</el-form-item>
<div class="colon">:</div>
<el-form-item prop="ctSecondary" style="margin-left: 10px" class="ratio-form-item">
<el-input v-model="ctSecondary" placeholder="二次侧" @input="handleCtInput" :disabled=" formContent.resultType!=null"/>
</el-form-item>
</div>
</el-form-item>
<el-form-item label="统计间隔" prop="statInterval">
<el-select v-model="formContent.statInterval" clearable placeholder="请选择统计间隔" :disabled=" formContent.resultType!=null">
<el-option
v-for="item in dictStore.getDictData('Dev_Chns')"
:key="item.id"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
<el-form-item label="谐波系统检测点id" prop="harmSysId" placeholder="请输入谐波系统检测点id">
<el-input v-model="formContent.harmSysId" :disabled=" formContent.resultType!=null"/>
</el-form-item>
<el-form-item label="是否参与检测" prop="checkFlag" placeholder="请输入CT编号">
<el-select v-model="formContent.checkFlag" :disabled="formContent.resultType!=null">
<el-option label="是" :value="1"></el-option>
<el-option label="否" :value="0"></el-option>
</el-select>
</el-form-item>
</el-form>
</div>
<el-alert
title="注意PT和CT变比请输入正常值不可以缩小相同的倍数"
type="error"
:closable="false"
></el-alert>
<template #footer>
<div class="dialog-footer">
<el-button @click="close()">取消</el-button>
<el-button type="primary" @click="save()">保存</el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ElMessage, ElMessageBox, type FormItemRule } from 'element-plus'
import { computed, ref, type Ref } from 'vue'
import { type Monitor } from '@/api/device/interface/monitor'
import { dialogMiddle } from '@/utils/elementBind'
import { useDictStore } from '@/stores/modules/dict'
import { generateUUID } from '@/utils'
import { type Device } from '@/api/device/interface/device'
const dictStore = useDictStore()
const lineNum = ref<{ id: number; name: string }[]>([])
const originalNum = ref<number | null>(null) // 存储编辑前的 num 值
const monitorTable = ref<any[]>()
const selectOptions = ref<Record<string, Device.SelectOption[]>>({})
// 新增用于PT/CT变比的临时字段
const ptPrimary = ref<string>('')
const ptSecondary = ref<string>('')
const ctPrimary = ref<string>('')
const ctSecondary = ref<string>('')
// 定义 props
const props = defineProps<{
DevFormContent: Device.ResPqDev
}>()
// 定义弹出组件元信息
const dialogFormRef = ref()
function useMetaInfo() {
const dialogVisible = ref(false)
const titleType = ref('add')
const formContent = ref<Monitor.ResPqMon>({
id: '',
devId: '',
busbar: '',
name: '',
num: 1,
pt: '',
ct: '',
connection: '',
statInterval: 1,
harmSysId: '',
checkFlag: 1
})
return { dialogVisible, titleType, formContent }
}
const { dialogVisible, titleType, formContent } = useMetaInfo()
const emit = defineEmits(['get-parameter'])
// 清空formContent
const resetFormContent = () => {
formContent.value = {
id: '',
devId: '',
busbar: '',
name: '',
num: 1,
pt: '',
ct: '',
connection: '',
statInterval: 1,
harmSysId: '',
checkFlag: 1,
resultType: null
}
}
let dialogTitle = computed(() => {
return titleType.value === 'add' ? '新增监测点台账' : '编辑监测点台账'
})
// 关闭弹窗
const close = () => {
dialogVisible.value = false
}
//定义校验规则
const rules: Ref<Record<string, Array<FormItemRule>>> = ref({
name: [{ required: true, message: '监测点名称必填!', trigger: 'blur' }],
num: [{ required: true, message: '线路号必选', trigger: 'change' }],
connection: [{ required: true, message: '接线方式必选!', trigger: 'change' }],
//busbar: [{ required: true, message: '所属母线必选!', trigger: 'change' }],
busbar: [{ required: true, message: '所属母线必填!', trigger: 'blur' }],
// harmSysId : [{ required: true, message: '谐波系统检测点id必填', trigger: 'blur' }],
checkFlag: [{ required: true, message: '是否参与检测必选!', trigger: 'change' }]
})
// 处理PT输入变化并更新formContent中的值
const handlePtInput = () => {
if (ptPrimary.value && ptSecondary.value) {
formContent.value.pt = `${ptPrimary.value}:${ptSecondary.value}`
} else {
formContent.value.pt = ''
}
}
// 处理CT输入变化并更新formContent中的值
const handleCtInput = () => {
if (ctPrimary.value && ctSecondary.value) {
formContent.value.ct = `${ctPrimary.value}:${ctSecondary.value}`
} else {
formContent.value.ct = ''
}
}
// 添加一个用于手动验证的引用
const extraFormRules = ref({
ptPrimary: [
{ required: true, message: 'PT变比一次侧必填', trigger: 'blur' },
{ pattern: /^[1-9]\d*$/, message: '请输入正整数', trigger: 'blur' }
],
ptSecondary: [
{ required: true, message: 'PT变比二次侧必填', trigger: 'blur' },
{ pattern: /^\d+(\.\d+)?$/, message: '请输入数字', trigger: 'blur' }
],
ctPrimary: [
{ required: true, message: 'CT变比一次侧必填', trigger: 'blur' },
{ pattern: /^[1-9]\d*$/, message: '请输入正整数', trigger: 'blur' }
],
ctSecondary: [
{ required: true, message: 'CT变比二次侧必填', trigger: 'blur' },
{ pattern: /^[1-9]\d*$/, message: '请输入正整数', trigger: 'blur' }
]
})
// 保存数据
const save = () => {
try {
dialogFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
// 手动验证额外的字段
let extraValid = true
const fieldsToValidate = ['ptPrimary', 'ptSecondary', 'ctPrimary', 'ctSecondary']
for (const field of fieldsToValidate) {
const value = eval(field) // 获取对应字段的值
const rules = extraFormRules.value[field]
for (const rule of rules) {
if (rule.required && !value.value) {
ElMessage.error({ message: rule.message as string })
extraValid = false
break
}
if (rule.pattern && value.value && !rule.pattern.test(value.value)) {
ElMessage.error({ message: rule.message as string })
extraValid = false
break
}
}
if (!extraValid) break
}
if (!extraValid) {
return
}
// 校验名称是否重复
const isNameDuplicate = monitorTable.value?.some(
item => item.name === formContent.value.name && item.id !== formContent.value.id
)
if (isNameDuplicate) {
ElMessage.error({ message: '监测点名称已存在,请重新输入!' })
return
}
// 添加PT CT逻辑
// PT 逻辑
let ptPrimaryValue = ptPrimary.value
let ptSecondaryValue = ptSecondary.value
let ptErrorTips = false
let ctErrorTips = false
const ptFinalValue = ['100', '380']
const ptFinalChangeValue = ['57.74', '220']
const ctFinalValue = ['1', '5']
// 若值都为 1 则改值为 380
if (ptPrimaryValue === '1' && ptSecondaryValue === '1') {
formContent.value.pt = `${ptFinalValue[1]}:${ptFinalValue[1]}`
} else {
// 若PT分母值不为 ['100', '380']
if (!ptFinalValue.includes(ptSecondaryValue)) {
// 若PT分母值不为 ['57.74', '220'],提示
if (ptFinalChangeValue.includes(ptSecondaryValue)) {
// 判断值为 57.74,则 57.74 => 100
if (ptSecondaryValue === ptFinalChangeValue[0]) {
ptSecondaryValue = ptFinalValue[0]
}
// 判断值为 220,则 220 => 380
if (ptSecondaryValue === ptFinalChangeValue[1]) {
ptSecondaryValue = ptFinalValue[1]
}
} else {
ptErrorTips = true
}
}
}
formContent.value.pt = `${ptPrimaryValue}:${ptSecondaryValue}`
// CT 逻辑, CT 分母是否为 ['1', '5']
if (!ctFinalValue.includes(ctSecondary.value)) {
ctErrorTips = true
}
if (ptErrorTips && ctErrorTips) {
await ElMessageBox.confirm('请确认PT和CT无误', '提示', {
confirmButtonText: '继续保存',
cancelButtonText: '取消保存'
})
.then(() => {
sendParameter()
})
.catch(() => {
return
})
} else {
if (ptErrorTips) {
await ElMessageBox.confirm('请确认PT无误', '提示', {
confirmButtonText: '继续保存',
cancelButtonText: '取消保存'
})
.then(() => {
sendParameter()
})
.catch(() => {
return
})
}
if (ctErrorTips) {
await ElMessageBox.confirm('请确认CT无误', '提示', {
confirmButtonText: '确认保存',
cancelButtonText: '取消保存'
})
.then(() => {
sendParameter()
})
.catch(() => {
return
})
}
}
if (!ptErrorTips && !ctErrorTips) {
sendParameter()
}
}
})
} catch (err) {
console.error('验证过程中出现错误', err)
}
}
const sendParameter = () => {
if (titleType.value != 'edit') {
formContent.value.id = generateUUID().replaceAll('-', '')
}
emit('get-parameter', formContent.value)
//ElMessage.success({ message: `${dialogTitle.value}成功!` })
close()
}
// 打开弹窗,可能是新增,也可能是编辑
const open = async (sign: string, data: Monitor.ResPqMon, device: Device.ResPqDev, table: any[], options: any) => {
selectOptions.value = options
titleType.value = sign
dialogVisible.value = true
monitorTable.value = table || []
// 提取 table 中已使用的 num安全处理
const usedNums = new Set<number>()
if (table && table.length > 0) {
table.forEach(item => {
if (item.num != null) {
usedNums.add(Number(item.num))
}
})
}
lineNum.value = Array.from({ length: device.devChns }, (_, i) => {
const id = i + 1
return {
id,
name: id.toString()
}
}).filter(item => !usedNums.has(item.id)) // 过滤掉已被使用的线路号
if (sign == 'edit') {
formContent.value = { ...data }
originalNum.value = data.num // 记录原始线路号
// 解析PT变比
if (data.pt) {
const [primary, secondary] = data.pt.split(':')
ptPrimary.value = primary
ptSecondary.value = secondary
}
// 解析CT变比
if (data.ct) {
const [primary, secondary] = data.ct.split(':')
ctPrimary.value = primary
ctSecondary.value = secondary
}
} else {
// 清空PT和CT的临时变量
ptPrimary.value = ''
ptSecondary.value = ''
ctPrimary.value = ''
ctSecondary.value = ''
// 重置表单内容但保留devId
const devId = formContent.value.devId
resetFormContent()
formContent.value.devId = devId
originalNum.value = null
// 使用nextTick确保DOM更新后再清除验证
setTimeout(() => {
dialogFormRef.value?.clearValidate()
}, 0)
// 设置默认选中第一个线路号
if (lineNum.value.length > 0) {
formContent.value.num = lineNum.value[0].id
}
}
formContent.value.devId = device.id
}
const handleMonNumChange = (value: string) => {
const newValue = parseInt(value)
if (originalNum.value && originalNum.value !== newValue) {
// 将原来的 num 添加回 lineNum表示释放
lineNum.value.push({
id: originalNum.value,
name: originalNum.value.toString()
})
//移除新选择的 num因为已被占用
lineNum.value = lineNum.value.filter(item => item.id !== newValue).sort((a, b) => a.id - b.id)
// 更新 originalNum 为最新值,以便下次修改
originalNum.value = newValue
}
}
// 对外映射
defineExpose({ open })
</script>
<style scoped>
.ratio-input-group {
display: flex;
align-items: center;
justify-content: space-between;
}
.ratio-form-item {
margin-bottom: 0 !important;
}
.colon {
text-align: center;
font-size: 16px;
font-weight: bold;
}
.el-alert {
--el-alert-padding: 0px 12px !important;
--el-alert-title-font-size: 12px !important;
}
</style>