Sfoglia il codice sorgente

修改ota验证部分,协议,批次,升级包版本号验证,添加模块,地图修改

Xiahai 1 anno fa
parent
commit
5dccb3a10f

+ 7 - 7
src/api/ota/index.ts

@@ -3,31 +3,31 @@ import { get, post, del, put } from '/@/utils/request';
 export default {
   manage: {
     getList: (data: any) => get('/operate/ota_firmware/list', data),
-    del: (ids: number) => del('/operate/ota_firmware/delete', { ids }),
+    del: (ids: number) => del('/operate/ota_firmware/delete', {ids}),
     add: (data: any) => post('/operate/ota_firmware/add', data),
     edit: (data: any) => put('/operate/ota_firmware/edit', data),
-    detail: (id: number) => get('/operate/ota_firmware/get', { id }),
+    detail: (id: number) => get('/operate/ota_firmware/get', {id}),
 
   },
   module: {
     getSubList: () => get('/product/list'),
     getList: (data: any) => get('/operate/ota_module/list', data),
-    del: (ids: number) => del('/operate/ota_module/delete', { ids }),
+    del: (ids: number) => del('/operate/ota_module/delete', {ids}),
     add: (data: any) => post('/operate/ota_module/add', data),
     edit: (data: any) => put('/operate/ota_module/edit', data),
-    detail: (id: number) => get('/operate/ota_module/get', { id }),
+    detail: (id: number) => get('/operate/ota_module/get', {id}),
   },
   batch: {
     getList: (data: any) => get('/operate/ota_strategy/list', data),
     getDeviceList: (data: any) => get('/product/device/list', data),
-    del: (ids: number) => del('/operate/ota_strategy/delete', { ids }),
+    del: (ids: number) => del('/operate/ota_strategy/delete', {ids}),
     add: (data: any) => post('/operate/ota_strategy/add', data),
     edit: (data: any) => put('/operate/ota_strategy/edit', data),
   },
   device: {
     getList: (data: any) => get('/operate/ota_detail/list', data),
-    del: (ids: number) => del('/operate/ota_detail/delete', { ids }),
+    del: (ids: number) => del('/operate/ota_detail/delete', {ids}),
     add: (data: any) => post('/operate/ota_detail/add', data),
     edit: (data: any) => post('/operate/ota_detail/edit', data),
   }
-}
+}

+ 12 - 0
src/utils/validator.ts

@@ -22,4 +22,16 @@ export const validateNoSpace = (rule: any, value: any, callback: any) => {
   } else {
     callback();
   }
+}
+
+// 校验版本号
+export const checkVersion = (rule: any, value: any, callback: any) => {
+  if (!value) {
+    return callback()
+  }
+
+  if (!/^(\d{1,3}\.){2}\d{1,3}$/.test(value)) {
+    callback(new Error('输入版本号格式错误,示例:(xx.xxx.xxx)'))
+  }
+  return callback()
 }

+ 7 - 1
src/views/iot/device/instance/component/map.vue

@@ -39,11 +39,13 @@
 <script lang="ts" setup>
 import { defineEmits, defineExpose, nextTick, ref } from 'vue';
 import { Search } from '@element-plus/icons-vue';
+import editDic from "/@/views/system/dict/component/editDic.vue";
 
 const mapContainer = ref<HTMLElement | null>(null);
 const address = ref('');
 const lng = ref('');
 const lat = ref('');
+const editMap = ref(false);
 const oldAddress = ref('');
 
 const searchKeyword = ref(''); // 搜索输入框的值
@@ -55,6 +57,7 @@ let map: BMapGL.Map | null = null;
 const openDialog = (row: any) => {
   oldAddress.value = '';
   isShowDialog.value = true;
+  editMap.value = false;
   nextTick(() => {
     map = new BMapGL.Map(mapContainer.value!);
     map.centerAndZoom('沈阳市', 10);
@@ -81,6 +84,7 @@ const openDialog = (row: any) => {
     if (row.lng && row.lat) {
       lng.value = row.lng;
       lat.value = row.lat;
+      editMap.value = true;
       searchByCoordinate();
     }
 
@@ -110,6 +114,9 @@ const setMarker = (lng: string, lat: string) => {
   map?.addOverlay(marker.value);
   // 移动地图中心到选点位置
   map?.setCenter(point);
+  if (editMap.value == true) {
+    map?.centerAndZoom();
+  }
 };
 
 const setAddressByCoordinate = (lng: string | number, lat: string | number) => {
@@ -139,7 +146,6 @@ const searchByCoordinate = () => {
     lng.value = "";
     lat.value = "";
     searchByKeyword(searchKeyword.value);
-
   }
 };
 

+ 1 - 1
src/views/iot/device/instance/detail.vue

@@ -112,7 +112,7 @@
                 </tr>
                 <tr class="ant-descriptions-row">
                   <th class="ant-descriptions-item-label ant-descriptions-item-colon">详细地址</th>
-                  <td class="ant-descriptions-item-content" colspan="1">{{ detail.address }}</td>
+                  <td class="ant-descriptions-item-content" colspan="5">{{ detail.address }}</td>
                 </tr>
                 <tr class="ant-descriptions-row">
                   <th class="ant-descriptions-item-label ant-descriptions-item-colon">说明</th>

+ 1 - 1
src/views/iot/ota-update/module/component/edit.vue

@@ -28,7 +28,7 @@
 </template>
 
 <script lang="ts">
-import { reactive, toRefs, defineComponent, ref, unref, getCurrentInstance,} from 'vue';
+import { reactive, toRefs, defineComponent, ref, unref} from 'vue';
 import { ElMessage } from 'element-plus';
 import api from '/@/api/ota';
 interface RuleFormState {

+ 91 - 16
src/views/iot/ota-update/update/component/batch.vue

@@ -33,7 +33,19 @@
       <el-table :data="tableData.data" style="width: 100%" v-loading="tableData.loading">
         <el-table-column prop="id" label="ID" width="60" />
         <el-table-column prop="name" label="名称" />
-        <el-table-column prop="waitVersion" label="待升级版本号" />
+<!--        <el-table-column prop="waitVersion" label="待升级版本号" width="120" />-->
+        <el-table-column label="类型" prop="typo" width="120" align="center">
+          <template #default="scope">
+            <el-tag type="success" size="small" v-if="scope.row.typo == 0">验证</el-tag>
+            <el-tag type="info" size="small" v-else>升级</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="状态" prop="active" width="120" align="center">
+          <template #default="scope">
+            <el-tag type="success" size="small" v-if="scope.row.active == 1">是</el-tag>
+            <el-tag type="info" size="small" v-else>否</el-tag>
+          </template>
+        </el-table-column>
         <el-table-column prop="method" label="协议方式" show-overflow-tooltip>
           <template #default="scope">
             <el-tag size="small" v-if="scope.row.method == 1">http</el-tag>
@@ -47,6 +59,7 @@
             <el-tag size="small" v-if="scope.row.stratege == 2">动态升级</el-tag>
           </template>
         </el-table-column>
+
         <el-table-column prop="push" label="主动推送" show-overflow-tooltip>
           <template #default="scope">
             <el-tag size="small" v-if="scope.row.push == 1">是 </el-tag>
@@ -54,12 +67,14 @@
           </template>
         </el-table-column>
         <el-table-column prop="createdAt" label="创建时间" min-width="100" align="center" />
-        <!-- <el-table-column label="操作" width="200" align="center">
-          <template #default="scope">
-            <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>
-          </template>
-        </el-table-column> -->
+<!--        <el-table-column label="操作" width="200" align="center">-->
+<!--          <template #default="scope">-->
+<!--            &lt;!&ndash;            <el-button size="small" text type="warning" v-auth="'edit'" @click="CheckUpdate(scope.row)">编辑</el-button>&ndash;&gt;-->
+<!--            &lt;!&ndash;            <el-button size="small" text type="danger" v-auth="'del'" @click="del(scope.row)">删除</el-button>&ndash;&gt;-->
+<!--            <el-button size="small" text type="success" v-if="scope.row.active != 1" @click="activation(scope.row)">激活</el-button>-->
+<!--            <el-button size="small" text type="danger" v-else @click="activation(scope.row)">禁用</el-button>-->
+<!--          </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()" />-->
@@ -73,7 +88,7 @@
 <script lang="ts">
 import api from '/@/api/ota';
 import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue';
-import { ElMessageBox, ElMessage, FormInstance } from 'element-plus'
+import { ElMessageBox, ElMessage } from 'element-plus'
 import CheckConfig from '/@/views/iot/ota-update/update/component/check.vue';
 
 // 定义接口来定义对象的类型
@@ -134,6 +149,18 @@ export default defineComponent({
     onMounted(() => {
       initTableData();
     });
+    // 激活操作
+    const activation = (row: any) => {
+      let active = 0;
+      console.log(row);
+      if (row.active === 1) active = 0;
+      if (row.active === 0) active = 1;
+      console.log(active);
+      api.batch.stop({id: row.id, active: active}).then((res: any) => {
+        ElMessage.success('操作成功');
+        batchList();
+      });
+    };
     // 初始化表格数据
     const initTableData = () => {
       batchList();
@@ -143,12 +170,12 @@ export default defineComponent({
       state.tableData.loading = true;
       state.tableData.param.devOtaFirmwareId = props.detail.id;
       api.batch
-        .getList(state.tableData.param)
-        .then((res: any) => {
-          state.tableData.data = res.Data;
-          state.tableData.total = res.Total;
-        })
-        .finally(() => (state.tableData.loading = false));
+          .getList(state.tableData.param)
+          .then((res: any) => {
+            state.tableData.data = res.Data;
+            state.tableData.total = res.Total;
+          })
+          .finally(() => (state.tableData.loading = false));
     };
     // 打开新增弹窗
     const onOpenAdd = () => {
@@ -179,7 +206,7 @@ export default defineComponent({
           getList();
         });
       })
-        .catch(() => { });
+          .catch(() => { });
     };
     /** 重置按钮操作 */
     const resetQuery = () => {
@@ -201,6 +228,7 @@ export default defineComponent({
       onOpenAdd,
       onRowDel,
       getList,
+      activation,
       resetQuery,
       handleSelectionChange,
       ...toRefs(props),
@@ -208,5 +236,52 @@ export default defineComponent({
     };
   },
 });
-
+// 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>

+ 232 - 85
src/views/iot/ota-update/update/component/check.vue

@@ -1,130 +1,198 @@
 <template>
-	<!-- <el-dialog
-		class="api-edit"
-		v-model="showDialog"
-		:title="`${formData.id ? '编辑批次' : '新增批次'}`"
-		width="768px"
-		:close-on-click-modal="false"
-		:close-on-press-escape="false">
-		<el-form ref="formRef" :model="formData" :rules="ruleForm" label-width="160px"> -->
-	<div class="ota-edit-module-container">
-		<el-dialog :title="'验证升级包'" v-model="isShowDialog" width="769px">
-			<el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="160px">
-				<el-form-item label="批次名称" prop="name">
-					<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="method">
-					<el-radio-group v-model="ruleForm.method">
-						<el-radio label="1">http</el-radio>
-						<el-radio label="2">https</el-radio>
-						<el-radio label="3">mqtt</el-radio>
-					</el-radio-group>
-				</el-form-item>
-
-				<el-form-item label="所属设备" prop="devices" v-if="ruleForm.method == '3'">
-					<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-form-item>
-
-				<el-form-item label="升级方式" prop="stratege">
-					<el-radio-group v-model="ruleForm.stratege">
-						<el-radio label="1">静态升级</el-radio>
-						<el-radio label="2">动态升级</el-radio>
-					</el-radio-group>
-				</el-form-item>
-
-				<el-form-item label="主动推送" prop="push">
-					<el-radio-group v-model="ruleForm.push">
-						<el-radio label="1">是</el-radio>
-						<el-radio label="2">否</el-radio>
-					</el-radio-group>
-				</el-form-item>
-			</el-form>
-			<template #footer>
+  <!-- <el-dialog
+    class="api-edit"
+    v-model="showDialog"
+    :title="`${formData.id ? '编辑批次' : '新增批次'}`"
+    width="768px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false">
+    <el-form ref="formRef" :model="formData" :rules="ruleForm" label-width="160px"> -->
+  <div class="ota-edit-module-container">
+    <el-dialog :title="'操作升级包'" v-model="isShowDialog" width="769px">
+      <el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="160px">
+        <el-form-item label="类型" prop="formType" @change="getFormType">
+          <el-radio-group v-model="ruleForm.typo">
+            <el-radio label="1">验证</el-radio>
+            <el-radio label="2">升级</el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <el-form-item label="批次名称" prop="name">
+          <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="method">
+          <el-radio-group v-model="ruleForm.method" @change="getMethod">
+            <el-radio label="1">http</el-radio>
+            <el-radio label="2">https</el-radio>
+            <el-radio label="3">mqtt</el-radio>
+          </el-radio-group>
+        </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-form-item>
+
+        <el-form-item label="升级方式" prop="stratege">
+          <el-radio-group v-model="ruleForm.stratege">
+            <el-radio label="1" disabled>静态升级</el-radio>
+            <el-radio label="2">动态升级</el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <el-form-item label="主动推送" prop="push">
+          <el-radio-group v-model="ruleForm.push">
+            <el-radio label="1" :disabled="ruleForm.pushDisabled">是</el-radio>
+            <el-radio label="2">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
 				<span class="dialog-footer">
 				<el-button @click="onCancel" size="default">取 消</el-button>
 				<el-button type="primary" @click="onSubmit" size="default">{{ruleForm.id!==0?'修 改':'添 加'}}</el-button>
 				</span>
-			</template>
-		</el-dialog>
-	</div>
+      </template>
+    </el-dialog>
+  </div>
 </template>
 
 <script lang="ts">
-import { reactive, toRefs, defineComponent, ref, unref} from 'vue';
+import { reactive, toRefs, defineComponent, onMounted, ref, unref} from 'vue';
 import { ElMessage } from 'element-plus';
 import api from '/@/api/ota';
+import rule from "/@/api/rule";
 
 interface RuleFormState {
   id: number;
   name: string;
   waitVersion: string;
   method: string;
-  devices: string;
+  devices: Array;
   stratege: string;
-  devOtaFirmwareId: number;
+  devOtaFirewareId: number;
   push: string;
+  pushDisabled: boolean,
+  typo: string;
+  productId: string;
 }
 interface UpdateState {
   isShowDialog: boolean;
   ruleForm: RuleFormState;
   productData: [];
   rules: {};
+  deviceShow: boolean;
 }
 
 export default defineComponent({
   name: 'otaEditUpdateData',
+  computed: {
+    rule() {
+      return rule
+    }
+  },
   setup(prop, { emit }) {
     const formRef = ref<HTMLElement | null>(null);
     const state = reactive<UpdateState>({
-		isShowDialog: false,
-		ruleForm: {
-			id: 0,
-			name: '',
-			waitVersion: '',
-			method: '',
-			devices: '',
-			stratege: '',
-      devOtaFirmwareId: 0,
-			push: '',
-		},
-	  	productData: [],
-      	rules: {
-        	name: [{ required: true, message: '批次名称不能为空', trigger: 'blur' }],
-			    waitVersion: [{ required: true, message: '待升级版本号不能为空', trigger: 'blur' }],
-			    method: [{ required: true, message: '协议方式不能为空', trigger: 'blur' }],
-			    stratege: [{ required: true, message: '升级方式不能为空', trigger: 'blur' }],
-			    devices: [{ required: true, message: '所属设备不能为空', trigger: 'blur' }],
-          push: [{ required: true, message: '推送方式不能为空', trigger: 'blur' }],
-      	},
+      isShowDialog: false,
+      ruleForm: {
+        id: 0,
+        name: '',
+        waitVersion: '',
+        method: '1',
+        devices: [],
+        stratege: '2',
+        devOtaFirewareId: 0,
+        push: '2',
+        pushDisabled: true,
+        typo: '1',
+        productId: '',
+      },
+      productData: [],
+      rules: {
+        name: [{ required: true, message: '批次名称不能为空', trigger: 'blur' }],
+        method: [{ required: true, message: '协议方式不能为空', trigger: 'blur' }],
+        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, // 所属设备是否显示
     });
+    // 页面加载时
+    onMounted(() => {
+      getProductList();
+      getFormType();
+    });
+    // 获取操作升级包类型
+    const getFormType = () => {
+      // 如果是验证类型,设备信息必填项
+      if (state.ruleForm.typo === '1') {
+        state.rules.devices = [{
+          required: true,
+          message: '所属设备不能为空',
+          trigger: 'blur'
+        }];
+      } else { // 如果是升级类型,设备可选可不选
+        delete (state.rules.devices);
+        state.deviceShow = false;
+      }
+    };
+    // 获取协议方式
+    const getMethod = () => {
+      // 如果是http、https协议则主动推送为否
+      if (state.ruleForm.method === '1' || state.ruleForm.method === '2') {
+        state.ruleForm.push = '2';
+        state.ruleForm.pushDisabled = true;
+      } else {
+        state.ruleForm.pushDisabled = false;
+        state.ruleForm.push = '';
+      }
+    };
+    const getProductList = () => {
+      api.batch.getDeviceList({ productId: state.ruleForm.productId}).then((res: any) => {
+        state.productData = res.device
+      })
+    }
     // 打开弹窗
     const openDialog = (row: RuleFormState | null) => {
       resetForm();
       if (row) {
         // api.manage.detail(row.id).then((res: any) => {
-          state.ruleForm.devOtaFirmwareId = row.id;
+        state.ruleForm.devOtaFirewareId = row.id;
         // });
+        state.ruleForm.productId = row.productId;
       }
       state.isShowDialog = true;
+
+      if (state.ruleForm.typo == '1') {
+        state.deviceShow = true;
+      }
     };
     const resetForm = () => {
-      	state.ruleForm = {
-        	id: 0,
-          name: '',
-          waitVersion: '',
-          method: '',
-          devices: '',
-          stratege: '',
-          devOtaFirmwareId: 0,
-          push: '',
-      	};
+      state.ruleForm = {
+        id: 0,
+        name: '',
+        waitVersion: '',
+        method: '1',
+        devices: [],
+        stratege: '2',
+        devOtaFirewareId: 0,
+        push: '2',
+        pushDisabled: true,
+        typo: '1',
+        productId: '',
+      };
     };
     // 关闭弹窗
     const closeDialog = () => {
@@ -163,10 +231,89 @@ export default defineComponent({
       closeDialog,
       onCancel,
       onSubmit,
+      getMethod,
+      getFormType,
       formRef,
       ...toRefs(state),
     };
   },
 });
 
+
+// import { ref, reactive, nextTick } from 'vue'
+// import api from '/@/api/ota'
+// import { ruleRequired } from '/@/utils/validator'
+// import { ElMessage } from 'element-plus'
+
+
+// const emit = defineEmits(['getList'])
+
+// const showDialog = ref(false)
+// const formRef = ref()
+
+// const productData = ref([
+// 	{
+// 		id: '',
+// 		name: '',
+// 	},
+// ])
+// const baseForm = {
+// 	id: undefined,
+// 	method: '1',
+// 	push: '1',
+// 	name: '',
+// 	devices: '',
+// 	stratege: '1',
+// 	waitVersion: '',
+// 	devOtaFirewareId: '',
+// 	productId:'',
+// }
+
+// const formData = reactive({
+// 	...baseForm,
+// })
+
+// const ruleForm = {
+// 	method: [ruleRequired('请选择批次类型')],
+// 	name: [ruleRequired('批次名称不能为空')],
+// 	productId: [ruleRequired('请选择所属产品')],
+// 	devices: [ruleRequired('请选择批次模块')],
+// 	stratege: [ruleRequired('批次版本号不能为空')],
+// 	waitVersion: [ruleRequired('升级后版本号不能为空')],
+// }
+
+
+// const onSubmit = async () => {
+// 	await formRef.value.validate()
+
+// 	const theApi = formData.id ? api.batch.edit : api.batch.add
+// 	await theApi(formData)
+// 	ElMessage.success('操作成功')
+// 	resetForm()
+// 	showDialog.value = false
+// 	emit('getList')
+// }
+
+// const resetForm = async () => {
+// 	Object.assign(formData, { ...baseForm })
+// 	formRef.value && formRef.value.resetFields()
+// }
+
+// const open = async (row: any) => {
+// 	resetForm()
+// 	showDialog.value = true
+// 	nextTick(() => {
+// 		Object.assign(formData, { ...row })
+// 		getProductList()
+
+// 	})
+// }
+
+// defineExpose({ open })
 </script>
+
+<style lang="scss" scoped>
+.width100 {
+  width: 100%;
+}
+</style>

+ 50 - 7
src/views/iot/ota-update/update/component/edit.vue

@@ -5,7 +5,7 @@
         <el-form-item label="升级包类型" prop="typo">
           <el-radio-group v-model="ruleForm.typo">
             <el-radio label="1">整包</el-radio>
-            <el-radio label="2">差分</el-radio>
+            <el-radio label="2" disabled>差分</el-radio>
           </el-radio-group>
         </el-form-item>
 
@@ -23,6 +23,9 @@
           <el-select v-model="ruleForm.module" placeholder="请选择升级包模块">
             <el-option v-for="item in moduleData" :key="item.id" :label="item.name" :value="item.id.toString()" />
           </el-select>
+
+          <!-- 添加模块 -->
+          <el-button type="success" @click="onOpenAddDic()" style="margin-left: 5px;">添加升级包模块</el-button>
         </el-form-item>
 
         <el-form-item label="升级包版本号" prop="version" v-if="ruleForm.typo == '1'">
@@ -44,7 +47,7 @@
         </el-form-item>
 
         <el-form-item label="选择升级包" prop="url">
-          <el-upload :file-list="fileList" :accept="['.doc', '.docx', '.zip', '.xls', '.xlsx', '.rar', '.jpg', '.jpeg', '.gif', '.npm', '.png', '.cert']" :show-file-list="false" :limit="1" :headers="headers" :action="uploadUrl" :on-success="updateImg">
+          <el-upload :file-list="fileList" :accept="fileAccept" :show-file-list="false" :limit="1" :headers="headers" :action="uploadUrl" :on-success="updateImg">
             <el-button type="Default">上传升级包</el-button>
           </el-upload>
           <div v-if="ruleForm.urlName" style="color: green;margin-left: 10px;">{{ ruleForm.urlName }},上传成功</div>
@@ -73,14 +76,20 @@
         </span>
       </template>
     </el-dialog>
+
+    <!-- 添加模块 -->
+    <EditConfig ref="editDicRef"/>
   </div>
 </template>
 
 <script lang="ts">
-import { reactive, toRefs, defineComponent, ref, unref, getCurrentInstance, } from 'vue';
+import { reactive, toRefs, defineComponent, ref, unref } from 'vue';
 import { ElMessage } from 'element-plus';
 import api from '/@/api/ota';
 import getOrigin from '/@/utils/origin';
+import {checkVersion} from '/@/utils/validator';
+import apiSystem from "/@/api/system";
+import EditConfig from "/@/views/iot/ota-update/module/component/edit.vue";
 
 interface RuleFormState {
   id: number;
@@ -96,15 +105,19 @@ interface RuleFormState {
   describe: string;
   info: string;
   url: string;
+  ossurl: string,
   urlName: string;
 }
 
 interface UpdateState {
+  uploadUrl: string;
   isShowDialog: boolean;
   ruleForm: RuleFormState;
   productData: [];
   moduleData: [];
   rules: {};
+  uploadFileWay: number;
+  fileAccept: [];
 }
 
 export default defineComponent({
@@ -112,7 +125,7 @@ export default defineComponent({
   setup(prop, { emit }) {
     const formRef = ref<HTMLElement | null>(null);
     const headers = { Authorization: 'Bearer ' + localStorage.token, };
-    const uploadUrl: string = getOrigin(import.meta.env.VITE_API_URL + "/common/singleFile");
+    const editDicRef = ref();
     const areType = ref([
       {
         label: 'MD5',
@@ -126,6 +139,7 @@ export default defineComponent({
     const fileList = ref([]);
     const urlName = ref();
     const state = reactive<UpdateState>({
+      uploadUrl: '', // 上传地址
       isShowDialog: false,
       ruleForm: {
         id: 0,
@@ -141,6 +155,7 @@ export default defineComponent({
         describe: '',
         info: '',
         url: '',
+        ossurl: '',
         urlName: '',
       },
       productData: [],
@@ -150,19 +165,24 @@ export default defineComponent({
         name: [{ required: true, message: '升级包名称不能为空', trigger: 'change' }],
         productId: [{ required: true, message: '所属产品不能为空', trigger: 'change' }],
         module: [{ required: true, message: '升级包模块不能为空', trigger: 'change' }],
-        version: [{ required: true, message: '升级包版本号不能为空', trigger: 'change' }],
+        version: [
+            { required: true, message: '升级包版本号不能为空', trigger: 'change' },
+            { validator: checkVersion, message: '输入版本号格式错误,示例:(xx.xxx.xxx)', trigger: 'blue' }
+        ],
         waitVersion: [{ required: true, message: '待升级版本号不能为空', trigger: 'change' }],
         afterVersion: [{ required: true, message: '升级后版本号不能为空', trigger: 'change' }],
         are: [{ required: true, message: '算法签名不能为空', trigger: 'change' }],
         url: [{ required: true, message: '升级包不能为空', trigger: 'change' }],
       },
+      uploadFileWay: 0,// 上传方式
+      fileAccept: [], // 上传格式
     });
     // 打开弹窗
     const openDialog = (row: RuleFormState | null) => {
       resetForm();
       if (row) {
         api.manage.detail(row.id).then((res: any) => {
-          const data: RuleFormState = res.data.data;
+          const data: RuleFormState = res;
           state.ruleForm = data;
         });
         seletChange(row.productId);
@@ -175,6 +195,20 @@ export default defineComponent({
       });
 
       state.isShowDialog = true;
+
+      // 获取上传方式
+      apiSystem.getInfoByKey({ ConfigKey: 'sys.uploadFile.way' }).then((res: any) => {
+        state.uploadFileWay = parseInt(res.data.configValue);
+        state.uploadUrl = getOrigin(import.meta.env.VITE_API_URL + "/common/singleFile?Source=" + state.uploadFileWay);
+      });
+      // 获取上传格式
+      apiSystem.getInfoByKey({ ConfigKey: 'sys.uploadFile.fileType' }).then((res: any) => {
+        let fileType = res.data.configValue.split(",");
+        for (let i = 0; i < fileType.length; i++) {
+          fileType[i] = '.' + fileType[i];
+        }
+        state.fileAccept = fileType;
+      });
     };
     const resetForm = () => {
       state.ruleForm = {
@@ -191,6 +225,7 @@ export default defineComponent({
         describe: '',
         info: '',
         url: '',
+        ossurl: '',
         urlName: '',
       };
     };
@@ -198,6 +233,7 @@ export default defineComponent({
       if (res.code === 0) {
         state.ruleForm.url = res.data.full_path
         state.ruleForm.urlName = res.data.name
+        state.ruleForm.ossurl = res.data.full_path
         fileList.value = []
         ElMessage.success('上传成功');
       } else {
@@ -229,6 +265,7 @@ export default defineComponent({
         if (valid) {
           if (state.ruleForm.id !== 0) {
             //修改
+            state.ruleForm.ossurl = state.ruleForm.url;
             api.manage.edit(state.ruleForm).then(() => {
               ElMessage.success('升级包修改成功');
               closeDialog(); // 关闭弹窗
@@ -245,7 +282,12 @@ export default defineComponent({
         }
       });
     };
+    // 添加模块
+    const onOpenAddDic = () => {
+      editDicRef.value.openDialog();
+    };
     return {
+      editDicRef,
       openDialog,
       closeDialog,
       seletChange,
@@ -254,12 +296,13 @@ export default defineComponent({
       formRef,
       areType,
       headers,
-      uploadUrl,
       fileList,
       urlName,
       updateImg,
+      onOpenAddDic,
       ...toRefs(state),
     };
   },
+  components: {EditConfig},
 });
 </script>

+ 138 - 140
src/views/iot/ota-update/update/detail.vue

@@ -1,5 +1,5 @@
 <template>
-	<div>
+  <div>
     <el-card class="system-dic-container" style="position: relative">
       <div class="content">
         <div class="flex cont_box">
@@ -49,29 +49,27 @@
         </div> -->
       </div>
     </el-card>
-	  <div class="mt10"></div>
+    <div class="mt10"></div>
     <el-card class="system-dic-container" style="position: relative">
       <el-tabs v-model="activeTab">
-          <el-tab-pane label="批次管理" name="tab1">
-            <BatchList v-if="detail.id" :detail="detail" />
-          </el-tab-pane>
-          <el-tab-pane label="设备列表" name="tab2">
-            <DeviceList v-if="detail.id" :detail="detail" />
-          </el-tab-pane>
-          <el-tab-pane label="升级包信息" name="tab3">
-            <InfoList v-if="detail.id" :detail="detail" />
-          </el-tab-pane>
-        </el-tabs>
+        <el-tab-pane label="批次管理" name="tab1">
+          <BatchList v-if="detail.id" :detail="detail" />
+        </el-tab-pane>
+        <el-tab-pane label="设备列表" name="tab2">
+          <DeviceList v-if="detail.id" :detail="detail" />
+        </el-tab-pane>
+        <el-tab-pane label="升级包信息" name="tab3">
+          <InfoList v-if="detail.id" :detail="detail" />
+        </el-tab-pane>
+      </el-tabs>
     </el-card>
   </div>
 </template>
 <script lang="ts">
 import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue'
-import { ElMessage } from 'element-plus'
 import type { TabsPaneContext } from 'element-plus'
 import { useRoute } from 'vue-router'
 import { EditPen, DocumentAdd } from '@element-plus/icons-vue'
-// import EditForm from './edit.vue'
 import EditForm from '/@/views/iot/ota-update/update/component/edit.vue';
 import InfoList from './component/info.vue'
 import DeviceList from './component/device.vue'
@@ -81,152 +79,152 @@ import api from '/@/api/ota'
 const editFormRef = ref()
 
 export default defineComponent({
-	components: { EditPen, EditForm, DocumentAdd, InfoList, DeviceList, BatchList},
-	setup(props) {
-		const route = useRoute()
-		const state = reactive({
-			activeTab:'tab1',
-			developer_status: 2,
-			detail: {
-				id: '',
-				name: '',
-				typo: 1,
-				are: '',
-				moduleName: '',
-				checkres: 0,
+  components: { EditPen, EditForm, DocumentAdd, InfoList, DeviceList, BatchList},
+  setup(props) {
+    const route = useRoute()
+    const state = reactive({
+      activeTab:'tab1',
+      developer_status: 2,
+      detail: {
+        id: '',
+        name: '',
+        typo: 1,
+        are: '',
+        moduleName: '',
+        checkres: 0,
         productId: 0,
-			},
-			
-		})
-		const getDetail = () => {
+      },
+
+    })
+    const getDetail = () => {
       const id = route.params && route.params.id
-			api.manage.detail(Number(id)).then((res: any) => {
-				state.detail = res
-			})
-		}
-		const addOrEdit = async (row?: any) => {
-			editFormRef.value.open(row)
-		}
-
-		onMounted(() => {
-			getDetail()
-		})
-		const handleClick = (tab: TabsPaneContext, event: Event) => {
-			// console.log(tab, event)
-		}
-
-		return {
-			addOrEdit,
-			editFormRef,
-			getDetail,
-			handleClick,
-			...toRefs(props),
-			...toRefs(state),
-		}
-	},
+      api.manage.detail(Number(id)).then((res: any) => {
+        state.detail = res
+      })
+    }
+    const addOrEdit = async (row?: any) => {
+      editFormRef.value.open(row)
+    }
+
+    onMounted(() => {
+      getDetail()
+    })
+    const handleClick = (tab: TabsPaneContext, event: Event) => {
+      // console.log(tab, event)
+    }
+
+    return {
+      addOrEdit,
+      editFormRef,
+      getDetail,
+      handleClick,
+      ...toRefs(props),
+      ...toRefs(state),
+    }
+  },
 })
 </script>
 
 <style scoped lang="scss">
 .status_list{
-	width: 100%;
+  width: 100%;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px;
+  .otaflex{
+    font-size: 12px;
     display: flex;
-    justify-content: space-between;
     align-items: center;
-	padding: 10px;
-	.otaflex{
-		font-size: 12px;
-		display: flex;
-		align-items: center;
-		margin-left: -6px;
-		.otaflex_div1{
-			padding: 0 24px;
-			min-width: 200px;
-			width: fit-content;
-			.otaflex_div2 {
-				align-items: center;
-				.title{
-					color: #666;
-					font-size: 14px;
-				}
-				span {
-					display: block;
-					border-radius: 50%;
-					.on {
-						background: #52c41a;
-					}
-
-					.off {
-						background: #c41a1a;
-					}
-					.ofn {
-						background: rgb(255, 138, 0);
-					}
-
-					span {
-						position: relative;
-						top: -1px;
-						display: inline-block;
-						width:10px;
-						height: 10px;
-						vertical-align: middle;
-						border-radius: 50%;
-						margin-right: 5px;
-					}
-
-				}
-				.otaflex_div3{
-					font-size: 24px;
-					margin-top: 10px;
-					color: #373d41;
-				}
-			}
-	
-	
-		}
-		
-	}
+    margin-left: -6px;
+    .otaflex_div1{
+      padding: 0 24px;
+      min-width: 200px;
+      width: fit-content;
+      .otaflex_div2 {
+        align-items: center;
+        .title{
+          color: #666;
+          font-size: 14px;
+        }
+        span {
+          display: block;
+          border-radius: 50%;
+          .on {
+            background: #52c41a;
+          }
+
+          .off {
+            background: #c41a1a;
+          }
+          .ofn {
+            background: rgb(255, 138, 0);
+          }
+
+          span {
+            position: relative;
+            top: -1px;
+            display: inline-block;
+            width:10px;
+            height: 10px;
+            vertical-align: middle;
+            border-radius: 50%;
+            margin-right: 5px;
+          }
+
+        }
+        .otaflex_div3{
+          font-size: 24px;
+          margin-top: 10px;
+          color: #373d41;
+        }
+      }
+
+
+    }
+
+  }
 }
 .container {
-	display: flex;
-	padding: 10px;
+  display: flex;
+  padding: 10px;
 }
 
 .item {
-	flex: 1;
+  flex: 1;
 }
 .desc {
-	margin-top: 15px;
+  margin-top: 15px;
 }
 
 .edit {
-	line-height: 40px;
-	margin-top: 15px;
-	margin-left: 30px;
+  line-height: 40px;
+  margin-top: 15px;
+  margin-left: 30px;
 }
 
 .cont_box .pro-status {
-	line-height: 40px;
-	margin-left: 30px;
-	margin-top: 5px;
-
-	.on {
-		background: #52c41a;
-	}
-
-	.off {
-		background: #c41a1a;
-	}
-
-	span {
-		position: relative;
-		top: -1px;
-		display: inline-block;
-		width: 6px;
-		height: 6px;
-		vertical-align: middle;
-		border-radius: 50%;
-		margin-right: 5px;
-	}
+  line-height: 40px;
+  margin-left: 30px;
+  margin-top: 5px;
+
+  .on {
+    background: #52c41a;
+  }
+
+  .off {
+    background: #c41a1a;
+  }
+
+  span {
+    position: relative;
+    top: -1px;
+    display: inline-block;
+    width: 6px;
+    height: 6px;
+    vertical-align: middle;
+    border-radius: 50%;
+    margin-right: 5px;
+  }
 }
-</style>
+</style>

+ 81 - 81
src/views/iot/ota-update/update/index.vue

@@ -1,74 +1,74 @@
 <template>
-	<div class="ota-module-container">
-		<el-card shadow="hover">
-			<div class="ota-module-search mb15">
-				<el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="100px">
-					<el-form-item label="升级包名称" prop="keyWord">
-						<el-input
-							v-model="tableData.param.keyWord"
-							placeholder="请输入升级包名称"
-							clearable
-							size="default"
-							style="width: 240px;"
-							@keyup.enter.native="getList(1)" />
-					</el-form-item>
-					<el-form-item>
-						<el-button size="default" type="primary" class="ml10" @click="getList(1)">
-							<el-icon>
-								<ele-Search />
-							</el-icon>
-							查询
-						</el-button>
-						<el-button size="default" @click="resetQuery(queryRef)">
-							<el-icon>
-								<ele-Refresh />
-							</el-icon>
-							重置
-						</el-button>
-						<el-button type="primary" v-auth="'add'" @click="onOpenAdd()">
-							<el-icon>
-								<ele-FolderAdd />
-							</el-icon>
-							添加升级包
-						</el-button>
-					</el-form-item>
-				</el-form>
-			</div>
+  <div class="ota-module-container">
+    <el-card shadow="hover">
+      <div class="ota-module-search mb15">
+        <el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="100px">
+          <el-form-item label="升级包名称" prop="keyWord">
+            <el-input
+                v-model="tableData.param.keyWord"
+                placeholder="请输入升级包名称"
+                clearable
+                size="default"
+                style="width: 240px;"
+                @keyup.enter.native="getList(1)" />
+          </el-form-item>
+          <el-form-item>
+            <el-button size="default" type="primary" class="ml10" @click="getList(1)">
+              <el-icon>
+                <ele-Search />
+              </el-icon>
+              查询
+            </el-button>
+            <el-button size="default" @click="resetQuery(queryRef)">
+              <el-icon>
+                <ele-Refresh />
+              </el-icon>
+              重置
+            </el-button>
+            <el-button type="primary" v-auth="'add'" @click="onOpenAdd()">
+              <el-icon>
+                <ele-FolderAdd />
+              </el-icon>
+              添加升级包
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </div>
 
-			<el-table :data="tableData.data" style="width: 100%" v-loading="tableData.loading">
-				<el-table-column label="ID" v-col="'id'" align="center" prop="id" width="60" />
-				<el-table-column label="升级包名称" v-col="'name'" prop="name" :show-overflow-tooltip="true" />
-				<el-table-column prop="typo" label="类型" show-overflow-tooltip v-col="'typo'">
-					<template #default="scope">
-						<el-tag  size="small" v-if="scope.row.typo == 1">整包</el-tag>
-						<el-tag  type="info" size="small" v-if="scope.row.typo == 2">差分</el-tag>
-					</template>
-				</el-table-column>
-				<el-table-column label="所属产品" v-col="'productName'" prop="productName" :show-overflow-tooltip="true" />
-				<el-table-column label="模块名称" v-col="'moduleName'" prop="moduleName" :show-overflow-tooltip="true" />
-				<el-table-column label="状态" prop="checkres" v-col="'checkres'" width="120" align="center">
-					<template #default="scope">
-						<el-tag type="success" size="small" v-if="scope.row.checkres == 1">验证</el-tag>
-						<el-tag type="info" size="small" v-else>未验证</el-tag>
-					</template>
-				</el-table-column>
-				<el-table-column label="创建时间" prop="createdAt" align="center" />
-				<el-table-column label="操作" width="200" v-col="'handle'" align="center" fixed="right">
-					<template #default="scope">
-						<el-button size="small" text type="primary" v-if="!scope.row.folderName" @click="toDetail(scope.row.id)">查看</el-button>
-						<el-button size="small" text type="warning" v-auth="'edit'" @click="onOpenEdit(scope.row)">编辑</el-button>
-						<el-button size="small" text type="success" v-auth="'check'" @click="onOpenCheck(scope.row)">验证</el-button>
+      <el-table :data="tableData.data" style="width: 100%" v-loading="tableData.loading">
+        <el-table-column label="ID" v-col="'id'" align="center" prop="id" width="60" />
+        <el-table-column label="升级包名称" v-col="'name'" prop="name" :show-overflow-tooltip="true" />
+        <el-table-column prop="typo" label="类型" show-overflow-tooltip v-col="'typo'">
+          <template #default="scope">
+            <el-tag  size="small" v-if="scope.row.typo == 1">整包</el-tag>
+            <el-tag  type="info" size="small" v-if="scope.row.typo == 2">差分</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="所属产品" v-col="'productName'" prop="productName" :show-overflow-tooltip="true" />
+        <el-table-column label="模块名称" v-col="'moduleName'" prop="moduleName" :show-overflow-tooltip="true" />
+        <el-table-column label="状态" prop="checkres" v-col="'checkres'" width="120" align="center">
+          <template #default="scope">
+            <el-tag type="success" size="small" v-if="scope.row.checkres == 1">验证</el-tag>
+            <el-tag type="info" size="small" v-else>未验证</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="创建时间" prop="createdAt" align="center" />
+        <el-table-column label="操作" width="200" v-col="'handle'" align="center" fixed="right">
+          <template #default="scope">
+            <el-button size="small" text type="primary" v-if="!scope.row.folderName" @click="toDetail(scope.row.id)">查看</el-button>
+            <el-button size="small" text type="warning" v-auth="'edit'" @click="onOpenEdit(scope.row)">编辑</el-button>
+            <el-button size="small" text type="success" v-auth="'handle'" @click="onOpenCheck(scope.row)">操作</el-button>
 
-						<el-button size="small" text type="info" v-auth="'del'" @click="onRowDel(scope.row)">删除</el-button>
-					</template>
-				</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="getList" />
-			<EditConfig ref="editRef" @getList="getList(1)" />
+            <el-button size="small" text type="info" v-auth="'del'" @click="onRowDel(scope.row)">删除</el-button>
+          </template>
+        </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="getList" />
+      <EditConfig ref="editRef" @getList="getList(1)" />
 
       <CheckConfig ref="checkRef" @getList="getList(1)" />
-		</el-card>
-	</div>
+    </el-card>
+  </div>
 </template>
 
 <script lang="ts">
@@ -111,11 +111,11 @@ export default defineComponent({
     const router = useRouter();
     const editRef = ref();
     const checkRef = ref();
-	  const detailRef = ref();
+    const detailRef = ref();
     const queryRef = ref();
     const tabDataList = ref([{dictLabel: '全部', dictValue: ''}]);
     const state = reactive<TableDataState>({
-	  ids: [],
+      ids: [],
       tableData: {
         data: [],
         total: 0,
@@ -140,12 +140,12 @@ export default defineComponent({
       typeof pageNum === 'number' && (state.tableData.param.pageNum = pageNum)
       state.tableData.loading = true;
       api.manage
-        .getList(state.tableData.param)
-        .then((res: any) => {
-          state.tableData.data = res.firmware;
-          state.tableData.total = res.Total;
-        })
-        .finally(() => (state.tableData.loading = false));
+          .getList(state.tableData.param)
+          .then((res: any) => {
+            state.tableData.data = res.firmware;
+            state.tableData.total = res.Total;
+          })
+          .finally(() => (state.tableData.loading = false));
     };
     // 打开新增弹窗
     const onOpenAdd = () => {
@@ -185,12 +185,12 @@ export default defineComponent({
         cancelButtonText: '取消',
         type: 'warning',
       }).then(() => {
-          api.manage.del(ids).then(() => {
-            ElMessage.success('删除成功');
-            getList();
-          });
-        })
-        .catch(() => { });
+        api.manage.del(ids).then(() => {
+          ElMessage.success('删除成功');
+          getList();
+        });
+      })
+          .catch(() => { });
     };
     /** 重置按钮操作 */
     const resetQuery = (formEl: FormInstance | undefined) => {
@@ -223,4 +223,4 @@ export default defineComponent({
     };
   },
 });
-</script>
+</script>