Newer
Older
IntegratedFront / src / views / page / device / components / addDialog.vue
lyg on 15 Nov 12 KB 视频修改
<!--
  Description: 设备管理 - 新建/编辑
  Author: 李亚光
  Date: 2024-11-01
 -->
<script lang="ts" setup name="DeviceManageEdit">
import { ElMessage, type FormRules } from 'element-plus'
import { ITEM_RENDER_EVT } from 'element-plus/es/components/virtual-list/src/defaults'
import { getSceneAll } from '@/api/page/scene'
import { getModelAll } from '@/api/page/model'
import { addDevice, getModelRelations, updateDevice, updateModelRelations, updateSceneRelations } from '@/api/page/device'
const emits = defineEmits(['refresh'])
const dataFormRef = ref()
const dialogFormVisible = ref(false) // 对话框是否显示
const dialogStatus = ref('') // 对话框类型:create,update
const multipleTableRef = ref()
const dataForm = ref<{ [key: string]: string }>({
  name: '', // 名称
  code: '', // 编号
  type: '', // 摄像头类型
  input_stream_url: '', // RTSP地址
  image_save_interval: '60', // 识别间隔
  alarm_interval: '60', // 告警间隔
  mode: '',
  gas_ip: '',
  relation_scene_name: '',
  relation_model_names: '',
  ip: '',
}) // 表单
const textMap: { [key: string]: string } = {
  update: '编辑',
  create: '新增',
  detail: '详情',
} // 表头显示标题
const btnLoading = ref(false) // 保存按钮的加载中状态
const rules: FormRules = {
  name: [{ required: true, message: '名称不能为空', trigger: ['blur', 'change'] }],
  code: [{ required: true, message: '编号不能为空', trigger: ['blur', 'change'] }],
  type: [{ required: true, message: '摄像头类型必选', trigger: ['blur', 'change'] }],
  input_stream_url: [{ required: true, message: '摄像头类型不能为空', trigger: ['blur', 'change'] }],
  image_save_interval: [{ required: true, message: '识别间隔不能为空', trigger: ['blur', 'change'] }],
  alarm_interval: [{ required: true, message: '告警间隔不能为空', trigger: ['blur', 'change'] }],
  mode: [{ required: true, message: '场景模式必选', trigger: ['blur', 'change'] }],
  gas_ip: [{ required: true, message: '甲烷IP必填', trigger: ['blur', 'change'] }],
  ip: [{ required: true, message: '摄像头IP必填', trigger: ['blur', 'change'] }],
  relation_model_names: [{ required: true, message: '关联算法必选', trigger: ['blur', 'change'] }],
  relation_scene_name: [{ required: true, message: '业务场景必选', trigger: ['blur', 'change'] }],
} // 前端校验规则
const sceneList = ref<any[]>([])
const modelList = ref<any[]>([])
const modelAllList = ref<any[]>([])

// 初始化对话框
const initDialog = (row: any, dialogStatusValue: string) => {
  dialogStatus.value = dialogStatusValue
  dialogFormVisible.value = true
  if (dialogStatusValue === 'create') {
    resetForm()
    // nextTick(() => {
    //   multipleTableRef.value?.resetFields()
    // })
  }
  else {
    dataForm.value = row
    for (const i in dataForm.value) {
      dataForm.value[i] = typeof dataForm.value[i] === 'number' ? String(dataForm.value[i]) : dataForm.value[i]
    }
    if (dataForm.value.mode === '1') {
      // 算法
      getModelRelations(row.id).then((res) => {
        if (!res.data.length) {
          modelList.value = modelAllList.value
          return
        }
        modelList.value = res.data.map((item: any) => ({
          ...item,
          name: item.algo_model_name,
          custom_threshold: item.threshold,
          id: item.algo_model_id,
        }))
        if (modelList.value.length !== modelAllList.value.length) {
          // 先判断是删除还是新建
          if (modelList.value.length < modelAllList.value.length) {
            //  新建
            const addArr = modelAllList.value.filter((item: any) => modelList.value.every((citem: any) => citem.name !== item.name))
            addArr.forEach((element: any) => {
              modelList.value.push({
                ...element,
                custom_threshold: '0.5',
              })
            })
          }
        }
        modelList.value = modelList.value.sort((a: any, b: any) => Number(a.id) - Number(b.id))
        nextTick(() => {
          modelList.value.forEach((element: any) => {
            multipleTableRef.value!.toggleRowSelection(
              element,
              String(element.is_use) === '1',
            )
          })
        })
      })
    }
  }
}
defineExpose({
  initDialog,
})

const cancel = () => {
  dialogFormVisible.value = false
  resetForm()
}
// 选择的算法
const selectModelList = ref<any[]>([])
const selectModel = (value: any) => {
  selectModelList.value = value
  dataForm.value.relation_model_names = value.map((item: any) => item.name).join(',')
}
// 重置表单
function resetForm() {
  selectModelList.value = []
  dataForm.value = {
    name: '',
    code: '', // 编号
    type: '', // 摄像头类型
    input_stream_url: '', // RTSP地址
    image_save_interval: '60', // 识别间隔
    alarm_interval: '60', // 告警间隔
    mode: '',
    gas_ip: '',
    relation_scene_name: '',
    relation_model_names: '',
    ip: '',
  }
  nextTick(() => {
    dataFormRef.value.resetFields()
  })
}
// 获取字典相关
const fetchDict = () => {
  getSceneAll({}).then((res) => {
    sceneList.value = res.data
  })
  getModelAll({}).then((res) => {
    modelList.value = res.data.map((item: any) => ({ ...item, custom_threshold: 0.5 })).sort((a: any, b: any) => Number(a.id) - Number(b.id))
    modelAllList.value = res.data.map((item: any) => ({ ...item, custom_threshold: 0.5 })).sort((a: any, b: any) => Number(a.id) - Number(b.id))
  })
}
fetchDict()

// 新建
const add = () => {
  const confirm = () => {
    ElMessage.success(dialogStatus.value === 'update' ? '编辑成功' : '新建成功')
    emits('refresh')
    resetForm()
    cancel()
  }
  (dialogStatus.value === 'update' ? updateDevice : addDevice)(dataForm.value).then((res) => {
    // 算法
    if (dataForm.value.mode === '1') {
      updateModelRelations({
        id: dialogStatus.value === 'update' ? dataForm.value.id : res.data.id,
        list: [
          ...selectModelList.value.map((item: any) => ({
            algo_model_id: item.id,
            is_use: 1,
            threshold: item.custom_threshold,
          })),
          ...modelList.value.filter((item: any) => selectModelList.value.every((citem: any) => citem.id !== item.id)).map((item: any) => ({
            algo_model_id: item.id,
            is_use: 0,
            threshold: item.custom_threshold,
          })),
        ],
      }).then((res) => {
        confirm()
      })
    }
    else if (dataForm.value.mode === '2') {
      // 场景
      updateSceneRelations({
        id: dialogStatus.value === 'update' ? dataForm.value.id : res.data.id,
        scene_id: sceneList.value.filter((item: any) => item.name === dataForm.value.relation_scene_name)[0]?.id || '',
      }).then(() => {
        confirm()
      })
    }
    else {
      confirm()
    }
  })
}
const saveData = () => {
  // 验证
  // 1.关联算法
  if (dataForm.value.mode === '1' && selectModelList.value.some(item => !item.custom_threshold)) {
    ElMessage.warning('关联算法所有阈值应为有效值')
    return
  }
  // 2.关联场景
  if (dataForm.value.mode === '2' && !dataForm.value.relation_scene_name) {
    ElMessage.warning('场景应为必选,若列表为空,应先添加场景')
    return
  }
  // 验证
  dataFormRef.value.validate((valid: any) => {
    if (valid) {
      if (dialogStatus.value === 'create') {
        add()
      }
      else {
        add()
      }
    }
  })
}
</script>

<template>
  <el-dialog v-model="dialogFormVisible" :title="textMap[dialogStatus]" append-to-body>
    <el-form
      ref="dataFormRef" :rules="rules" :model="dataForm" label-position="right" label-width="120px"
      :disabled="dialogStatus === 'detail'"
    >
      <el-row :gutter="24">
        <el-col :span="12">
          <el-form-item label="摄像头名称" prop="name">
            <el-input v-model.trim="dataForm.name" type="text" placeholder="必填" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="摄像头编号" prop="code">
            <el-input v-model.trim="dataForm.code" type="text" placeholder="必填" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="摄像头IP" prop="ip">
            <el-input v-model.trim="dataForm.ip" type="text" placeholder="必填" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="RTSP地址" prop="input_stream_url">
            <el-input v-model.trim="dataForm.input_stream_url" type="text" placeholder="必填" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="识别间隔(s)" prop="image_save_interval">
            <el-input v-model.trim="dataForm.image_save_interval" type="number" :min="1" placeholder="必填" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="告警间隔(s)" prop="alarm_interval">
            <el-input v-model.trim="dataForm.alarm_interval" type="number" :min="1" placeholder="必填" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="摄像头类型" prop="type">
            <el-select v-model="dataForm.type" placeholder="摄像头类型" clearable class="select" style="width: 100%;">
              <el-option value="1" label="摄像头" />
              <el-option value="2" label="安全树" />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col v-if="dataForm.type === '2'" :span="12">
          <el-form-item label="甲烷IP" prop="gas_ip">
            <el-input v-model.trim="dataForm.gas_ip" type="text" placeholder="必填" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="24">
        <el-col :span="12">
          <el-form-item label="场景模式" prop="mode">
            <el-radio-group v-model="dataForm.mode">
              <el-radio label="2">
                业务场景
              </el-radio>
              <el-radio label="1">
                算法关联
              </el-radio>
              <el-radio label="0">
                无
              </el-radio>
            </el-radio-group>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="dataForm.mode === '2'" :gutter="24">
        <el-col :span="12">
          <el-form-item label="业务场景" prop="relation_scene_name">
            <el-select
              v-model="dataForm.relation_scene_name" placeholder="业务场景" clearable class="select"
              style="width: 100%;"
            >
              <el-option v-for="item in sceneList" :key="item.id" :value="item.name" :label="item.name" />
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="dataForm.mode === '1'" :gutter="24">
        <el-col :span="18">
          <el-form-item label="算法关联" prop="relation_model_names">
            <el-table
              ref="multipleTableRef" :data="modelList" border stripe style="width: 100%;"
              @selection-change="selectModel"
            >
              <el-table-column label="算法名称" align="center" value="name">
                <template #default="scope">
                  {{ scope.row.name }}
                </template>
              </el-table-column>
              <el-table-column label="阈值" align="center">
                <template #default="scope">
                  <el-input-number v-model="scope.row.custom_threshold" :min="0" controls-position="right" />
                </template>
              </el-table-column>
              <el-table-column type="selection" width="55" align="center" />
            </el-table>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button :loading="btnLoading" type="primary" @click="saveData">
          保存
        </el-button>
        <el-button @click="cancel">
          取消
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<style lang="scss" scoped>
.el-dialog {
  width: 700px;
}

.el-select {
  width: 100%;
}

.draw {
  height: 300px;
  width: 533.333px;
  border: 2px solid #000;
  padding: 0;
  margin: 0;
  box-sizing: content-box;
  position: relative;
}
</style>