<script lang="ts" setup name="ConfigDev"> import type { Ref } from 'vue' import { nextTick, reactive } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus' import type { DictCodeInfo } from '../system/dict/dict-interface' import type { DevInfo, DevListInfo } from './dev-interface' import { addDev, configDev, getDevInfo } from '@/api/ptz/dev' import { getDictByCode } from '@/api/system/dict' import { isInRange, isInRangeNum } from '@/utils/validate' const emits = defineEmits(['closeRefresh']) // 对话框类型:create,update const dialogStatus = ref('create') const dialogVisible = ref(false) // 显示标题 const textMap: { [key: string]: string } = { detail: '详情', update: '全局配置设备', create: '新增', } // 表单数据对象 const formData: Ref<DevInfo> = ref({ id: '', stationId: '', stationName: '', monitorName: '', deviceIp: '', devicePort: '', deviceUser: '', devicePassword: '', nvrIp: '', nvrPort: '', nvrUser: '', nvrPassword: '', nvrChannel: '', deviceType: '', deviceTypeName: '', doorIp: '', doorSn: '', longitude: '', latitude: '', description: '', location: '', speed: 0, stopTime: 0, high: 0, angle: 0, deviceStatus: '', deviceStatusName: '', }) // 保存按钮加载状态 const btnLoading = ref(false) // ---------------表单提交-------------------------------- const isInRangeV = function (min: number, max: number) { return function (rule: any, value: any, callback: any) { if (isInRange(value, min, max)) { callback() } else { callback(new Error(`请输入${min.toString()}-${max.toString()}整数`)) } callback() } } const isInRangeNumV = function (min: number, max: number, length: number) { return function (rule: any, value: any, callback: any) { if (isNaN(value)) { callback(new Error(`请输入${min.toString()}-${max.toString()}范围${length}位小数`)) } else if (isInRangeNum(Number(value), min, max)) { if (value.toString().includes('.') && value.toString().split('.')[1].length > length) { callback(new Error(`请输入${min.toString()}-${max.toString()}范围${length}位小数`)) } callback() } else { callback(new Error(`请输入${min.toString()}-${max.toString()}范围${length}位小数`)) } callback() } } // 表单对象 const configFormRef = ref<FormInstance>() // 校验规则 const rules = reactive<FormRules>({ speed: [{ type: 'number', required: true, message: '请输入合法巡航速度(1-63整数)', trigger: ['blur'], validator: isInRangeV(1, 63) }], stopTime: [{ type: 'number', required: true, message: '请输入合法停留时间(0-255整数)', trigger: ['blur'], validator: isInRangeV(0, 255) }], high: [{ type: 'number', required: true, message: '请输入合法报警阈值(0-10000整数)', trigger: ['blur'], validator: isInRangeV(0, 10000) }], angle: [{ type: 'number', required: true, message: '请输入合法扫描角度(0.1-25.5一位小数)', trigger: ['blur'], validator: isInRangeNumV(0.1, 25.5, 1) }], }) const deviceTypeList = ref<DictCodeInfo[]>([]) // 字典值 function getDict() { getDictByCode('deviceType').then((response) => { deviceTypeList.value = response.data }) } // 表单提交 function submitForm() { if (configFormRef) { configFormRef.value?.validate((valid: boolean) => { if (valid) { if (dialogStatus.value === 'create') { createData() } else if (dialogStatus.value === 'update') { updateData() } } }) } } // 新增数据 function createData() { btnLoading.value = true addDev(formData.value).then((res) => { ElMessageBox.confirm( '新增成功,是否继续新增?', '提示', { confirmButtonText: '是', cancelButtonText: '否', type: 'info', }, ).then(() => { resetForm() }).catch(() => { closeRefresh() }) btnLoading.value = false }).catch((_) => { btnLoading.value = false }) } // 更新数据 function updateData() { const angle = formData.value.angle formData.value.angle = Number.parseInt(formData.value.angle * 10) configDev(formData.value).then((res) => { formData.value.angle = angle ElMessage.success('全局配置成功') btnLoading.value = false closeRefresh() }).catch((_) => { // 异常情况,loading置为false formData.value.angle = angle btnLoading.value = false }) formData.value.angle = angle } // 重置表单 function resetForm() { formData.value = { id: '', stationId: '', stationName: '', monitorName: '', deviceIp: '', devicePort: '', deviceUser: '', devicePassword: '', nvrIp: '', nvrPort: '', nvrUser: '', nvrPassword: '', nvrChannel: '', deviceType: '', deviceTypeName: '', doorIp: '', doorSn: '', longitude: '', latitude: '', description: '', location: '', speed: 0, stopTime: 0, high: 0, angle: 0, deviceStatus: '', deviceStatusName: '', } } // ----------初始化、关闭对话框相关----------------- function initDialog(dialogstatus: string, row: DevListInfo) { dialogStatus.value = dialogstatus dialogVisible.value = true btnLoading.value = false if (dialogstatus === 'create') { resetForm() nextTick(() => { configFormRef.value?.clearValidate() }) } else if (dialogstatus === 'update' || dialogstatus === 'detail') { nextTick(() => { configFormRef.value?.clearValidate() }) getDev(row.id) } } function getDev(id: string) { getDevInfo(id).then((response) => { formData.value = response.data if (formData.value.angle !== '' && formData.value.angle !== undefined && formData.value.angle !== null) { formData.value.angle = Number(formData.value.angle) / 10 } }) } // 关闭并刷新 function closeRefresh() { dialogVisible.value = false resetForm() emits('closeRefresh') } // 关闭弹窗 function dialogClose() { dialogVisible.value = false resetForm() closeRefresh() } onMounted(() => { getDict() }) // ----------------------- 以下是暴露的方法内容 ---------------------------- defineExpose({ initDialog }) </script> <template> <el-dialog v-model="dialogVisible" :title="textMap[dialogStatus]" width="50%" :before-close="dialogClose" append-to-body :open-delay="0" :close-on-click-modal="false" > <el-form ref="configFormRef" :model="formData" :rules="rules" label-position="left" label-width="150px" class="form-container" size="default" @submit.prevent > <el-row :gutter="10"> <el-col :span="20" :offset="2" class="grid-cell"> <el-form-item label="默认巡航速度(m/s)" prop="speed" class="required"> <el-input v-model="formData.speed" type="text" placeholder="必填" /> </el-form-item> </el-col> <el-col :span="20" :offset="2" class="grid-cell"> <el-form-item label="默认停留时间(s)" prop="stopTime" class="required"> <el-input v-model="formData.stopTime" type="text" placeholder="必填" /> </el-form-item> </el-col> <el-col :span="20" :offset="2" class="grid-cell"> <el-form-item label="默认报警值(ppm·m)" prop="high" class="required"> <el-input v-model="formData.high" type="text" placeholder="必填" /> </el-form-item> </el-col> <el-col :span="20" :offset="2" class="grid-cell"> <el-form-item label="局部扫描角度(°)" prop="angle" class="required"> <el-input v-model="formData.angle" type="text" placeholder="必填" /> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <div v-show="dialogStatus !== 'detail'" class="dialog-footer"> <el-button :loading="btnLoading" type="primary" @click="submitForm"> 保存 </el-button> <el-button @click="dialogClose"> 取消 </el-button> </div> </template> </el-dialog> </template> <style lang="scss" scoped> .form-container { width: 100%; .full-width-input { width: 100%; } .dict-detail { padding: 10px; .title { font-size: 16px; font-weight: bold; margin-bottom: 15px; } } } </style>