Quellcode durchsuchen

Merge branch 'master' of http://git.mydig.net/Sagoo-Cloud/sagoo-admin-ui

vera_min vor 3 Jahren
Ursprung
Commit
c657320460

+ 22 - 2
src/api/device/index.ts

@@ -8,11 +8,12 @@ export default {
     getList: (params: object) => get('/product/page_list', params),
     getLists: (params: object) => get('/product/list', params),
     add: (data: object) => post('/product/add', data),
-    delete: (id: number) => del('/product/del', { id }),
+    delete: (ids: number) => del('/product/del', { ids }),
     edit: (data: object) => put('/product/edit', data),
     detail: (id: number) => get('/product/detail', { id }),
     message_protocol_list: (params: object) => get('/product/protocol/message_protocol_list', params),
     trunsport_protocol_list: (params: object) => get('/product/protocol/trunsport_protocol_list', params),
+    getDataType: (params: object) => get('/product/tsl/data_type', params),
   },
   category:{
     getList: (params: object) => get('/product/category/list', params),
@@ -24,11 +25,30 @@ export default {
     getList: (params: object) => get('/product/device/page_list', params),
     add: (data: object) => post('/product/device/add', data),
     edit: (data: object) => put('/product/device/edit', data),
-    del: (id: number) => del('/product/device/del', { id }),
+    del: (ids: number) => del('/product/device/del', { ids }),
   },
   dept: {
     getList: (params: object) => get('/system/dept/tree', params),
   },
+
+  model: {
+    property: (params: object) => get('/product/tsl/property/list', params),
+    propertyadd: (data: object) => post('/product/tsl/property/add', data),
+    propertydel: (productId: number,key:string) => del('/product/property/del', { productId,key }),
+
+    function: (params: object) => get('/product/tsl/function/list', params),
+    functionadd: (data: object) => post('/product/tsl/function/add', data),
+    functiondel: (productId: number,key:string) => del('/product/function/del', { productId,key }),
+
+
+    event: (params: object) => get('/product/tsl/event/list', params),
+    eventadd: (data: object) => post('/product/tsl/event/add', data),
+    eventdel: (productId: number,key:string) => del('/product/event/del', { productId,key }),
+
+    tag: (params: object) => get('/product/tsl/tag/list', params),
+    tagadd: (data: object) => post('/product/tsl/tag/add', data),
+    tagdel: (productId: number,key:string) => del('/product/tag/del', { productId,key }),
+  },
   
   
 }

+ 4 - 1
src/api/system/index.ts

@@ -43,7 +43,10 @@ export default {
     getRole: (id: number) => get('/system/role/getInfoById', { id }),
     addRole: (data: object) => post('/system/role/add', data),
     deleteRole: (id: number) => del('/system/role/delInfoById', { id }),
-    editRole: (data: object) => put('/system/role/edit', data)
+    editRole: (data: object) => put('/system/role/edit', data),
+    auth: {
+      getList: (itemsType: 'menu' | 'button' | 'column' | 'api' | string, menuIds?: number[]) => get('/system/authorize/query', { itemsType, menuIds }),
+    }
   },
   org: {
     getList: (params: object) => get('/system/organization/tree', params),

+ 5 - 1
src/theme/element.scss

@@ -185,7 +185,11 @@
 	overflow-y: auto;
 	overflow-x: hidden;
 }
-
+.el-dialog.is-fullscreen{
+	.el-dialog__body {
+		max-height: 100vh !important;
+	}
+}
 /* Card 卡片
 ------------------------------- */
 .el-card__header {

+ 4 - 3
src/views/device/instance/component/edit.vue

@@ -2,13 +2,14 @@
 	<div class="system-edit-dic-container">
 		<el-dialog :title="(ruleForm.id!==0?'修改':'添加')+'设备'" v-model="isShowDialog" width="769px">
 			<el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="110px">
+       <el-form-item label="设备标识" prop="key">
+          <el-input v-model="ruleForm.key" placeholder="请输入设备标识" />
+        </el-form-item>
         <el-form-item label="设备名称" prop="name">
           <el-input v-model="ruleForm.name" placeholder="请输入设备名称" />
         </el-form-item>
 
-         <el-form-item label="设备标识" prop="key">
-          <el-input v-model="ruleForm.key" placeholder="请输入设备标识" />
-        </el-form-item>
+        
 
            <el-form-item label="所属产品" prop="productId">
        

+ 1 - 1
src/views/device/instance/index.vue

@@ -69,7 +69,7 @@
          <el-table-column prop="lastOnlineTime" label="最后上线时间" align="center" width="180"></el-table-column> 
         <el-table-column label="操作" width="200" align="center">
           <template #default="scope">
-		   <router-link :to="'/device/instance/detail/id/' + scope.row.id" class="link-type" style="padding-right: 10px;color: #409eff;">
+		   <router-link :to="'/device/instance/detail/' + scope.row.id" class="link-type" style="padding-right: 10px;color: #409eff;">
               <span>详情</span>
             </router-link>
             <el-button size="small" text type="warning" @click="onOpenEditDic(scope.row)">修改</el-button>

+ 248 - 0
src/views/device/product/component/editAttr.vue

@@ -0,0 +1,248 @@
+<template>
+	<div class="system-edit-dic-container">
+		<el-dialog :title="(ruleForm.id !== 0 ? '修改' : '添加') + '属性定义'" v-model="isShowDialog" width="769px">
+			<el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="120px">
+				<el-form-item label="属性定义标识" prop="key">
+					<el-input v-model="ruleForm.key" placeholder="请输入属性定义标识" />
+				</el-form-item>
+				<el-form-item label="属性定义名称" prop="name">
+					<el-input v-model="ruleForm.name" placeholder="请输入属性定义名称" />
+				</el-form-item>
+
+				<el-form-item label="数据类型" prop="type">
+					<el-select v-model="valueType.type" placeholder="请选择数据类型" @change="seletChange">
+						<el-option-group v-for="group in typeData" :key="group.label" :label="group.label">
+							<el-option v-for="item in group.options" :key="item.type" :label="item.title" :value="item.type" />
+						</el-option-group>
+					</el-select>
+				</el-form-item>
+
+        <!--根据数据类型输出不同表单-->
+
+             <el-form-item label="精度" prop="maxLength1" v-if="type=='float' || type=='double'">
+                <el-input v-model="valueType.maxLength1" placeholder="请输入精度" />
+              </el-form-item>
+
+            	<el-form-item label="单位" prop="maxLength" v-if="type=='int' || type=='long' || type=='float'  || type=='double'">
+                <el-input v-model="valueType.maxLength" placeholder="请输入单位" />
+              </el-form-item>
+
+              <el-form-item label="最大长度" prop="maxLength" v-if="type=='string'">
+                <el-input v-model="valueType.maxLength" placeholder="请输入最大长度" />
+              </el-form-item>
+
+               <el-form-item label="时间格式" prop="maxLength" v-if="type=='date'">
+                <el-input v-model="valueType.maxLength" placeholder="请输入时间格式" />
+              </el-form-item>
+             
+
+        <!--根据数据类型输出不同表单-->
+
+
+
+
+
+
+
+
+				<el-form-item label="是否只读" prop="accessMode">
+					<el-radio-group v-model="ruleForm.accessMode" model-value="0">
+						<el-radio label="0">读写</el-radio>
+
+						<el-radio label="1">只读</el-radio>
+					</el-radio-group>
+				</el-form-item>
+				<el-form-item label="属性定义描述	" prop="desc">
+					<el-input v-model="ruleForm.desc" type="textarea" placeholder="请输入属性定义描述"></el-input>
+				</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>
+
+<script lang="ts">
+import { reactive, toRefs, defineComponent, ref, unref } from 'vue';
+import api from '/@/api/device';
+import uploadVue from '/@/components/upload/index.vue';
+import { ElMessage, UploadProps } from 'element-plus';
+
+interface RuleFormState {
+	id: number;
+	name: string;
+	dictType: string;
+	status: number;
+	desc: string;
+}
+interface DicState {
+	isShowDialog: boolean;
+	ruleForm: RuleFormState;
+	typeData: RuleFormState[];
+	rules: {};
+}
+
+export default defineComponent({
+	name: 'deviceEditPro',
+	components: { uploadVue },
+	setup(prop, { emit }) {
+		const formRef = ref<HTMLElement | null>(null);
+
+		const state = reactive<DicState>({
+			isShowDialog: false,
+			typeData: [], //
+      type: '',
+       valueType: {
+          type:'',
+          maxLength:'',
+
+        },
+
+			ruleForm: {
+				name: '',
+				key: '',
+				transportProtocol: '',
+				accessMode: '0',
+				status: 1,
+        valueType: {
+          type:'',
+          maxLength:'',
+
+        },
+				
+				desc: '',
+			},
+			rules: {
+				name: [{ required: true, message: '属性定义名称不能为空', trigger: 'blur' }],
+				key: [{ required: true, message: '属性定义标识不能为空', trigger: 'blur' }],
+				accessMode: [{ required: true, message: '请选择是否只读', trigger: 'blur' }],
+		
+			},
+		});
+
+		// 打开弹窗
+		const openDialog = (row: RuleFormState | null) => {
+			resetForm();
+
+			api.product.getDataType({ status: -1 }).then((res: any) => {
+				const datat = Object.values(res.dataType);
+				datat.forEach((item, index) => {
+					if (index == 0) {
+						datat[index]['label'] = '基础类型';
+						datat[index]['options'] = item;
+					} else {
+						datat[index]['label'] = '扩展类型';
+						datat[index]['options'] = item;
+					}
+				});
+				console.log(datat);
+				state.typeData = datat || [];
+			});
+
+			if (row) {
+				// api.dict.getType(row.dictId).then((res:any)=>{
+				//   state.ruleForm = res.data.dictType
+				// }
+				console.log(row);
+				state.ruleForm = row;
+			}
+			state.isShowDialog = true;
+		};
+		const resetForm = () => {
+			state.ruleForm = {
+				id: 0,
+				name: '',
+				dictType: '',
+				status: 1,
+				desc: '',
+			};
+		};
+
+    const seletChange=(val)=>{
+      state.type=val;
+      console.log(val);
+    };
+		// 关闭弹窗
+		const closeDialog = () => {
+			state.isShowDialog = false;
+		};
+		// 取消
+		const onCancel = () => {
+			closeDialog();
+		};
+		// 新增
+		const onSubmit = () => {
+			const formWrap = unref(formRef) as any;
+			if (!formWrap) return;
+			formWrap.validate((valid: boolean) => {
+				if (valid) {
+					if (state.ruleForm.id !== 0) {
+						//修改
+						api.product.edit(state.ruleForm).then(() => {
+							ElMessage.success('属性定义类型修改成功');
+							closeDialog(); // 关闭弹窗
+							emit('typeList');
+						});
+					} else {
+						//添加
+         
+            console.log(state.valueType);
+            state.ruleForm.valueType=state.valueType;
+           console.log(state.ruleForm);
+						api.model.propertyadd(state.ruleForm).then(() => {
+							ElMessage.success('属性定义类型添加成功');
+							closeDialog(); // 关闭弹窗
+							emit('typeList');
+						});
+					}
+				}
+			});
+		};
+
+		return {
+			openDialog,
+      seletChange,
+			closeDialog,
+			onCancel,
+			onSubmit,
+			formRef,
+			...toRefs(state),
+		};
+	},
+});
+</script>
+
+<style scoped>
+.avatar-uploader .avatar {
+	width: 178px;
+	height: 178px;
+	display: block;
+}
+</style>
+
+<style>
+.avatar-uploader .el-upload {
+	border: 1px dashed var(--el-border-color);
+	border-radius: 6px;
+	cursor: pointer;
+	position: relative;
+	overflow: hidden;
+	transition: var(--el-transition-duration-fast);
+}
+
+.avatar-uploader .el-upload:hover {
+	border-color: var(--el-color-primary);
+}
+
+.el-icon.avatar-uploader-icon {
+	font-size: 28px;
+	color: #8c939d;
+	width: 178px;
+	height: 178px;
+	text-align: center;
+}
+</style>

+ 251 - 0
src/views/device/product/component/editEvent.vue

@@ -0,0 +1,251 @@
+<template>
+	<div class="system-edit-dic-container">
+		<el-dialog :title="(ruleForm.id !== 0 ? '修改' : '添加') + '事件定义'" v-model="isShowDialog" width="769px">
+			<el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="120px">
+				<el-form-item label="事件定义标识" prop="key">
+					<el-input v-model="ruleForm.key" placeholder="请输入事件定义标识" />
+				</el-form-item>
+				<el-form-item label="事件定义名称" prop="name">
+					<el-input v-model="ruleForm.name" placeholder="请输入事件定义名称" />
+				</el-form-item>
+
+        
+				<el-form-item label="事件级别" prop="level">
+					<el-radio-group v-model="ruleForm.level" model-value="0">
+						<el-radio label="0">普通</el-radio>
+
+						<el-radio label="1">警告</el-radio>
+						<el-radio label="2">紧急</el-radio>
+					</el-radio-group>
+				</el-form-item>
+
+				<el-form-item label="输出参数" prop="type">
+					<el-select v-model="valueType.type" placeholder="请选择输出参数" @change="seletChange">
+						<el-option-group v-for="group in typeData" :key="group.label" :label="group.label">
+							<el-option v-for="item in group.options" :key="item.type" :label="item.title" :value="item.type" />
+						</el-option-group>
+					</el-select>
+				</el-form-item>
+
+        <!--根据数据类型输出不同表单-->
+
+             <el-form-item label="精度" prop="maxLength1" v-if="type=='float' || type=='double'">
+                <el-input v-model="valueType.maxLength1" placeholder="请输入精度" />
+              </el-form-item>
+
+            	<el-form-item label="单位" prop="maxLength" v-if="type=='int' || type=='long' || type=='float'  || type=='double'">
+                <el-input v-model="valueType.maxLength" placeholder="请输入单位" />
+              </el-form-item>
+
+              <el-form-item label="最大长度" prop="maxLength" v-if="type=='string'">
+                <el-input v-model="valueType.maxLength" placeholder="请输入最大长度" />
+              </el-form-item>
+
+               <el-form-item label="时间格式" prop="maxLength" v-if="type=='date'">
+                <el-input v-model="valueType.maxLength" placeholder="请输入时间格式" />
+              </el-form-item>
+             
+
+        <!--根据数据类型输出不同表单-->
+
+
+
+
+
+
+
+
+				<el-form-item label="事件定义描述	" prop="desc">
+					<el-input v-model="ruleForm.desc" type="textarea" placeholder="请输入事件定义描述"></el-input>
+				</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>
+
+<script lang="ts">
+import { reactive, toRefs, defineComponent, ref, unref } from 'vue';
+import api from '/@/api/device';
+import uploadVue from '/@/components/upload/index.vue';
+import { ElMessage, UploadProps } from 'element-plus';
+
+interface RuleFormState {
+	id: number;
+	name: string;
+	dictType: string;
+	status: number;
+	desc: string;
+}
+interface DicState {
+	isShowDialog: boolean;
+	ruleForm: RuleFormState;
+	typeData: RuleFormState[];
+	rules: {};
+}
+
+export default defineComponent({
+	name: 'deviceEditPro',
+	components: { uploadVue },
+	setup(prop, { emit }) {
+		const formRef = ref<HTMLElement | null>(null);
+
+		const state = reactive<DicState>({
+			isShowDialog: false,
+			typeData: [], //
+      type: '',
+       valueType: {
+          type:'',
+          maxLength:'',
+
+        },
+
+			ruleForm: {
+				name: '',
+				key: '',
+				transportProtocol: '',
+				accessMode: '0',
+				status: 1,
+        valueType: {
+          type:'',
+          maxLength:'',
+
+        },
+				
+				desc: '',
+			},
+			rules: {
+				name: [{ required: true, message: '事件定义名称不能为空', trigger: 'blur' }],
+				key: [{ required: true, message: '事件定义标识不能为空', trigger: 'blur' }],
+				accessMode: [{ required: true, message: '请选择是否只读', trigger: 'blur' }],
+		
+			},
+		});
+
+		// 打开弹窗
+		const openDialog = (row: RuleFormState | null) => {
+			resetForm();
+
+			api.product.getDataType({ status: -1 }).then((res: any) => {
+				const datat = Object.values(res.dataType);
+				datat.forEach((item, index) => {
+					if (index == 0) {
+						datat[index]['label'] = '基础类型';
+						datat[index]['options'] = item;
+					} else {
+						datat[index]['label'] = '扩展类型';
+						datat[index]['options'] = item;
+					}
+				});
+				console.log(datat);
+				state.typeData = datat || [];
+			});
+
+			if (row) {
+				// api.dict.getType(row.dictId).then((res:any)=>{
+				//   state.ruleForm = res.data.dictType
+				// }
+				console.log(row);
+				state.ruleForm = row;
+			}
+			state.isShowDialog = true;
+		};
+		const resetForm = () => {
+			state.ruleForm = {
+				id: 0,
+				name: '',
+				dictType: '',
+				status: 1,
+				desc: '',
+			};
+		};
+
+    const seletChange=(val)=>{
+      state.type=val;
+      console.log(val);
+    };
+		// 关闭弹窗
+		const closeDialog = () => {
+			state.isShowDialog = false;
+		};
+		// 取消
+		const onCancel = () => {
+			closeDialog();
+		};
+		// 新增
+		const onSubmit = () => {
+			const formWrap = unref(formRef) as any;
+			if (!formWrap) return;
+			formWrap.validate((valid: boolean) => {
+				if (valid) {
+					if (state.ruleForm.id !== 0) {
+						//修改
+						api.product.edit(state.ruleForm).then(() => {
+							ElMessage.success('事件定义类型修改成功');
+							closeDialog(); // 关闭弹窗
+							emit('typeList');
+						});
+					} else {
+						//添加
+         
+            console.log(state.valueType);
+            state.ruleForm.valueType=state.valueType;
+           console.log(state.ruleForm);
+						api.model.eventadd(state.ruleForm).then(() => {
+							ElMessage.success('事件定义类型添加成功');
+							closeDialog(); // 关闭弹窗
+							emit('typeList');
+						});
+					}
+				}
+			});
+		};
+
+		return {
+			openDialog,
+      seletChange,
+			closeDialog,
+			onCancel,
+			onSubmit,
+			formRef,
+			...toRefs(state),
+		};
+	},
+});
+</script>
+
+<style scoped>
+.avatar-uploader .avatar {
+	width: 178px;
+	height: 178px;
+	display: block;
+}
+</style>
+
+<style>
+.avatar-uploader .el-upload {
+	border: 1px dashed var(--el-border-color);
+	border-radius: 6px;
+	cursor: pointer;
+	position: relative;
+	overflow: hidden;
+	transition: var(--el-transition-duration-fast);
+}
+
+.avatar-uploader .el-upload:hover {
+	border-color: var(--el-color-primary);
+}
+
+.el-icon.avatar-uploader-icon {
+	font-size: 28px;
+	color: #8c939d;
+	width: 178px;
+	height: 178px;
+	text-align: center;
+}
+</style>

+ 232 - 0
src/views/device/product/component/editFun.vue

@@ -0,0 +1,232 @@
+<template>
+	<div class="system-edit-dic-container">
+		<el-dialog :title="(ruleForm.id!==0?'修改':'添加')+'功能定义'" v-model="isShowDialog" width="769px">
+			<el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="120px">
+        <el-form-item label="功能定义标识" prop="key">
+          <el-input v-model="ruleForm.key" placeholder="请输入功能定义标识" />
+        </el-form-item>
+        <el-form-item label="功能定义名称" prop="name">
+          <el-input v-model="ruleForm.name" placeholder="请输入功能定义名称" />
+        </el-form-item>
+    
+    
+
+
+           
+         <el-form-item label="数据类型" prop="valueType">
+
+             <!--    <el-select v-model="ruleForm.valueType" placeholder="请选择数据类型">
+              <el-option
+                v-for="item in typeData"
+                :key="item.key"
+                :label="item.name"
+                :value="item.key"
+              />
+            </el-select> -->
+
+             <el-select v-model="ruleForm.valueType" placeholder="请选择数据类型">
+              <el-option-group
+                v-for="group in typeData"
+                :key="group"
+                :label="group"
+              >
+                <el-option
+                  v-for="item in group.options"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-option-group>
+            </el-select>
+            </el-form-item> 
+
+          
+
+      
+        <el-form-item label="是否只读" prop="accessMode">
+          <el-radio-group v-model="ruleForm.accessMode" model-value="0">
+            <el-radio label="0">读写</el-radio>
+
+            <el-radio label="1">只读</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="功能定义描述	" prop="desc">
+          <el-input v-model="ruleForm.desc" type="textarea" placeholder="请输入功能定义描述"></el-input>
+        </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>
+
+<script lang="ts">
+import { reactive, toRefs, defineComponent,ref, unref } from 'vue';
+import api from '/@/api/device';
+import uploadVue from '/@/components/upload/index.vue';
+import {ElMessage,UploadProps} from "element-plus";
+
+interface RuleFormState {
+  id:number;
+  name:string;
+  dictType:string;
+  status:number;
+  desc:string;
+}
+interface DicState {
+	isShowDialog: boolean;
+	ruleForm: RuleFormState;
+  typeData: RuleFormState[];
+  rules:{}
+}
+
+export default defineComponent({
+	name: 'deviceEditPro',
+  components: { uploadVue },
+	setup(prop,{emit}) {
+    const formRef = ref<HTMLElement | null>(null);
+    const baseURL:string|undefined|boolean = import.meta.env.VITE_API_URL
+
+		const state = reactive<DicState>({
+			isShowDialog: false,
+    	typeData: [], // 
+    	
+
+			ruleForm: {
+        id:0,
+        name:'',
+        key:'',
+        transportProtocol:'',
+        accessMode:'0',
+        status:1,
+        desc:''
+			},
+      rules: {
+        name: [
+          { required: true, message: "功能定义名称不能为空", trigger: "blur" }
+        ],
+         key: [
+          { required: true, message: "功能定义标识不能为空", trigger: "blur" }
+        ],
+        accessMode: [{ required: true, message: '功能定义分类不能为空', trigger: 'blur' }],
+        deptId: [{ required: true, message: '所属部门不能为空', trigger: 'blur' }],
+        deviceType: [{ required: true, message: '设备类型不能为空', trigger: 'blur' }],
+      }
+		});
+
+		// 打开弹窗
+		const openDialog = (row: RuleFormState|null) => {
+      resetForm();
+   
+        api.product.getDataType({ status: -1 }).then((res: any) => {
+        
+       
+            // const  datat=Object.values(res.dataType);
+            // datat.forEach((item, index) => {
+
+            // });
+          
+                state.typeData = res.dataType || [];
+           
+         
+        });
+       
+      if (row){
+        // api.dict.getType(row.dictId).then((res:any)=>{
+        //   state.ruleForm = res.data.dictType
+        // }
+        console.log(row);
+        state.ruleForm = row;
+      }
+			state.isShowDialog = true;
+		};
+    const resetForm = ()=>{
+      state.ruleForm = {
+        id:0, 
+        name:'',
+        dictType:'',
+        status:1,
+        desc:''
+      }
+    };
+		// 关闭弹窗
+		const closeDialog = () => {
+			state.isShowDialog = false;
+		};
+		// 取消
+		const onCancel = () => {
+			closeDialog();
+		};
+		// 新增
+		const onSubmit = () => {
+      const formWrap = unref(formRef) as any;
+      if (!formWrap) return;
+      formWrap.validate((valid: boolean) => {
+        if (valid) {
+          if(state.ruleForm.id!==0){
+            //修改
+            api.product.edit(state.ruleForm).then(()=>{
+              ElMessage.success('功能定义类型修改成功');
+              closeDialog(); // 关闭弹窗
+              emit('typeList')
+            })
+          }else{
+            //添加
+            console.log(state.ruleForm);
+            api.product.add(state.ruleForm).then(()=>{
+              ElMessage.success('功能定义类型添加成功');
+              closeDialog(); // 关闭弹窗
+              emit('typeList')
+            })
+          }
+        }
+      });
+		};
+
+
+		return {
+			openDialog,
+			closeDialog,
+			onCancel,
+			onSubmit,
+      formRef,
+			...toRefs(state),
+		};
+	},
+});
+</script>
+
+<style scoped>
+.avatar-uploader .avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+</style>
+
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed var(--el-border-color);
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  transition: var(--el-transition-duration-fast);
+}
+
+.avatar-uploader .el-upload:hover {
+  border-color: var(--el-color-primary);
+}
+
+.el-icon.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  text-align: center;
+}
+</style>

+ 23 - 35
src/views/device/product/component/editPro.vue

@@ -2,25 +2,18 @@
 	<div class="system-edit-dic-container">
 		<el-dialog :title="(ruleForm.id!==0?'修改':'添加')+'产品'" v-model="isShowDialog" width="769px">
 			<el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="90px">
+        <el-form-item label="产品标识" prop="key">
+          <el-input v-model="ruleForm.key" placeholder="请输入产品标识" />
+        </el-form-item>
         <el-form-item label="产品名称" prop="name">
           <el-input v-model="ruleForm.name" placeholder="请输入产品名称" />
         </el-form-item>
         <el-form-item label="产品图片" prop="imageUrl">
-        <el-upload
-            name="icon"
-            class="avatar-uploader"
-            :action="singleImg"
-            :show-file-list="false"
-            :on-success="handleAvatarSuccess"
-            :before-upload="beforeAvatarUpload"
-          >
-            <img v-if="imageUrl" :src="imageUrl" class="avatar" />
-            <el-icon v-else class="avatar-uploader-icon"><ele-Plus /></el-icon>
-          </el-upload>
-        </el-form-item>
-         <el-form-item label="产品标识" prop="key">
-          <el-input v-model="ruleForm.key" placeholder="请输入产品标识" />
+     
+                     <uploadVue @set-img="handleAvatarSuccess" ></uploadVue>
+
         </el-form-item>
+       
         <el-form-item label="产品分类" prop="categoryId">
               <el-cascader :options="cateData" :props="{ checkStrictly: true,emitPath: false, value: 'id', label: 'name' }" placeholder="请选择分类" clearable class="w100" v-model="ruleForm.categoryId">
                 <template #default="{ node, data }">
@@ -68,9 +61,10 @@
 
       
         <el-form-item label="设备类型" prop="deviceType">
-          <el-radio-group v-model="ruleForm.deviceType">
-            <el-radio label="网关" >网关</el-radio>
-            <el-radio label="设备" >设备</el-radio>
+          <el-radio-group v-model="ruleForm.deviceType" model-value="设备">
+            <el-radio label="设备">设备</el-radio>
+
+            <el-radio label="网关">网关</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="产品描述	" prop="desc">
@@ -90,13 +84,13 @@
 <script lang="ts">
 import { reactive, toRefs, defineComponent,ref, unref } from 'vue';
 import api from '/@/api/device';
+import uploadVue from '/@/components/upload/index.vue';
 import {ElMessage,UploadProps} from "element-plus";
 
 interface RuleFormState {
   id:number;
   name:string;
   dictType:string;
-  deviceType:string;
   status:number;
   desc:string;
 }
@@ -112,6 +106,7 @@ interface DicState {
 
 export default defineComponent({
 	name: 'deviceEditPro',
+  components: { uploadVue },
 	setup(prop,{emit}) {
     const formRef = ref<HTMLElement | null>(null);
     const baseURL:string|undefined|boolean = import.meta.env.VITE_API_URL
@@ -132,7 +127,7 @@ export default defineComponent({
         deptId:'',
         messageProtocol:'',
         transportProtocol:'',
-        deviceType:'网关',
+        deviceType:'设备',
         status:1,
         desc:''
 			},
@@ -151,25 +146,19 @@ export default defineComponent({
       }
 		});
 
+
+
+
     const handleAvatarSuccess: UploadProps['onSuccess'] = (
-      response,
-      uploadFile
-    ) => {
+      response    ) => {
 
-      state.imageUrl = response.data.name
-        state.ruleForm.imageUrl=response.data.name
-    }
+	console.log( response);
 
-    const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
-      if (rawFile.type !== 'image/jpeg') {
-        ElMessage.error('Avatar picture must be JPG format!')
-        return false
-      } else if (rawFile.size / 1024 / 1024 > 2) {
-        ElMessage.error('Avatar picture size can not exceed 2MB!')
-        return false
-      }
-      return true
+         state.imageUrl = response
+        state.ruleForm.imageUrl=response
     }
+
+
 		// 打开弹窗
 		const openDialog = (row: RuleFormState|null) => {
       resetForm();
@@ -241,7 +230,6 @@ export default defineComponent({
 		return {
 			openDialog,
       handleAvatarSuccess,
-      beforeAvatarUpload,
 			closeDialog,
 			onCancel,
 			onSubmit,

+ 248 - 0
src/views/device/product/component/editTab.vue

@@ -0,0 +1,248 @@
+<template>
+	<div class="system-edit-dic-container">
+		<el-dialog :title="(ruleForm.id !== 0 ? '修改' : '添加') + '标签定义'" v-model="isShowDialog" width="769px">
+			<el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="120px">
+				<el-form-item label="标签定义标识" prop="key">
+					<el-input v-model="ruleForm.key" placeholder="请输入标签定义标识" />
+				</el-form-item>
+				<el-form-item label="标签定义名称" prop="name">
+					<el-input v-model="ruleForm.name" placeholder="请输入标签定义名称" />
+				</el-form-item>
+
+				<el-form-item label="数据类型" prop="type">
+					<el-select v-model="valueType.type" placeholder="请选择数据类型" @change="seletChange">
+						<el-option-group v-for="group in typeData" :key="group.label" :label="group.label">
+							<el-option v-for="item in group.options" :key="item.type" :label="item.title" :value="item.type" />
+						</el-option-group>
+					</el-select>
+				</el-form-item>
+
+        <!--根据数据类型输出不同表单-->
+
+             <el-form-item label="精度" prop="maxLength1" v-if="type=='float' || type=='double'">
+                <el-input v-model="valueType.maxLength1" placeholder="请输入精度" />
+              </el-form-item>
+
+            	<el-form-item label="单位" prop="maxLength" v-if="type=='int' || type=='long' || type=='float'  || type=='double'">
+                <el-input v-model="valueType.maxLength" placeholder="请输入单位" />
+              </el-form-item>
+
+              <el-form-item label="最大长度" prop="maxLength" v-if="type=='string'">
+                <el-input v-model="valueType.maxLength" placeholder="请输入最大长度" />
+              </el-form-item>
+
+               <el-form-item label="时间格式" prop="maxLength" v-if="type=='date'">
+                <el-input v-model="valueType.maxLength" placeholder="请输入时间格式" />
+              </el-form-item>
+             
+
+        <!--根据数据类型输出不同表单-->
+
+
+
+
+
+
+
+
+				<el-form-item label="是否只读" prop="accessMode">
+					<el-radio-group v-model="ruleForm.accessMode" model-value="0">
+						<el-radio label="0">读写</el-radio>
+
+						<el-radio label="1">只读</el-radio>
+					</el-radio-group>
+				</el-form-item>
+				<el-form-item label="标签定义描述	" prop="desc">
+					<el-input v-model="ruleForm.desc" type="textarea" placeholder="请输入标签定义描述"></el-input>
+				</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>
+
+<script lang="ts">
+import { reactive, toRefs, defineComponent, ref, unref } from 'vue';
+import api from '/@/api/device';
+import uploadVue from '/@/components/upload/index.vue';
+import { ElMessage, UploadProps } from 'element-plus';
+
+interface RuleFormState {
+	id: number;
+	name: string;
+	dictType: string;
+	status: number;
+	desc: string;
+}
+interface DicState {
+	isShowDialog: boolean;
+	ruleForm: RuleFormState;
+	typeData: RuleFormState[];
+	rules: {};
+}
+
+export default defineComponent({
+	name: 'deviceEditPro',
+	components: { uploadVue },
+	setup(prop, { emit }) {
+		const formRef = ref<HTMLElement | null>(null);
+
+		const state = reactive<DicState>({
+			isShowDialog: false,
+			typeData: [], //
+      type: '',
+       valueType: {
+          type:'',
+          maxLength:'',
+
+        },
+
+			ruleForm: {
+				name: '',
+				key: '',
+				transportProtocol: '',
+				accessMode: '0',
+				status: 1,
+        valueType: {
+          type:'',
+          maxLength:'',
+
+        },
+				
+				desc: '',
+			},
+			rules: {
+				name: [{ required: true, message: '标签定义名称不能为空', trigger: 'blur' }],
+				key: [{ required: true, message: '标签定义标识不能为空', trigger: 'blur' }],
+				accessMode: [{ required: true, message: '请选择是否只读', trigger: 'blur' }],
+		
+			},
+		});
+
+		// 打开弹窗
+		const openDialog = (row: RuleFormState | null) => {
+			resetForm();
+
+			api.product.getDataType({ status: -1 }).then((res: any) => {
+				const datat = Object.values(res.dataType);
+				datat.forEach((item, index) => {
+					if (index == 0) {
+						datat[index]['label'] = '基础类型';
+						datat[index]['options'] = item;
+					} else {
+						datat[index]['label'] = '扩展类型';
+						datat[index]['options'] = item;
+					}
+				});
+				console.log(datat);
+				state.typeData = datat || [];
+			});
+
+			if (row) {
+				// api.dict.getType(row.dictId).then((res:any)=>{
+				//   state.ruleForm = res.data.dictType
+				// }
+				console.log(row);
+				state.ruleForm = row;
+			}
+			state.isShowDialog = true;
+		};
+		const resetForm = () => {
+			state.ruleForm = {
+				id: 0,
+				name: '',
+				dictType: '',
+				status: 1,
+				desc: '',
+			};
+		};
+
+    const seletChange=(val)=>{
+      state.type=val;
+      console.log(val);
+    };
+		// 关闭弹窗
+		const closeDialog = () => {
+			state.isShowDialog = false;
+		};
+		// 取消
+		const onCancel = () => {
+			closeDialog();
+		};
+		// 新增
+		const onSubmit = () => {
+			const formWrap = unref(formRef) as any;
+			if (!formWrap) return;
+			formWrap.validate((valid: boolean) => {
+				if (valid) {
+					if (state.ruleForm.id !== 0) {
+						//修改
+						api.product.edit(state.ruleForm).then(() => {
+							ElMessage.success('标签定义类型修改成功');
+							closeDialog(); // 关闭弹窗
+							emit('typeList');
+						});
+					} else {
+						//添加
+         
+            console.log(state.valueType);
+            state.ruleForm.valueType=state.valueType;
+           console.log(state.ruleForm);
+						api.model.tagadd(state.ruleForm).then(() => {
+							ElMessage.success('标签定义类型添加成功');
+							closeDialog(); // 关闭弹窗
+							emit('typeList');
+						});
+					}
+				}
+			});
+		};
+
+		return {
+			openDialog,
+      seletChange,
+			closeDialog,
+			onCancel,
+			onSubmit,
+			formRef,
+			...toRefs(state),
+		};
+	},
+});
+</script>
+
+<style scoped>
+.avatar-uploader .avatar {
+	width: 178px;
+	height: 178px;
+	display: block;
+}
+</style>
+
+<style>
+.avatar-uploader .el-upload {
+	border: 1px dashed var(--el-border-color);
+	border-radius: 6px;
+	cursor: pointer;
+	position: relative;
+	overflow: hidden;
+	transition: var(--el-transition-duration-fast);
+}
+
+.avatar-uploader .el-upload:hover {
+	border-color: var(--el-color-primary);
+}
+
+.el-icon.avatar-uploader-icon {
+	font-size: 28px;
+	color: #8c939d;
+	width: 178px;
+	height: 178px;
+	text-align: center;
+}
+</style>

+ 515 - 0
src/views/device/product/detail.vue

@@ -0,0 +1,515 @@
+<template>
+	<div class="system-dic-container">
+		<div class="content">
+			<div class="cont_box">
+				<div class="title">产品:{{ detail.name }}</div>
+				<div class="pro-status"><span class="on"></span>已发布</div>
+				<div class="pro-option">停用</div>
+			</div>
+		</div>
+
+		<div class="content-box">
+			<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+				<el-tab-pane label="产品信息" name="1">
+					<div class="pro-box">
+						<div class="protitle">产品信息</div>
+						<el-button type="" :icon="Edit" class="buttonedit" @click="onOpenEditDic(detail)">编辑</el-button>
+					</div>
+
+					<div class="ant-descriptions-view">
+						<table>
+							<tbody>
+								<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.name }}</td>
+									<th class="ant-descriptions-item-label ant-descriptions-item-colon">所属品类</th>
+									<td class="ant-descriptions-item-content" colspan="1">{{ detail.categoryName }}</td>
+									<th class="ant-descriptions-item-label ant-descriptions-item-colon">所属部门</th>
+									<td class="ant-descriptions-item-content" colspan="1">{{ detail.deptName }}</td>
+								</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.messageProtocol }}</td>
+									<th class="ant-descriptions-item-label ant-descriptions-item-colon">链接协议</th>
+									<td class="ant-descriptions-item-content" colspan="1">{{ detail.transportProtocol }}</td>
+									<th class="ant-descriptions-item-label ant-descriptions-item-colon">设备类型</th>
+									<td class="ant-descriptions-item-content" colspan="1">{{ detail.deviceType }}</td>
+								</tr>
+								<tr class="ant-descriptions-row">
+									<th class="ant-descriptions-item-label ant-descriptions-item-colon">描述</th>
+									<td class="ant-descriptions-item-content" colspan="5">{{ detail.desc }}</td>
+								</tr>
+							</tbody>
+						</table>
+					</div>
+				</el-tab-pane>
+				<el-tab-pane label="物模型" name="2">
+					<div class="wu-box">
+						<el-tabs type="border-card" v-model="activetab" @tab-click="wuhandleClick">
+							<el-tab-pane label="属性定义" name="attr">
+								<div class="wu-title">
+									<div class="title">属性定义</div>
+									<div><el-button type="primary" @click="onOpenEditAttr()">添加</el-button></div>
+								</div>
+
+								<el-table style="width: 100%" :data="tableData.data" v-if="activetab == 'attr'">
+									<el-table-column label="属性标识" align="center" prop="key" />
+									<el-table-column label="属性名称" prop="name" :show-overflow-tooltip="true" />
+									<el-table-column prop="valueType" label="数据类型" width="120" align="center">
+										<template #default="scope">
+											<span>{{ scope.row.valueType.type }}</span>
+										</template>
+									</el-table-column>
+									<el-table-column prop="accessMode" label="是否只读" width="120" align="center">
+										<template #default="scope">
+											<el-tag type="info" size="small" v-if="scope.row.accessMode">只读</el-tag>
+											<el-tag type="success" size="small" v-else>读写</el-tag>
+										</template>
+									</el-table-column>
+									<el-table-column label="说明" prop="desc" :show-overflow-tooltip="true" />
+									<el-table-column label="操作" width="300" align="center">
+										<template #default="scope">
+											<el-button size="small" text type="warning">修改</el-button>
+											<el-button size="small" text type="danger" @click="onRowDel(scope.row.key,'attr')">删除</el-button>
+										</template>
+									</el-table-column>
+								</el-table>
+							</el-tab-pane>
+							<el-tab-pane label="功能定义" name="fun">
+								<div class="wu-title">
+									<div class="title">功能定义</div>
+									<div><el-button type="primary" @click="onOpenEditFun()">添加</el-button></div>
+								</div>
+
+								<el-table style="width: 100%" :data="tableData.data" v-if="activetab == 'fun'">
+									<el-table-column label="功能标识" align="center" prop="key" />
+									<el-table-column label="名称" prop="name" :show-overflow-tooltip="true" />
+
+									<el-table-column label="描述" prop="desc" :show-overflow-tooltip="true" />
+									<el-table-column label="操作" width="300" align="center">
+										<template #default="scope">
+											<el-button size="small" text type="warning">修改</el-button>
+											<el-button size="small" text type="danger" @click="onRowDel(scope.row.key,'fun')">删除</el-button>
+										</template>
+									</el-table-column>
+								</el-table>
+							</el-tab-pane>
+							<el-tab-pane label="事件定义" name="event">
+								<div class="wu-title">
+									<div class="title">事件定义</div>
+									<div><el-button type="primary" @click="onOpenEditEvent()">添加</el-button></div>
+								</div>
+
+								<el-table style="width: 100%" :data="tableData.data" v-if="activetab == 'event'">
+									<el-table-column label="事件标识" align="center" prop="key" />
+									<el-table-column label="名称" prop="name" :show-overflow-tooltip="true" />
+									<el-table-column prop="level" label="事件级别" width="120" align="center">
+										<template #default="scope">
+											<el-tag type="primary" size="small" v-if="scope.row.level == 0">普通</el-tag>
+											<el-tag type="warning" size="small" v-if="scope.row.level == 1">警告</el-tag>
+											<el-tag type="danger" size="small" v-if="scope.row.level == 2">紧急</el-tag>
+										</template>
+									</el-table-column>
+									<el-table-column label="描述" prop="desc" :show-overflow-tooltip="true" />
+
+									<el-table-column label="操作" width="300" align="center">
+										<template #default="scope">
+											<el-button size="small" text type="warning">修改</el-button>
+											<el-button size="small" text type="danger" @click="onRowDel(scope.row.key,'event')">删除</el-button>
+										</template>
+									</el-table-column>
+								</el-table></el-tab-pane
+							>
+							<el-tab-pane label="标签定义" name="tab"
+								><div class="wu-title">
+									<div class="title">标签定义</div>
+									<div><el-button type="primary" @click="onOpenEditTab()">添加</el-button></div>
+								</div>
+
+								<el-table style="width: 100%" :data="tableData.data" v-if="activetab == 'tab'">
+									<el-table-column label="属性标识" align="center" prop="key" />
+									<el-table-column label="属性名称" prop="name" :show-overflow-tooltip="true" />
+									<el-table-column prop="valueType" label="数据类型" width="120" align="center">
+										<template #default="scope">
+											<span>{{ scope.row.valueType.type }}</span>
+										</template>
+									</el-table-column>
+									<el-table-column prop="accessMode" label="是否只读" width="120" align="center">
+										<template #default="scope">
+											<el-tag type="info" size="small" v-if="scope.row.accessMode">只读</el-tag>
+											<el-tag type="success" size="small" v-else>读写</el-tag>
+										</template>
+									</el-table-column>
+									<el-table-column label="描述" prop="desc" :show-overflow-tooltip="true" />
+									<el-table-column label="操作" width="300" align="center">
+										<template #default="scope">
+											<el-button size="small" text type="warning">修改</el-button>
+											<el-button size="small" text type="danger" @click="onRowDel(scope.row.key,'tab')">删除</el-button>
+										</template>
+									</el-table-column>
+								</el-table>
+							</el-tab-pane>
+						</el-tabs>
+						<pagination
+							v-show="tableData.total > 0"
+							:total="tableData.total"
+							v-model:page="tableData.param.pageNum"
+							v-model:limit="tableData.param.pageSize"
+							@pagination="typeList"
+						/>
+					</div>
+				</el-tab-pane>
+			</el-tabs>
+		</div>
+		<EditDic ref="editDicRef" @typeList="typeList" />
+		<EditAttr ref="editAttrRef" @typeList="getproperty" />
+		<EditFun ref="editFunRef" @typeList="getfunction" />
+		<EditEvent ref="editEventRef" @typeList="getevent" />
+		<EditTab ref="editTabRef" @typeList="gettab" />
+	</div>
+</template>
+<script lang="ts">
+import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue';
+import { Delete, Edit, Search, Share, Upload } from '@element-plus/icons-vue';
+import { ElMessageBox, ElMessage, FormInstance } from 'element-plus';
+
+import EditDic from './component/editPro.vue';
+import EditAttr from './component/editAttr.vue';
+import EditFun from './component/editFun.vue';
+import EditEvent from './component/editEvent.vue';
+import EditTab from './component/editTab.vue';
+
+import { useRoute } from 'vue-router';
+
+import api from '/@/api/device';
+
+interface TableDataState {
+	ids: number[];
+	tableData: {
+		data: [];
+		total: number;
+		loading: boolean;
+		param: {
+			pageNum: number;
+			pageSize: number;
+			name: string;
+			deviceType: string;
+			status: string;
+			dateRange: string[];
+		};
+	};
+}
+export default defineComponent({
+	name: 'deviceEditPro',
+	components: { EditDic, EditAttr, EditFun, EditEvent, EditTab },
+
+	setup(prop, context) {
+		const route = useRoute();
+		const editDicRef = ref();
+		const editAttrRef = ref();
+		const editFunRef = ref();
+		const editEventRef = ref();
+		const editTabRef = ref();
+		const state = reactive<TableDataState>({
+			isShowDialog: false,
+			activeName: '2', // 分类数据
+			activetab: 'attr', // 分类数据
+			detail: [],
+			tableData: {
+				data: [],
+				total: 0,
+				loading: false,
+				param: {
+					pageNum: 1,
+					productId: route.params && route.params.id,
+					pageSize: 10,
+					status: '',
+					dateRange: [],
+				},
+			},
+		});
+
+		onMounted(() => {
+			const ids = route.params && route.params.id;
+			api.product.detail(ids).then((res: any) => {
+				state.detail = res.data;
+			});
+
+			//第一次加载
+			api.model.property(state.tableData.param).then((res: any) => {
+				state.tableData.data = res.Data;
+				state.tableData.total = res.Total;
+			});
+		});
+
+		//打开添加属性弹窗
+		const onOpenEditAttr = () => {
+			editAttrRef.value.openDialog({ product_id: route.params.id, id: 0 });
+		};
+
+		//打开添加功能弹窗
+		const onOpenEditFun = () => {
+			editFunRef.value.openDialog({ product_id: route.params.id, id: 0 });
+		};
+		//打开添加事件弹窗
+		const onOpenEditEvent = () => {
+			editEventRef.value.openDialog({ product_id: route.params.id, id: 0 });
+		};
+
+		//打开添加事件弹窗
+		const onOpenEditTab = () => {
+			editTabRef.value.openDialog({ product_id: route.params.id, id: 0 });
+		};
+
+		// 打开修改产品弹窗
+		const onOpenEditDic = (row: TableDataRow) => {
+			editDicRef.value.openDialog(row);
+		};
+
+
+		// 删除产品
+		const onRowDel = (key,type) => {
+			let msg = `此操作将永久删除该数据吗?,是否继续?`;
+			
+			if (key.length === 0) {
+				ElMessage.error('请选择要删除的数据。');
+				return;
+			}
+			ElMessageBox.confirm(msg, '提示', {
+				confirmButtonText: '确认',
+				cancelButtonText: '取消',
+				type: 'warning',
+			})
+				.then(() => {
+					if(type=='attr'){
+						api.model.propertydel(route.params.id,key).then(() => {
+							ElMessage.success('删除成功');
+							getproperty();
+						});
+					}
+					if(type=='fun'){
+						api.model.functiondel(route.params.id,key).then(() => {
+							ElMessage.success('删除成功');
+							getfunction();
+						});
+					}
+					if(type=='event'){
+						api.model.eventdel(route.params.id,key).then(() => {
+							ElMessage.success('删除成功');
+							getevent();
+						});
+					}
+					if(type=='tab'){
+						api.model.eventdel(route.params.id,key).then(() => {
+							ElMessage.success('删除成功');
+							tagdel();
+						});
+					}
+				})
+				.catch(() => {});
+		};
+
+
+		const getproperty=()=>{
+			api.model.property(state.tableData.param).then((res: any) => {
+				state.tableData.data = res.Data;
+				state.tableData.total = res.Total;
+			});
+		};
+
+		const getfunction=()=>{
+			api.model.function(state.tableData.param).then((res: any) => {
+				state.tableData.data = res.Data;
+				state.tableData.total = res.Total;
+			});
+		};
+		const getevent=()=>{
+			api.model.event(state.tableData.param).then((res: any) => {
+				state.tableData.data = res.Data;
+				state.tableData.total = res.Total;
+			});
+		};
+
+		const gettab=()=>{
+			api.model.tag(state.tableData.param).then((res: any) => {
+				state.tableData.data = res.Data;
+				state.tableData.total = res.Total;
+			});
+		};
+
+		const wuhandleClick = (tab: TabsPaneContext) => {
+			state.activetab = tab.props.name;
+			switch (tab.props.name) {
+				case 'attr':
+					getproperty();
+					break;
+				case 'fun':
+					getfunction();
+					break;
+				case 'event':
+					getevent();
+					break;
+				case 'tab':
+					gettab();
+					break;
+			}
+		};
+
+		const handleClick = (tab: TabsPaneContext, event: Event) => {
+			console.log(tab, event);
+		};
+
+		return {
+			Edit,
+			editDicRef,
+			editAttrRef,
+			editFunRef,
+			editEventRef,
+			editTabRef,
+			onRowDel,
+			getproperty,
+			getfunction,
+			getevent,
+			gettab,
+			wuhandleClick,
+			onOpenEditTab,
+			onOpenEditEvent,
+			onOpenEditAttr,
+			onOpenEditFun,
+			onOpenEditDic,
+			handleClick,
+			...toRefs(state),
+		};
+	},
+});
+</script>
+  <style>
+.content {
+	background: #fff;
+	width: 100%;
+	padding: 20px;
+}
+.content-box {
+	background: #fff;
+	width: 100%;
+	padding: 20px;
+	margin-top: 20px;
+}
+.cont_box {
+	display: flex;
+}
+.cont_box .title {
+	font-size: 24px;
+}
+.cont_box .pro-status {
+	line-height: 40px;
+	margin-left: 30px;
+}
+.cont_box .pro-status .on {
+	background: #52c41a;
+}
+.cont_box .pro-status .off {
+	background: #c41a1a;
+}
+.cont_box .pro-status span {
+	position: relative;
+	top: -1px;
+	display: inline-block;
+	width: 6px;
+	height: 6px;
+	vertical-align: middle;
+	border-radius: 50%;
+	margin-right: 5px;
+}
+.cont_box .pro-option {
+	line-height: 40px;
+	margin-left: 10px;
+	color: #1890ff;
+}
+.content-box .pro-box {
+	display: flex;
+	padding: 10px;
+}
+.content-box .pro-box .protitle {
+	font-size: 18px;
+	font-weight: bold;
+	line-height: 35px;
+}
+.content-box .pro-box .buttonedit {
+	border: 0px;
+	color: #1890ff;
+}
+table {
+	border-collapse: collapse;
+	text-indent: initial;
+	border-spacing: 2px;
+}
+tbody {
+	box-sizing: border-box;
+	display: table-row-group;
+	vertical-align: middle;
+	border-color: inherit;
+}
+
+tr {
+	display: table-row;
+	vertical-align: inherit;
+	border-color: inherit;
+}
+.ant-descriptions-view {
+	width: 100%;
+	overflow: hidden;
+	border-radius: 4px;
+}
+.ant-descriptions-view {
+	border: 1px solid #e8e8e8;
+}
+.ant-descriptions-view table {
+	width: 100%;
+	table-layout: fixed;
+}
+.ant-descriptions-view > table {
+	table-layout: auto;
+}
+.ant-descriptions-row {
+	border-bottom: 1px solid #e8e8e8;
+}
+.ant-descriptions-item-label {
+	color: rgba(0, 0, 0, 0.85);
+	font-weight: 400;
+	font-size: 14px;
+	line-height: 1.5;
+}
+.ant-descriptions-item-label {
+	padding: 16px 24px;
+	border-right: 1px solid #e8e8e8;
+}
+.ant-descriptions-item-label {
+	background-color: #fafafa;
+}
+.ant-descriptions-item-content {
+	padding: 16px 24px;
+	border-right: 1px solid #e8e8e8;
+	display: table-cell;
+	color: rgba(0, 0, 0, 0.65);
+	font-size: 14px;
+	line-height: 1.5;
+}
+.wu-box {
+	border: #e8e8e8 solid 1px;
+	padding: 20px;
+	width: 100%;
+}
+.wu-box .wu-title {
+	display: flex;
+	flex-direction: row;
+	justify-content: space-between;
+	padding: 20px;
+	border-bottom: #e8e8e8 1px solid;
+}
+.wu-box .wu-title .title {
+	font-size: 18px;
+}
+</style>
+
+

+ 4 - 1
src/views/device/product/index.vue

@@ -64,8 +64,11 @@
           </template>
         </el-table-column>
         <!-- <el-table-column prop="createdAt" label="创建时间" align="center" width="180"></el-table-column> -->
-        <el-table-column label="操作" width="100" align="center">
+        <el-table-column label="操作" width="300" align="center">
           <template #default="scope">
+		     <router-link :to="'/device/product/detail/' + scope.row.id" class="link-type" style="padding-right: 10px;color: #409eff;">
+              <span>详情</span>
+            </router-link>
             <el-button size="small" text type="warning" @click="onOpenEditDic(scope.row)">修改</el-button>
             <el-button size="small" text type="danger" @click="onRowDel(scope.row)">删除</el-button>
           </template>

+ 68 - 4
src/views/system/role/component/permission.vue

@@ -1,20 +1,84 @@
 <template>
-  <el-dialog title="角色权限设置" v-model="isShowDialog" width="1000px">
-    角色权限设置
+  <el-dialog :title="title" custom-class="full-dialog" v-model="isShowDialog" width="1100px" fullscreen>
+    <div class="mb-4 tr">
+      <el-dropdown>
+        <el-button plain class="mr-3">
+          操作<el-icon>
+            <ele-ArrowDown />
+          </el-icon>
+        </el-button>
+        <template #dropdown>
+          <el-dropdown-menu>
+            <el-dropdown-item>全部勾选</el-dropdown-item>
+            <el-dropdown-item>取消全选</el-dropdown-item>
+            <el-dropdown-item>展开所有</el-dropdown-item>
+            <el-dropdown-item>折叠所有</el-dropdown-item>
+          </el-dropdown-menu>
+        </template>
+      </el-dropdown>
+      <el-button :disabled="step <= 0" @click="step--">上一步</el-button>
+      <el-button :disabled="step >= 3" @click="next">下一步</el-button>
+      <el-button type="primary" :loading="btnLoading" :disabled="step < 3">确定</el-button>
+      <el-button @click="cancel">取消</el-button>
+    </div>
+    <el-steps :active="step" simple>
+      <el-step name title="菜单权限" />
+      <el-step title="按钮权限" />
+      <el-step title="列表权限" />
+      <el-step title="接口权限" />
+    </el-steps>
+    <div class="scroll-part mt-3">
+      <el-tree ref="treeRef" :data="menuData" show-checkbox default-expand-all node-key="id" highlight-current :props="defaultProps" check-on-click-node :expand-on-click-node="false" />
+    </div>
   </el-dialog>
 </template>
 
 <script lang="ts" setup>
 import { ref } from 'vue';
+import api from '/@/api/system';
 const isShowDialog = ref(false);
+const btnLoading = ref(false);
+const step = ref(0);
+const treeRef = ref();
+const title = ref('角色权限设置');
+const menuData = ref([]);
+const menuIds = ref([]);
 
-const openDialog = (row: any) => {
-	console.log(row);
+const typeList = ['menu', 'button', 'column', 'api'];
+const defaultProps = {
+	children: 'children',
+	label: 'name',
+};
+
+const openDialog = async (row: any) => {
+	title.value = '角色权限设置 - ' + row.name;
 	isShowDialog.value = true;
+	let res = await api.role.auth.getList(typeList[step.value]);
+	console.log(res);
+	menuData.value = res;
+};
+const cancel = () => {
+	isShowDialog.value = false;
 };
+const next = async () => {
+	if (step.value === 0) {
+		const val = treeRef.value.getCheckedKeys(true);
+		console.log(val);
+		menuIds.value = val;
+		let res = await api.role.auth.getList(typeList[step.value + 1], val);
+		console.log(res);
+	}
+};
+
+// openDialog({ name: '超级管理员' });
 
 defineExpose({ openDialog });
 </script>
 
 <style scoped lang="scss">
+.scroll-part {
+	max-height: calc(100vh - 200px);
+	overflow-x: hidden;
+	overflow-y: auto;
+}
 </style>