Bläddra i källkod

优化ota批次设备管理弹窗,优化ota批次选择设备时table多选

Xiahai 1 år sedan
förälder
incheckning
90ce0109f0

+ 13 - 55
src/views/iot/ota-update/update/component/batch.vue

@@ -69,9 +69,10 @@
         <el-table-column prop="createdAt" label="创建时间" min-width="100" align="center" />
         <el-table-column label="操作" width="200" align="center">
           <template #default="scope">
-            <router-link :to="'/iotmanager/operation/ota/update/device/' + scope.row.id" class="link-type" style="padding-right: 12px;font-size: 12px;color: #409eff;">
-              <span>查看</span>
-            </router-link>
+<!--            <router-link :to="'/iotmanager/operation/ota/update/device/' + scope.row.id" class="link-type" style="padding-right: 12px;font-size: 12px;color: #409eff;">-->
+<!--              <span>查看</span>-->
+<!--            </router-link>-->
+            <el-button size="small" text type="primary" @click="getDeviceList(scope.row)">查看</el-button>
             <!--            <el-button size="small" text type="warning" v-auth="'edit'" @click="CheckUpdate(scope.row)">编辑</el-button>-->
             <!--            <el-button size="small" text type="danger" v-auth="'del'" @click="del(scope.row)">删除</el-button>-->
 <!--            <el-button size="small" text type="success" v-if="scope.row.active != 1" @click="activation(scope.row)">激活</el-button>-->
@@ -79,11 +80,9 @@
           </template>
         </el-table-column>
       </el-table>
-      <!--      <pagination v-if="params.total" :total="params.total" v-model:page="params.pageNum" v-model:limit="params.pageSize"-->
-      <!--        @pagination="getList()" />-->
-      <!--      <CheckForm ref="checkFormRef" @getList="getList()"></CheckForm>-->
       <pagination v-show="tableData.total > 0" :total="tableData.total" v-model:page="tableData.param.pageNum" v-model:limit="tableData.param.pageSize" @pagination="getList" />
       <CheckConfig ref="checkRef" @getList="getList(1)" />
+      <DeviceList ref="deviceRef" />
     </el-card>
   </div>
 </template>
@@ -93,6 +92,7 @@ import api from '/@/api/ota';
 import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue';
 import { ElMessageBox, ElMessage } from 'element-plus'
 import CheckConfig from '/@/views/iot/ota-update/update/component/check.vue';
+import DeviceList from '/@/views/iot/ota-update/update/component/deviceList.vue';
 
 // 定义接口来定义对象的类型
 interface TableDataRow {
@@ -121,7 +121,7 @@ interface TableDataState {
   };
 }
 export default defineComponent({
-  components: { CheckConfig },
+  components: { CheckConfig, DeviceList },
   props: {
     detail: {
       type: Object,
@@ -129,6 +129,7 @@ export default defineComponent({
     }
   },
   setup(props) {
+    const deviceRef = ref();
     const checkRef = ref();
     const queryRef = ref();
     const tabDataList = ref([{ dictLabel: '全部', dictValue: '' }]);
@@ -222,7 +223,11 @@ export default defineComponent({
     const batchList = () => {
       getList();
     };
+    const getDeviceList = (row: any) => {
+      deviceRef.value.openDialog(row);
+    };
     return {
+      deviceRef,
       checkRef,
       queryRef,
       tabDataList,
@@ -232,57 +237,10 @@ export default defineComponent({
       activation,
       resetQuery,
       handleSelectionChange,
+      getDeviceList,
       ...toRefs(props),
       ...toRefs(state),
     };
   },
 });
-// import api from '/@/api/ota';
-// import { useSearch } from '/@/hooks/useCommon';
-// import { ElMessageBox, ElMessage, FormInstance } from 'element-plus';
-// // import CheckForm from '../check.vue';
-// import CheckForm from '/@/views/iot/ota-update/update/component/check.vue';
-//
-// import { ref } from 'vue';
-// import { useRouter } from 'vue-router';
-// const props = defineProps({
-// 	detail: {
-// 		type: Object,
-// 		default: () => { }
-// 	},
-// })
-// const queryRef = ref();
-// const router = useRouter();
-//
-// const checkFormRef = ref();
-//
-// const { params, tableData, getList, loading } = useSearch<any[]>(api.batch.getList, 'Data', { devOtaFirewareId: props.detail.id });
-//
-// getList();
-//
-// const CheckUpdate = async (row?: any) => {
-// 	if (row) {
-// 		checkFormRef.value.open(row);
-// 		return;
-// 	} else {
-// 		let array = {
-// 			productId: props.detail.productId,
-// 			devOtaFirewareId: props.detail.id
-// 		}
-// 		checkFormRef.value.open(array);
-// 	}
-// };
-//
-//
-// const del = (row: any) => {
-// 	ElMessageBox.confirm(`此操作将删除图形:“${row.name}”,是否继续?`, '提示', {
-// 		confirmButtonText: '确认',
-// 		cancelButtonText: '取消',
-// 		type: 'warning',
-// 	}).then(async () => {
-// 		await api.manage.del(row.id);
-// 		ElMessage.success('删除成功');
-// 		getList();
-// 	});
-// };
 </script>

+ 40 - 10
src/views/iot/ota-update/update/component/check.vue

@@ -21,9 +21,9 @@
           <el-input v-model="ruleForm.name" placeholder="请输入批次名称" />
         </el-form-item>
 
-<!--        <el-form-item label="待升级版本号" prop="waitVersion">-->
-<!--          <el-input v-model="ruleForm.waitVersion" placeholder="请输入待升级版本号" />-->
-<!--        </el-form-item>-->
+        <!--        <el-form-item label="待升级版本号" prop="waitVersion">-->
+        <!--          <el-input v-model="ruleForm.waitVersion" placeholder="请输入待升级版本号" />-->
+        <!--        </el-form-item>-->
 
         <el-form-item label="协议方式" prop="method">
           <el-radio-group v-model="ruleForm.method" @change="getMethod">
@@ -34,13 +34,16 @@
         </el-form-item>
 
         <el-form-item label="所属设备" prop="devices" v-if="deviceShow">
-<!--            <el-select v-model="ruleForm.devices" placeholder="请选择设备" >-->
-<!--              <el-option v-for="item in productData" :key="item.id" :label="item.name" :value="item.id.toString()" />-->
-<!--            </el-select>-->
+<!--          <el-select v-model="ruleForm.devices" filterable multiple placeholder="请选择设备" class="width100">-->
+<!--            <el-option v-for="item in productData" :key="item.id" :label="item.name" :value="item.id.toString()" />-->
+<!--          </el-select>-->
 
-          <el-select v-model="ruleForm.devices" filterable multiple placeholder="请选择设备" class="width100">
-            <el-option v-for="item in productData" :key="item.id" :label="item.name" :value="item.id.toString()" />
-          </el-select>
+          <!-- 回显已选设备 -->
+          <template v-if="deviceNameShow">
+            <el-tag v-for="item in deviceNameList" style="margin-right: 10px;">{{ item }}</el-tag>
+          </template>
+
+          <el-button type="primary" @click="onOpenDevice()" style="margin-left: 5px; margin-top: 10px;">选择设备</el-button>
         </el-form-item>
 
         <el-form-item label="升级方式" prop="stratege">
@@ -64,6 +67,9 @@
 				</span>
       </template>
     </el-dialog>
+
+    <!-- 设备绑定弹窗 -->
+    <DeviceBind ref="deviceRef" @bindSuccess="getDeviceTableData" />
   </div>
 </template>
 
@@ -72,6 +78,8 @@ import { reactive, toRefs, defineComponent, onMounted, ref, unref} from 'vue';
 import { ElMessage } from 'element-plus';
 import api from '/@/api/ota';
 import rule from "/@/api/rule";
+import Device from "/@/views/iot/device/instance/index.vue";
+import DeviceBind from "/@/views/iot/ota-update/update/component/deviceBind.vue";
 
 interface RuleFormState {
   id: number;
@@ -92,16 +100,20 @@ interface UpdateState {
   productData: [];
   rules: {};
   deviceShow: boolean;
+  deviceNameShow: boolean;
+  deviceNameList: [];
 }
 
 export default defineComponent({
   name: 'otaEditUpdateData',
+  components: {DeviceBind},
   computed: {
     rule() {
       return rule
     }
   },
   setup(prop, { emit }) {
+    const deviceRef = ref();
     const formRef = ref<HTMLElement | null>(null);
     const state = reactive<UpdateState>({
       isShowDialog: false,
@@ -125,9 +137,10 @@ export default defineComponent({
         stratege: [{ required: true, message: '升级方式不能为空', trigger: 'blur' }],
         push: [{ required: true, message: '推送方式不能为空', trigger: 'blur' }],
         typo: [{ required: true, message: '类型不能为空', trigger: 'blur' }],
-        // devices: [{required: true, message: '所属设备不能为空', trigger: 'blur'}],
       },
       deviceShow: false, // 所属设备是否显示
+      deviceNameShow: false, // 回显设备名称状态
+      deviceNameList: [], // 回显设备名称
     });
     // 页面加载时
     onMounted(() => {
@@ -168,6 +181,8 @@ export default defineComponent({
     // 打开弹窗
     const openDialog = (row: RuleFormState | null) => {
       resetForm();
+      state.deviceNameList = [];
+      state.deviceNameShow = false;
       if (row) {
         state.ruleForm.devOtaFirmwareId = row.id;
         state.ruleForm.productId = row.productId;
@@ -196,6 +211,8 @@ export default defineComponent({
     // 关闭弹窗
     const closeDialog = () => {
       state.isShowDialog = false;
+      state.deviceNameList = [];
+      state.deviceNameShow = false;
     };
     // 取消
     const onCancel = () => {
@@ -225,13 +242,26 @@ export default defineComponent({
         }
       });
     };
+    // 获取设备列表
+    const getDeviceTableData = (deviceIdList: any, deviceNameList: any) => {
+      state.ruleForm.devices = deviceIdList;
+      state.deviceNameList = deviceNameList;
+      state.deviceNameShow = true;
+    };
+    // 打开设备列表
+    const onOpenDevice = () => {
+      deviceRef.value.openDialog(state.ruleForm.devices);
+    };
     return {
+      deviceRef,
       openDialog,
       closeDialog,
       onCancel,
       onSubmit,
       getMethod,
       getFormType,
+      onOpenDevice,
+      getDeviceTableData,
       formRef,
       ...toRefs(state),
     };

+ 178 - 0
src/views/iot/ota-update/update/component/deviceBind.vue

@@ -0,0 +1,178 @@
+<template>
+  <div class="mutiple-bind-dialog-wrap">
+    <el-dialog title="选择设备" v-model="isShowDialog" width="90%">
+      <el-form :model="ruleForm" ref="formRef" :rules="rules" size="small" label-width="110px">
+        <el-form-item label="设备名称" prop="name">
+          <el-input v-model="tableData.param.name" placeholder="请输入设备名称" clearable size="default" style="width: 240px" @keyup.enter.native="typeList" />
+          <el-button style="margin-left: 20px;" type="primary" @click="getDeviceList()">查询</el-button>
+
+          <el-button style="margin-left: 20px;" :disabled="!deviceKeyList.length" type="danger" @click="confirmBind()">确定选择</el-button>
+        </el-form-item>
+      </el-form>
+      <el-table ref="multipleTable" :data="tableData.data" style="width: 100%" @selection-change="handleSelectionChange" v-loading="tableData.loading">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="标识" prop="key" width="130" :show-overflow-tooltip="true" v-col="'key'" />
+        <el-table-column label="设备名称" prop="name" :show-overflow-tooltip="true" v-col="'name'" />
+        <el-table-column label="产品名称" prop="productName" :show-overflow-tooltip="true" v-col="'productName'" />
+
+        <el-table-column prop="status" label="状态" width="100" align="center" v-col="'status'">
+          <template #default="scope">
+            <el-tag type="info" size="small" v-if="scope.row.status == 1">离线</el-tag>
+            <el-tag type="success" size="small" v-if="scope.row.status == 2">在线</el-tag>
+            <el-tag type="info" size="small" v-if="scope.row.status == 0">未启用</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="registryTime" label="激活时间" align="center" width="150" v-col="'registryTime'"></el-table-column>
+        <el-table-column prop="desc" label="说明" v-col="'desc'"></el-table-column>
+
+      </el-table>
+      <pagination v-show="tableData.total > 0" :total="tableData.total" v-model:page="tableData.param.pageNum" v-model:limit="tableData.param.pageSize" @pagination="getDeviceList" />
+
+    </el-dialog>
+  </div>
+</template>
+<script lang="ts">
+import { toRefs, reactive, defineComponent, nextTick, getCurrentInstance } from 'vue'
+import { ElMessageBox, ElMessage } from 'element-plus'
+
+import 'vue3-json-viewer/dist/index.css'
+
+import { useRoute } from 'vue-router'
+
+import api from '/@/api/device'
+
+interface TableDataState {
+  isShowDialog: boolean,
+  productData: object[],
+  deviceKeyList: string[];
+  deviceIdList: string[];
+  deviceNameList: string[];
+  checkIdList: string[];
+  tableData: {
+    data: []
+    total: number
+    loading: boolean
+    param: {
+      pageNum: number
+      pageSize: number
+      name: string
+    }
+  },
+  ruleForm: {
+    productId: string | number
+  },
+  rules: {}
+}
+export default defineComponent({
+  name: 'DeviceBindDialog',
+
+  setup(prop, { emit }) {
+    const { proxy } = getCurrentInstance() as any;
+    const route = useRoute()
+    const state = reactive<TableDataState>({
+      deviceKeyList: [],
+      deviceIdList: [],
+      deviceNameList: [],
+      isShowDialog: false,
+      productData: [],
+      checkIdList: [],
+      tableData: {
+        data: [],
+        total: 0,
+        loading: false,
+        param: {
+          pageNum: 1,
+          pageSize: 10,
+          name: '',
+        },
+      },
+      ruleForm: {
+        productId: ''
+      },
+      rules: {
+        productId: [{ required: true, message: '所属产品不能为空', trigger: 'blur' }],
+      }
+    })
+
+    const getDeviceList = () => {
+      if (!state.ruleForm.productId) {
+        state.tableData.data = [];
+        state.tableData.total = 0;
+        return;
+      }
+      state.tableData.loading = true;
+      api.instance.getList(state.tableData.param).then((res: any) => {
+        state.tableData.data = res.device;
+        state.tableData.total = res.total;
+
+        changeSelect();
+      }).finally(() => (state.tableData.loading = false));
+    };
+
+    const getProductList = () => {
+      api.product.getSubList().then((res: any) => {
+        let productDataList = res.product
+        state.productData = productDataList;
+        state.ruleForm.productId = state.productData[0].id
+        getDeviceList()
+        state.isShowDialog = true;
+      });
+    };
+
+    const openDialog = (checkIdData: any) => {
+      state.checkIdList = checkIdData;
+      getProductList()
+    };
+
+    // 多选框选中数据
+    const handleSelectionChange = (selection: any[]) => {
+      state.deviceKeyList = selection.map((item) => item.key);
+      state.deviceIdList = selection.map((item) => item.id);
+      state.deviceNameList = selection.map((item) => item.name);
+    };
+
+    const confirmBind = () => {
+      let msg = '是否确定选择设备?';
+      if (state.deviceKeyList.length === 0) {
+        ElMessage.error('请选择要确定绑定的数据。');
+        return;
+      }
+      ElMessageBox.confirm(msg, '提示', {
+        confirmButtonText: '确认',
+        cancelButtonText: '取消',
+        type: 'warning',
+      }).then(() => {
+        emit('bindSuccess', state.deviceIdList, state.deviceNameList)
+        state.isShowDialog = false;
+      })
+    };
+
+    const handleChange = (productId: number) => {
+      state.ruleForm.productId = productId;
+      getDeviceList()
+    }
+
+    const changeSelect = () => {
+      nextTick(() => {
+        state.tableData.data.forEach((item) => {
+          if (state.checkIdList.includes(item.id)) {
+            proxy.$refs.multipleTable.toggleRowSelection(item, true);
+          }
+        })
+      });
+    };
+
+    return {
+      openDialog,
+      getProductList,
+      confirmBind,
+      getDeviceList,
+      handleSelectionChange,
+      handleChange,
+      ...toRefs(state),
+    }
+  },
+})
+</script>
+
+

+ 138 - 0
src/views/iot/ota-update/update/component/deviceList.vue

@@ -0,0 +1,138 @@
+<template>
+  <div class="ota-edit-module-container">
+    <el-dialog :title="'设备详情'" v-model="isShowDialog" width="769px">
+      <div class="search">
+        <el-form :inline="true" ref="queryRef">
+          <el-form-item label="设备名称:" prop="name">
+            <el-input v-model="tableData.param.deviceName" placeholder="请输入设备名称" clearable size="default" style="width: 240px" @submit.prevent />
+          </el-form-item>
+
+          <el-form-item>
+
+            <el-button size="default" type="primary" class="ml10" @click="getDetail">
+              <el-icon>
+                <ele-Search />
+              </el-icon>
+              查询
+            </el-button>
+          </el-form-item>
+
+        </el-form>
+      </div>
+      <el-table :data="tableData.data" style="width: 100%" row-key="id" v-loading="tableData.loading">
+        <el-table-column prop="id" label="ID" width="60" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="deviceName" label="设备名称" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="status" label="状态" show-overflow-tooltip>
+          <template #default="scope">
+            <el-tag size="small" v-if="scope.row.status == 0">待推送</el-tag>
+            <el-tag size="small" v-if="scope.row.status == 1">已推送</el-tag>
+            <el-tag size="small" v-if="scope.row.status == 2">升级中</el-tag>
+            <el-tag size="small" v-if="scope.row.status == 3">升级成功</el-tag>
+            <el-tag size="small" v-if="scope.row.status == 4">升级失败</el-tag>
+            <el-tag size="small" v-if="scope.row.status == 5">已取消</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="step" label="升级进度" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="fail" label="失败原因" width="100" align="center">
+          <template #default="scope">
+            <el-tag size="small" v-if="scope.row.fail == -1">升级失败</el-tag>
+            <el-tag size="small" v-if="scope.row.fail == -2">下载失败</el-tag>
+            <el-tag size="small" v-if="scope.row.fail == -3">校验失败</el-tag>
+            <el-tag size="small" v-if="scope.row.fail == -4">烧写失败</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="createdAt" label="时间" min-width="100" align="center"></el-table-column>
+      </el-table>
+      <pagination v-show="tableData.total > 0" :total="tableData.total" v-model:page="tableData.param.pageNum" v-model:limit="tableData.param.pageSize" @pagination="getDetail" />
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts">
+import api from '/@/api/ota';
+import {defineComponent, reactive, toRefs} from 'vue';
+
+interface TableDataRow {
+  id: number;
+  name: string;
+  typo: string;
+  productName: number;
+  moduleName: string;
+  checkres: string;
+  createdAt: string;
+}
+
+interface TableDataState {
+  ids: number[];
+  tableData: {
+    data: Array<TableDataRow>;
+    total: number;
+    loading: boolean;
+    param: {
+      pageNum: number;
+      pageSize: number;
+      deviceName: string;
+      devOtaFirmwareId: number;
+    };
+  };
+  isShowDialog: boolean;
+}
+
+export default defineComponent({
+  setup(prop) {
+    const state = reactive<TableDataState>({
+      ids: [],
+      tableData: {
+        data: [],
+        total: 0,
+        loading: false,
+        param: {
+          pageNum: 1,
+          pageSize: 10,
+          deviceName: '',
+          devOtaFirmwareId: 0,
+        },
+      },
+      isShowDialog: false,
+    });
+    // 打开弹窗
+    const openDialog = (row: any) => {
+      state.tableData.loading = true;
+      state.tableData.param.devOtaFirmwareId = Number(row.id);
+      api.device.getList(state.tableData.param).then((res: any) => {
+        state.tableData.data = res.Data;
+        state.tableData.total = res.Total;
+      }).finally(() => (state.tableData.loading = false));
+      state.isShowDialog = true;
+    };
+    // 关闭弹窗
+    const closeDialog = () => {
+      state.isShowDialog = false;
+    };
+    // 取消
+    const onCancel = () => {
+      closeDialog();
+    };
+    const getDetail = () => {
+      state.tableData.loading = true;
+      api.device.getList(state.tableData.param).then((res: any) => {
+        state.tableData.data = res.Data;
+        state.tableData.total = res.Total;
+      }).finally(() => (state.tableData.loading = false));
+    };
+    return {
+      getDetail,
+      openDialog,
+      closeDialog,
+      onCancel,
+      ...toRefs(state),
+    };
+  },
+});
+</script>
+
+<style lang="scss" scoped>
+.width100 {
+  width: 100%;
+}
+</style>