Newer
Older
laserPTZFrontV2.0 / src / views / device / editDev.vue
wangxitong on 22 May 2023 16 KB first commit
<script lang="ts" setup name="EditDev">
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, StationListInfo } from './dev-interface'
import { addDev, getDevInfo, updateDev } from '@/api/ptz/dev'
import { getDictByCode } from '@/api/system/dict'
import { isInRange, isInRangeNum, isIp, isPort } from '@/utils/validate'
import { getStationList } from '@/api/ptz/station'
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 isIpV = (rule: any, value: any, callback: any) => {
  if (value === '') {
    callback(new Error('Something went wrong!'))
  }
  else if (isIp(value)) {
    callback()
  }
  else {
    callback(new Error('IP不合法'))
  }
  callback()
}

const isPortV = (rule: any, value: any, callback: any) => {
  if (value === '') {
    callback(new Error('Something went wrong!'))
  }
  else if (isPort(value)) {
    callback()
  }
  else {
    callback(new Error('端口号不合法'))
  }
  callback()
}
const isInRangeV = function (min: number, max: number) {
  return function (rule: any, value: any, callback: any) {
    if (value === '') {
      callback(new Error(`请输入${min.toString()}-${max.toString()}整数`))
    }
    else if (isInRange(value, min, max)) {
      callback()
    }
    else {
      callback(new Error(`请输入${min.toString()}-${max.toString()}整数`))
    }
    callback()
  }
}

const isInRangeNumV = function (min: number, max: number) {
  return function (rule: any, value: any, callback: any) {
    if (value === '') {
      callback(new Error(`请输入${min.toString()}-${max.toString()}小数`))
    }
    else if (isNaN(value)) {
      callback(new Error(`请输入${min.toString()}-${max.toString()}小数`))
    }
    else if (isInRangeNum(Number(value), min, max)) {
      callback()
    }
    else {
      callback(new Error(`请输入${min.toString()}-${max.toString()}小数`))
    }
    callback()
  }
}

// 表单对象
const dataFormRef = ref<FormInstance>()
// 校验规则
const rules = reactive<FormRules>({
  monitorName: [{ required: true, message: '设备名称不能为空', trigger: ['blur', 'change'] }],
  stationId: [{ required: true, message: '所在场站不能为空', trigger: ['blur', 'change'] }],
  deviceIp: [{ required: true, message: '请输入合法云台登录地址', trigger: ['blur', 'change'], validator: isIpV }],
  devicePort: [{ required: true, message: '请输入合法端口号', trigger: ['blur', 'change'], validator: isPortV }],
  deviceUser: [{ required: true, message: '云台登录账号不能为空', trigger: ['blur', 'change'] }],
  devicePassword: [{ required: true, message: '云台登录密码不能为空', trigger: ['blur', 'change'] }],
  nvrIp: [{ required: true, message: '请输入合法NVR登录地址', trigger: ['blur', 'change'], validator: isIpV }],
  nvrPort: [{ required: true, message: '请输入合法端口号', trigger: ['blur', 'change'], validator: isPortV }],
  nvrUser: [{ required: true, message: 'NVR登录账号不能为空', trigger: ['blur', 'change'] }],
  nvrPassword: [{ required: true, message: 'NVR登录密码不能为空', trigger: ['blur', 'change'] }],
  nvrChannel: [{ required: true, message: '请输入合法NVR通道号', trigger: ['blur', 'change'], validator: isInRangeV(0, 63) }],
  deviceType: [{ required: true, message: '设备型号不能为空', trigger: ['blur', 'change'] }],
  doorIp: [{ required: true, message: '控制开关IP不能为空', trigger: ['blur', 'change'], validator: isIpV }],
  doorSn: [{ required: true, message: '控制开关SN码不能为空', trigger: ['blur', 'change'] }],
  longitude: [{ required: true, message: '请输入合法经度', trigger: ['blur', 'change'], validator: isInRangeNumV(0, 200) }],
  latitude: [{ required: true, message: '请输入合法纬度', trigger: ['blur', 'change'], validator: isInRangeNumV(0, 200) }],
})

const deviceTypeList = ref<DictCodeInfo[]>([]) // 字典值
function getDict() {
  getDictByCode('deviceType').then((response) => {
    deviceTypeList.value = response.data
  })
}

// 获取场站列表
const stationList: Ref<StationListInfo[]> = ref([])
function fetchStationList() {
  getStationList().then((res) => {
    stationList.value = res.data
  })
}

// 表单提交
function submitForm() {
  if (dataFormRef) {
    dataFormRef.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() {
  updateDev(formData.value).then((res) => {
    ElMessage.success('修改成功')
    btnLoading.value = false
    closeRefresh()
  }).catch((_) => { // 异常情况,loading置为false
    btnLoading.value = false
  })
}

// 重置表单
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(() => {
      dataFormRef.value?.clearValidate()
    })
  }
  else if (dialogstatus === 'update' || dialogstatus === 'detail') {
    nextTick(() => {
      dataFormRef.value?.clearValidate()
    })
    getDev(row.id)
  }
}

function getDev(id: string) {
  getDevInfo(id).then((response) => {
    formData.value.id = response.data.id
    formData.value.stationId = response.data.stationId
    formData.value.stationName = response.data.stationName
    formData.value.monitorName = response.data.monitorName
    formData.value.deviceIp = response.data.deviceIp
    formData.value.devicePort = response.data.devicePort
    formData.value.deviceUser = response.data.deviceUser
    formData.value.devicePassword = response.data.devicePassword
    formData.value.nvrIp = response.data.nvrIp
    formData.value.nvrPort = response.data.nvrPort
    formData.value.nvrUser = response.data.nvrUser
    formData.value.nvrPassword = response.data.nvrPassword
    formData.value.nvrChannel = response.data.nvrChannel
    formData.value.deviceType = response.data.deviceType
    formData.value.deviceTypeName = response.data.deviceTypeName
    formData.value.doorIp = response.data.doorIp
    formData.value.doorSn = response.data.doorSn
    formData.value.longitude = response.data.longitude
    formData.value.latitude = response.data.latitude
    formData.value.description = response.data.description
    formData.value.location = response.data.location
    formData.value.deviceStatus = response.data.deviceStatus
    formData.value.deviceStatusName = response.data.deviceStatusName
    formData.value.deviceTypeName = deviceTypeList.value.filter(item => item.value === formData.value.deviceType)[0].name
  })
}

function selectStation() {
  formData.value.stationName = stationList.value.filter(item => item.id === formData.value.stationId)[0].stationName
}
function selectType() {
  formData.value.deviceTypeName = deviceTypeList.value.filter(item => item.value === formData.value.deviceType)[0].name
}
// 关闭并刷新
function closeRefresh() {
  dialogVisible.value = false
  resetForm()
  emits('closeRefresh')
}
// 关闭弹窗
function dialogClose() {
  dialogVisible.value = false
  resetForm()
  closeRefresh()
}

onMounted(() => {
  fetchStationList()
  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="dataFormRef" :model="formData" :rules="rules" label-position="left" label-width="110px"
      class="form-container" size="default" @submit.prevent
    >
      <el-row :gutter="10">
        <el-col :span="12" class="grid-cell">
          <el-form-item label="设备名称" prop="monitorName" class="required">
            <el-input
              v-model="formData.monitorName" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="所在场站" prop="stationId" class="required">
            <el-select
              v-model="formData.stationId" :disabled="dialogStatus === 'detail'" placeholder="必选"
              style="width: 100%;" @change="selectStation"
            >
              <el-option v-for="item in stationList" :key="item.id" :label="item.stationName" :value="item.id" />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="云台登录地址" prop="deviceIp" class="required">
            <el-input
              v-model="formData.deviceIp" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="云台登录端口" prop="devicePort" class="required">
            <el-input
              v-model="formData.devicePort" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="云台登录账号" prop="deviceUser" class="required">
            <el-input
              v-model="formData.deviceUser" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="云台登录密码" prop="devicePassword" class="required">
            <el-input
              v-model="formData.devicePassword" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="NVR登录地址" prop="nvrIp" class="required">
            <el-input
              v-model="formData.nvrIp" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="NVR登录端口" prop="nvrPort" class="required">
            <el-input
              v-model="formData.nvrPort" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="NVR登录账号" prop="nvrUser" class="required">
            <el-input
              v-model="formData.nvrUser" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="NVR登录密码" prop="nvrPassword" class="required">
            <el-input
              v-model="formData.nvrPassword" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="NVR通道号" prop="nvrChannel" class="required">
            <el-input
              v-model="formData.nvrChannel" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="设备类型" prop="deviceType" class="required">
            <el-select
              v-model="formData.deviceType" :disabled="dialogStatus === 'detail'" placeholder="必选"
              style="width: 100%;" @change="selectType"
            >
              <el-option v-for="item in deviceTypeList" :key="item.value" :label="item.name" :value="item.value" />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="控制开关IP" prop="doorIp" class="required">
            <el-input
              v-model="formData.doorIp" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="控制开关SN" prop="doorSn" class="required">
            <el-input
              v-model="formData.doorSn" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="经度" prop="longitude" class="required">
            <el-input
              v-model="formData.longitude" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="纬度" prop="latitude" class="required">
            <el-input
              v-model="formData.latitude" :disabled="dialogStatus === 'detail'" type="text" placeholder="必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="24" class="grid-cell">
          <el-form-item label="详细位置" class="required">
            <el-input
              v-model="formData.location" :disabled="dialogStatus === 'detail'" type="text" placeholder="非必填"
              clearable
            />
          </el-form-item>
        </el-col>
        <el-col :span="24" class="grid-cell">
          <el-form-item label="备注" class="required">
            <el-input
              v-model="formData.description" :disabled="dialogStatus === 'detail'" type="text" placeholder="非必填"
              clearable
            />
          </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>