From b05c43105564b174de6476835e7c55bca21fcb31 Mon Sep 17 00:00:00 2001
From: 潘志宝 <979469083@qq.com>
Date: 星期六, 14 九月 2024 16:56:34 +0800
Subject: [PATCH] modbus tag

---
 src/views/data/channel/modbus/ModBusDeviceForm.vue |   89 +++++---
 src/api/data/channel/modbus/tag.ts                 |   43 +++
 src/views/data/channel/modbus/tag/index.vue        |  234 +++++++++++++++++++++
 src/utils/constants.ts                             |    5 
 src/views/data/channel/modbus/tag/TagForm.vue      |  185 ++++++++++++++++
 src/utils/dict.ts                                  |    2 
 src/views/data/channel/modbus/index.vue            |   24 +
 src/utils/validate.ts                              |   63 +++++
 src/api/data/channel/modbus/index.ts               |    2 
 9 files changed, 610 insertions(+), 37 deletions(-)

diff --git a/src/api/data/channel/modbus/index.ts b/src/api/data/channel/modbus/index.ts
index d86f914..2fa3860 100644
--- a/src/api/data/channel/modbus/index.ts
+++ b/src/api/data/channel/modbus/index.ts
@@ -32,7 +32,7 @@
 
 // 新增ModBusDevice
 export const createModBusDevice = (data: ModBusDeviceVO) => {
-  return request.post({ url: '/data/channel/modbus/device/add', data })
+  return request.post({ url: '/data/channel/modbus/device/create', data })
 }
 
 // 修改ModBusDevice
diff --git a/src/api/data/channel/modbus/tag.ts b/src/api/data/channel/modbus/tag.ts
new file mode 100644
index 0000000..a6299df
--- /dev/null
+++ b/src/api/data/channel/modbus/tag.ts
@@ -0,0 +1,43 @@
+import request from '@/config/axios'
+
+export interface ModBusTagVO {
+  id: string
+  tagName: string
+  dataType: string
+  enabled: boolean
+  format: string
+  tag: string
+  address: string
+  samplingRate: number
+  tagDesc: string
+}
+
+export interface ModBusTagPageReqVO extends PageParam {
+  tagName?: string
+  address?: string
+}
+
+// 查询ModBusTag列表
+export const getModBusTagPage = (params: ModBusTagPageReqVO) => {
+  return request.get({ url: '/data/channel/modbus/tag/page', params })
+}
+
+// 查询ModBusTag详情
+export const getModBusTag = (id: number) => {
+  return request.get({ url: `/data/channel/modbus/tag/info/${id}`})
+}
+
+// 新增ModBusTag
+export const createModBusTag = (data: ModBusTagVO) => {
+  return request.post({ url: '/data/channel/modbus/tag/create', data })
+}
+
+// 修改ModBusTag
+export const updateModBusTag = (data: ModBusTagVO) => {
+  return request.put({ url: '/data/channel/modbus/tag/update', data })
+}
+
+// 删除ModBusTag
+export const deleteModBusTag = (id: number) => {
+  return request.delete({ url: '/data/channel/modbus/tag/delete?id=' + id })
+}
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index b21f067..360cf05 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -446,3 +446,8 @@
   SALE_OUT: 21,
   SALE_RETURN: 22
 }
+
+export const CommonEnabled = {
+  ENABLE: 1, // 启用
+  DISABLE: 0 // 禁用
+}
diff --git a/src/utils/dict.ts b/src/utils/dict.ts
index 12724e0..c0f80f6 100644
--- a/src/utils/dict.ts
+++ b/src/utils/dict.ts
@@ -239,4 +239,6 @@
 
   // ========== DATA - 数据平台模块  ==========
   DATA_FIELD_TYPE = 'data_field_type',
+  TAG_DATA_TYPE = 'tag_data_type',
+  IS_ENABLED = 'is_enabled'
 }
diff --git a/src/utils/validate.ts b/src/utils/validate.ts
new file mode 100644
index 0000000..8d754d5
--- /dev/null
+++ b/src/utils/validate.ts
@@ -0,0 +1,63 @@
+/**
+ * 邮箱
+ * @param {*} s
+ */
+export function isEmail (s) {
+  return /^([a-zA-Z0-9._-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s)
+}
+
+/**
+ * 手机号码
+ * @param {*} s
+ */
+export function isMobile (s) {
+  return /^1[0-9]{10}$/.test(s)
+}
+
+/**
+ * 电话号码
+ * @param {*} s
+ */
+export function isPhone (s) {
+  return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s)
+}
+
+/**
+ * URL地址
+ * @param {*} s
+ */
+export function isURL (s) {
+  return /^http[s]?:\/\/.*/.test(s)
+}
+
+/**
+ * 正整数
+ * @param {*} s
+ */
+export function isPositiveInteger (s) {
+  return /^[1-9]\d*$/.test(s)
+}
+
+/**
+ * 整数
+ * @param {*} s
+ */
+export function isInteger (s) {
+  return /^\d*$/.test(s)
+}
+
+/**
+ * 正数
+ * @param {*} s
+ */
+export function isPositiveNum (s) {
+  return /^([0-9]*|\d*.\d{1}?\d*)$/.test(s)
+}
+
+/**
+ * IP
+ * @param {*} s
+ */
+export function isIP (s) {
+  return /^(\d+\.\d+\.\d+\.\d+)$/.test(s)
+}
diff --git a/src/views/data/channel/modbus/ModBusDeviceForm.vue b/src/views/data/channel/modbus/ModBusDeviceForm.vue
index 5ab02f1..ee57f6a 100644
--- a/src/views/data/channel/modbus/ModBusDeviceForm.vue
+++ b/src/views/data/channel/modbus/ModBusDeviceForm.vue
@@ -10,62 +10,62 @@
       <el-row>
         <el-col :span="12">
           <el-form-item label="设备名称" prop="name">
-            <el-input v-model="formData.name" placeholder="请输入设备名称" />
+            <el-input v-model="formData.name" placeholder="请输入设备名称"/>
           </el-form-item>
         </el-col>
       </el-row>
       <el-row>
         <el-col :span="12">
           <el-form-item label="IP地址" prop="address">
-            <el-input v-model="formData.address" placeholder="请输入IP地址" />
+            <el-input v-model="formData.address" placeholder="请输入IP地址"/>
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="端口" prop="port">
-            <el-input v-model="formData.port" placeholder="请输入端口" />
+            <el-input v-model="formData.port" placeholder="请输入端口"/>
           </el-form-item>
         </el-col>
       </el-row>
       <el-row>
         <el-col :span="12">
           <el-form-item label="不活动超时(ms)" prop="connectInactivityTimeout">
-            <el-input v-model="formData.connectInactivityTimeout" placeholder="请输入不活动超时" />
+            <el-input v-model="formData.connectInactivityTimeout" placeholder="请输入不活动超时"/>
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="重连超时(ms)" prop="reconnectInterval">
-            <el-input v-model="formData.reconnectInterval" placeholder="请输入重连超时" />
+            <el-input v-model="formData.reconnectInterval" placeholder="请输入重连超时"/>
           </el-form-item>
         </el-col>
       </el-row>
       <el-row>
         <el-col :span="12">
           <el-form-item label="重试次数" prop="attemptsBeforeTimeout">
-            <el-input v-model="formData.attemptsBeforeTimeout" placeholder="请输入重试次数" />
+            <el-input v-model="formData.attemptsBeforeTimeout" placeholder="请输入重试次数"/>
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="重试间隔(ms)" prop="waitToRetryMilliseconds">
-            <el-input v-model="formData.waitToRetryMilliseconds" placeholder="请输入重试间隔" />
+            <el-input v-model="formData.waitToRetryMilliseconds" placeholder="请输入重试间隔"/>
           </el-form-item>
         </el-col>
       </el-row>
       <el-row>
         <el-col :span="12">
           <el-form-item label="读超时(ms)" prop="readTimeout">
-            <el-input v-model="formData.readTimeout" placeholder="请输入读超时" />
+            <el-input v-model="formData.readTimeout" placeholder="请输入读超时"/>
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="写超时(ms)" prop="writeTimeout">
-            <el-input v-model="formData.writeTimeout" placeholder="请输入写超时" />
+            <el-input v-model="formData.writeTimeout" placeholder="请输入写超时"/>
           </el-form-item>
         </el-col>
       </el-row>
       <el-row>
         <el-col :span="12">
           <el-form-item label="是否使用优化" prop="useOptimizedBlockRead">
-            <el-input v-model="formData.useOptimizedBlockRead" placeholder="请输入是否使用优化" />
+            <el-input v-model="formData.useOptimizedBlockRead" placeholder="请输入是否使用优化"/>
           </el-form-item>
         </el-col>
       </el-row>
@@ -77,11 +77,12 @@
   </Dialog>
 </template>
 <script lang="ts" setup>
-import * as ModBusApi from '@/api/data/channel/modbus'
+  import * as ModBusApi from '@/api/data/channel/modbus'
+  import {isIP, isPositiveInteger} from '@/utils/validate'
 
-defineOptions({ name: 'DataModBusDeviceForm' })
+  defineOptions({name: 'DataModBusDeviceForm'})
 
-  const { t } = useI18n() // 国际化
+  const {t} = useI18n() // 国际化
   const message = useMessage() // 消息弹窗
   const dialogVisible = ref(false) // 弹窗的是否展示
   const dialogTitle = ref('') // 弹窗的标题
@@ -92,21 +93,43 @@
     name: undefined,
     address: undefined,
     port: undefined,
-    connectInactivityTimeout: undefined,
-    reconnectInterval: undefined,
-    attemptsBeforeTimeout: undefined,
-    waitToRetryMilliseconds: undefined,
-    readTimeout: undefined,
-    writeTimeout: undefined,
-    useOptimizedBlockRead: undefined,
-    projectReference: undefined
+    connectInactivityTimeout: "",
+    reconnectInterval: "5000",
+    attemptsBeforeTimeout: "3",
+    waitToRetryMilliseconds: "250",
+    readTimeout: "3000",
+    writeTimeout: "3000",
+    useOptimizedBlockRead: "true",
+    projectReference: ''
   })
+  const validateIP = (rule, value, callback) => {
+    if (!isIP(value)) {
+      callback(new Error('IP地址不正确'))
+    } else {
+      callback()
+    }
+  }
+  const validateNum = (rule, value, callback) => {
+    if (!isPositiveInteger(value)) {
+      callback(new Error('格式不正确'))
+    } else {
+      callback()
+    }
+  }
+
   const formRules = reactive({
-    name: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
-    address: [{ required: true, message: 'IP地址不能为空', trigger: 'blur' }],
-    port: [{ required: true, message: '端口不能为空', trigger: 'blur' }]
+    name: [{required: true, message: '设备名称不能为空', trigger: 'blur'}],
+    address: [
+      {required: true, message: 'IP地址不能为空', trigger: 'blur'},
+      {validator: validateIP, trigger: 'blur'}
+    ],
+    port: [
+      {required: true, message: '端口不能为空', trigger: 'blur'},
+      {validator: validateNum, trigger: 'blur'}
+    ]
   })
   const formRef = ref() // 表单 Ref
+
 
   /** 打开弹窗 */
   const open = async (type: string, id?: number) => {
@@ -124,7 +147,7 @@
       }
     }
   }
-  defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+  defineExpose({open}) // 提供 open 方法,用于打开弹窗
 
   /** 提交表单 */
   const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
@@ -159,14 +182,14 @@
       name: undefined,
       address: undefined,
       port: undefined,
-      connectInactivityTimeout: undefined,
-      reconnectInterval: undefined,
-      attemptsBeforeTimeout: undefined,
-      waitToRetryMilliseconds: undefined,
-      readTimeout: undefined,
-      writeTimeout: undefined,
-      useOptimizedBlockRead: undefined,
-      projectReference: undefined
+      connectInactivityTimeout: "",
+      reconnectInterval: "5000",
+      attemptsBeforeTimeout: "3",
+      waitToRetryMilliseconds: "250",
+      readTimeout: "3000",
+      writeTimeout: "3000",
+      useOptimizedBlockRead: "true",
+      projectReference: ''
     }
     formRef.value?.resetFields()
   }
diff --git a/src/views/data/channel/modbus/index.vue b/src/views/data/channel/modbus/index.vue
index 27b491f..58b0942 100644
--- a/src/views/data/channel/modbus/index.vue
+++ b/src/views/data/channel/modbus/index.vue
@@ -39,7 +39,7 @@
           type="primary"
           plain
           @click="openForm('create')"
-          v-hasPermi="['system:tenant:create']"
+          v-hasPermi="['data:channel-modbus:create']"
         >
           <Icon icon="ep:plus" class="mr-5px" />
           新增
@@ -68,15 +68,23 @@
             link
             type="primary"
             @click="openForm('update', scope.row.id)"
-            v-hasPermi="['system:tenant:update']"
+            v-hasPermi="['data:channel-modbus:update']"
           >
             编辑
           </el-button>
           <el-button
             link
+            type="primary"
+            @click="openTagList(scope.row.name)"
+            v-hasPermi="['data:channel-modbus:update']"
+          >
+            TAG
+          </el-button>
+          <el-button
+            link
             type="danger"
             @click="handleDelete(scope.row.id)"
-            v-hasPermi="['system:tenant:delete']"
+            v-hasPermi="['data:channel-modbus:delete']"
           >
             删除
           </el-button>
@@ -95,10 +103,14 @@
   <!-- 表单弹窗:添加/修改 -->
   <ModBusDeviceForm ref="formRef" @success="getList" />
 
+  <!-- TAG弹窗:添加/修改 -->
+  <TagList ref="tagRef" @success="getList" />
+
 </template>
 <script lang="ts" setup>
 import * as ModbusApi from '@/api/data/channel/modbus'
 import ModBusDeviceForm from './ModBusDeviceForm.vue'
+import TagList from './tag/index.vue'
 
 defineOptions({name: 'DataModBus'})
 
@@ -147,6 +159,12 @@
     formRef.value.open(type, id)
   }
 
+  /** TAG操作 */
+  const tagRef = ref()
+  const openTagList = (name?: string) => {
+    tagRef.value.open(name)
+  }
+
   /** 删除按钮操作 */
   const handleDelete = async (id: number) => {
     try {
diff --git a/src/views/data/channel/modbus/tag/TagForm.vue b/src/views/data/channel/modbus/tag/TagForm.vue
new file mode 100644
index 0000000..fc70722
--- /dev/null
+++ b/src/views/data/channel/modbus/tag/TagForm.vue
@@ -0,0 +1,185 @@
+<template>
+  <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%">
+    <el-form
+      ref="formRef"
+      v-loading="formLoading"
+      :model="formData"
+      :rules="formRules"
+      label-width="120px"
+    >
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="关联设备" prop="device">
+            <el-input v-model="formData.device" readonly/>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="Tag名称" prop="tagName">
+            <el-input v-model="formData.tagName" placeholder="请输Tag名称"/>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="数据类型" prop="dataType">
+            <el-select v-model="formData.dataType" placeholder="请选择">
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.TAG_DATA_TYPE)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="地址" prop="address">
+            <el-input v-model="formData.address" placeholder="请输入地址"/>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="大小端" prop="format">
+            <el-input v-model="formData.format" placeholder="请输入大小端" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="采集频率" prop="samplingRate">
+            <el-input v-model="formData.samplingRate" placeholder="请输入采集频率"/>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="是否启用" prop="enabled">
+            <el-select v-model="formData.enabled" placeholder="请选择">
+              <el-option
+                v-for="dict in getBoolDictOptions(DICT_TYPE.IS_ENABLED)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="描述" prop="tagDesc">
+            <el-input v-model="formData.tagDesc" placeholder="描述"/>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script lang="ts" setup>
+  import * as ModBusTagApi from '@/api/data/channel/modbus/tag'
+  import { CommonEnabled } from '@/utils/constants'
+  import {isPositiveInteger} from '@/utils/validate'
+  import { DICT_TYPE, getStrDictOptions, getBoolDictOptions } from '@/utils/dict'
+
+  defineOptions({name: 'ModBusTagForm'})
+
+  const {t} = useI18n() // 国际化
+  const message = useMessage() // 消息弹窗
+  const dialogVisible = ref(false) // 弹窗的是否展示
+  const dialogTitle = ref('') // 弹窗的标题
+  const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+  const formType = ref('') // 表单的类型:create - 新增;update - 修改
+  const formData = ref({
+    id: undefined,
+    tagName: undefined,
+    dataType: undefined,
+    enabled: CommonEnabled.ENABLE,
+    format: undefined,
+    device: '1',
+    address: '',
+    samplingRate: undefined,
+    tagDesc: '',
+  })
+  const validateNum = (rule, value, callback) => {
+    if (!isPositiveInteger(value)) {
+      callback(new Error('格式不正确'))
+    } else {
+      callback()
+    }
+  }
+  const formRules = reactive({
+    device: [{required: true, message: '关联设备不能为空', trigger: 'blur'}],
+    address: [
+      {required: true, message: '地址不能为空', trigger: 'blur'},
+      {validator: validateNum, trigger: 'blur'}],
+    dataType: [{required: true, message: '数据类型不能为空', trigger: 'blur'}]
+  })
+  const formRef = ref() // 表单 Ref
+
+  /** 打开弹窗 */
+  const open = async (type: string, id?: number, device?: string) => {
+    dialogVisible.value = true
+    dialogTitle.value = t('action.' + type)
+    formType.value = type
+    resetForm()
+    if (device) {
+      formData.value.device = device
+    }
+    // 修改时,设置数据
+    if (id) {
+      formLoading.value = true
+      try {
+        formData.value = await ModBusTagApi.getModBusTag(id)
+        formData.device = device
+      } finally {
+        formLoading.value = false
+      }
+    }
+  }
+  defineExpose({open}) // 提供 open 方法,用于打开弹窗
+
+  /** 提交表单 */
+  const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+  const submitForm = async () => {
+    // 校验表单
+    if (!formRef) return
+    const valid = await formRef.value.validate()
+    if (!valid) return
+    // 提交请求
+    formLoading.value = true
+    try {
+      const data = formData.value as unknown as ModBusTagApi.ModBusTagVO
+      if (formType.value === 'create') {
+        await ModBusTagApi.createModBusTag(data)
+        message.success(t('common.createSuccess'))
+      } else {
+        await ModBusTagApi.updateModBusTag(data)
+        message.success(t('common.updateSuccess'))
+      }
+      dialogVisible.value = false
+      // 发送操作成功的事件
+      emit('success')
+    } finally {
+      formLoading.value = false
+    }
+  }
+
+  /** 重置表单 */
+  const resetForm = () => {
+    formData.value = {
+      id: undefined,
+      tagName: undefined,
+      dataType: undefined,
+      enabled: CommonEnabled.ENABLE,
+      format: undefined,
+      device: '',
+      address: '',
+      samplingRate: undefined,
+      tagDesc: '',
+    }
+    formRef.value?.resetFields()
+  }
+</script>
diff --git a/src/views/data/channel/modbus/tag/index.vue b/src/views/data/channel/modbus/tag/index.vue
new file mode 100644
index 0000000..335b5e1
--- /dev/null
+++ b/src/views/data/channel/modbus/tag/index.vue
@@ -0,0 +1,234 @@
+<template>
+  <el-drawer
+    v-model="drawer"
+    size="50%"
+    title="ModBus Tag"
+    :direction="direction"
+    :before-close="handleClose"
+  >
+    <!-- 搜索 -->
+    <ContentWrap>
+      <el-form
+        class="-mb-15px"
+        :model="queryParams"
+        ref="queryFormRef"
+        :inline="true"
+        label-width="68px"
+      >
+        <el-form-item label="Tag名称" prop="tagName">
+          <el-input
+            v-model="queryParams.tagName"
+            placeholder="请输入Tag名称"
+            clearable
+            @keyup.enter="handleQuery"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="地址" prop="address">
+          <el-input
+            v-model="queryParams.address"
+            placeholder="请输入Modbus地址"
+            clearable
+            @keyup.enter="handleQuery"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button @click="handleQuery">
+            <Icon icon="ep:search" class="mr-5px" />
+            搜索
+          </el-button>
+          <el-button @click="resetQuery">
+            <Icon icon="ep:refresh" class="mr-5px" />
+            重置
+          </el-button>
+          <el-button
+            type="primary"
+            plain
+            @click="openForm('create')"
+            v-hasPermi="['data:channel-modbus:create']"
+          >
+            <Icon icon="ep:plus" class="mr-5px" />
+            新增
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </ContentWrap>
+    <!-- 列表 -->
+    <ContentWrap>
+      <el-table v-loading="loading" :data="list">
+        <el-table-column
+          prop="tagName"
+          label="Tag名称"
+          header-align="center"
+          align="left"
+          min-width="150"
+        />
+        <el-table-column
+          prop="tagDesc"
+          label="Tag描述"
+          header-align="center"
+          align="left"
+          min-width="150"
+        />
+        <el-table-column
+          prop="dataType"
+          label="数据类型"
+          header-align="center"
+          align="center"
+        />
+        <el-table-column
+          prop="address"
+          label="地址"
+          header-align="center"
+          align="center"
+        />
+        <el-table-column
+          prop="format"
+          label="大小端"
+          header-align="center"
+          align="center"
+        />
+        <el-table-column
+          prop="samplingRate"
+          label="采集频率"
+          header-align="center"
+          align="center"
+        />
+        <el-table-column
+          prop="enabled"
+          label="是否启用"
+          header-align="center"
+          align="center"
+        >
+          <template #default="scope">
+            <el-tag v-if="scope.row.enabled === true" size="small">是</el-tag>
+            <el-tag v-else size="small" type="danger">否</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" min-width="110" fixed="right">
+          <template #default="scope">
+            <el-button
+              link
+              type="primary"
+              @click="openForm('update', scope.row.id)"
+              v-hasPermi="['data:channel-modbus:update']"
+            >
+              编辑
+            </el-button>
+            <el-button
+              link
+              type="danger"
+              @click="handleDelete(scope.row.id)"
+              v-hasPermi="['data:channel-modbus:delete']"
+            >
+              删除
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <Pagination
+        :total="total"
+        v-model:page="queryParams.pageNo"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </ContentWrap>
+    <!-- 表单弹窗:添加/修改 -->
+    <TagForm ref="formRef" @success="getList" />
+  </el-drawer>
+</template>
+<script lang="ts" setup>
+  import type { DrawerProps } from 'element-plus'
+  import * as ModBusTagApi from "@/api/data/channel/modbus/tag";
+  import TagForm from './TagForm.vue'
+
+  defineOptions({name: 'ModBusTag'})
+
+  const message = useMessage() // 消息弹窗
+  const {t} = useI18n() // 国际化
+
+  const drawer = ref(false)
+  const direction = ref<DrawerProps['direction']>('rtl')
+  const loading = ref(true) // 列表的加载中
+  const total = ref(0) // 列表的总页数
+  const list = ref([]) // 列表的数据
+  const queryParams = reactive({
+    pageNo: 1,
+    pageSize: 10,
+    device: undefined,
+    tagName: undefined,
+    address: undefined
+  })
+  const queryFormRef = ref() // 搜索的表单
+  const exportLoading = ref(false) // 导出的加载中
+
+  /** 查询列表 */
+  const getList = async () => {
+    loading.value = true
+    try {
+      const page = await ModBusTagApi.getModBusTagPage(queryParams)
+      list.value = page.list
+      total.value = page.total
+    } finally {
+      loading.value = false
+    }
+  }
+
+  /** 搜索按钮操作 */
+  const handleQuery = () => {
+    queryParams.pageNo = 1
+    getList()
+  }
+
+  /** 重置按钮操作 */
+  const resetQuery = () => {
+    queryFormRef.value.resetFields()
+    handleQuery()
+  }
+
+  /** 添加/修改操作 */
+  const formRef = ref()
+  const openForm = (type: string, id?: number) => {
+    formRef.value.open(type, id, queryParams.device)
+  }
+
+  /** 删除按钮操作 */
+  const handleDelete = async (id: number) => {
+    try {
+      // 删除的二次确认
+      await message.delConfirm()
+      // 发起删除
+      await ModBusTagApi.deleteModBusTag(id)
+      message.success(t('common.delSuccess'))
+      // 刷新列表
+      await getList()
+    } catch {
+    }
+  }
+
+  /** 打开弹窗 */
+  const open = async (device?: string) => {
+    resetForm()
+    drawer.value = true
+    queryParams.device = device
+    if (device) {
+      getList()
+    }
+  }
+  defineExpose({open}) // 提供 open 方法,用于打开弹窗
+
+  /** 重置表单 */
+  const resetForm = () => {
+    queryParams.pageNo = 1
+    queryParams.pageSize = 10
+    queryParams.device = ''
+    queryParams.tagName = ''
+    queryParams.address = ''
+  }
+
+  const handleClose = (done: () => void) => {
+    drawer.value = false
+  }
+</script>

--
Gitblit v1.9.3