浏览代码

fix: 1. 设备数中树形结构,根据传来的id进行判断,如果有,那么当前节点和他的所有子节点都不能选择,因为自己不能挂到自己和自己的子节点上,2. 优化设备树的显示

yanglzh 2 年之前
父节点
当前提交
4b17f1c707
共有 2 个文件被更改,包括 139 次插入119 次删除
  1. 47 35
      src/views/iot/device-tree/tree/component/edit.vue
  2. 92 84
      src/views/iot/device-tree/tree/index.vue

+ 47 - 35
src/views/iot/device-tree/tree/component/edit.vue

@@ -5,17 +5,8 @@
 				<el-row :gutter="35">
 					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
 						<el-form-item label="设备树" prop="parentId">
-              <el-tree-select
-                v-model="ruleForm.parentId"
-                :data="treeData"
-                check-strictly
-                style="width: 100%;"
-                :props="{
-                  label: 'name'
-                }"
-                node-key="infoId"
-                :render-after-expand="true"
-              />
+							<el-cascader :options="treeData" :props="{ checkStrictly: true, emitPath: false, value: 'infoId', label: 'name' }" placeholder="请选择分类" clearable class="w100" v-model="ruleForm.parentId">
+							</el-cascader>
 						</el-form-item>
 					</el-col>
 					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
@@ -49,11 +40,11 @@
 						</el-form-item>
 					</el-col>
 					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-            <el-form-item label="类型" prop="template">
-              <el-select v-model="ruleForm.template" filterable clearable placeholder="请选择类型" style="width: 100%;">
-                <el-option v-for="dict in tree_types" :key="dict.value" :label="dict.label" :value="dict.value"> </el-option>
-              </el-select>
-            </el-form-item>
+						<el-form-item label="类型" prop="template">
+							<el-select v-model="ruleForm.template" filterable clearable placeholder="请选择类型" style="width: 100%;">
+								<el-option v-for="dict in tree_types" :key="dict.value" :label="dict.label" :value="dict.value"> </el-option>
+							</el-select>
+						</el-form-item>
 					</el-col>
 					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
 						<el-form-item label="设备标识" prop="deviceKey">
@@ -61,11 +52,11 @@
 						</el-form-item>
 					</el-col>
 					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-            <el-form-item label="分类" prop="category">
-              <el-select v-model="ruleForm.category" filterable clearable placeholder="请选择分类" style="width: 100%;">
-                <el-option v-for="dict in tree_category" :key="dict.value" :label="dict.label" :value="dict.value"> </el-option>
-              </el-select>
-            </el-form-item>
+						<el-form-item label="分类" prop="category">
+							<el-select v-model="ruleForm.category" filterable clearable placeholder="请选择分类" style="width: 100%;">
+								<el-option v-for="dict in tree_category" :key="dict.value" :label="dict.label" :value="dict.value"> </el-option>
+							</el-select>
+						</el-form-item>
 					</el-col>
 					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
 						<el-form-item label="设备所属区域" prop="area">
@@ -108,12 +99,30 @@
 import { reactive, toRefs, defineComponent, ref, unref, getCurrentInstance } from 'vue';
 import api from '/@/api/device';
 import apiSystem from '/@/api/system';
-import { phoneValidate } from '/@/utils/validator';
 import { ElMessage } from 'element-plus';
 
+// 树形结构,根据传来的id进行判断,如果有,那么当前节点和他的所有子节点都不能选择,因为自己不能挂到自己和自己的子节点上
+function setDisabledById(objArray: any, id: number, parentDisabled = false) {
+	for (let i = 0; i < objArray.length; i++) {
+		const obj = objArray[i];
+		let isAllDisAbled = false || parentDisabled
+
+		if (isAllDisAbled || obj.infoId === id) {
+			obj.disabled = true;
+			isAllDisAbled = true;
+		} else {
+			isAllDisAbled = false;
+		}
+
+		if (obj.children && Array.isArray(obj.children)) {
+			setDisabledById(obj.children, id, isAllDisAbled);
+		}
+	}
+}
+
 interface RuleFormState {
 	id?: number;
-	parentId: string|number;
+	parentId: string | number;
 	name: string;
 	address: string;
 	lat: string;
@@ -124,7 +133,6 @@ interface RuleFormState {
 	area: string;
 	company: string;
 	types: string;
-	parentId: string;
 	startDate: string;
 	endDate: string;
 }
@@ -141,7 +149,6 @@ const baseForm: RuleFormState = {
 	area: '',
 	company: '',
 	types: '',
-	parentId: '',
 	startDate: '',
 	endDate: '',
 };
@@ -149,7 +156,7 @@ const baseForm: RuleFormState = {
 export default defineComponent({
 	name: 'deviceEditCate',
 	setup(prop, { emit }) {
-    const { proxy } = getCurrentInstance() as any;
+		const { proxy } = getCurrentInstance() as any;
 		const formRef = ref<HTMLElement | null>(null);
 		const state = reactive({
 			isShowDialog: false,
@@ -160,13 +167,13 @@ export default defineComponent({
 				name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
 				address: [{ required: true, message: '地址不能为空', trigger: 'blur' }],
 			},
-      orgData: [],
-      treeData: []
+			orgData: [],
+			treeData: [] as any[]
 		});
 
-    // const { tree_types_2 } = proxy.useDict('tree_types_2');
+		// const { tree_types_2 } = proxy.useDict('tree_types_2');
 
-    const { tree_types, tree_category } = proxy.useDict('tree_types', 'tree_category');
+		const { tree_types, tree_category } = proxy.useDict('tree_types', 'tree_category');
 
 		// 打开弹窗
 		const openDialog = (type: string, row?: any) => {
@@ -181,9 +188,14 @@ export default defineComponent({
 			apiSystem.org.getList({ status: 1 }).then((res: any) => {
 				state.orgData = res || [];
 			});
-      api.tree.getList({}).then((res: any) => {
-        state.treeData = res.list;
-      })
+			api.tree.getList({}).then((res: any) => {
+				setDisabledById(res.list, row.infoId)
+				state.treeData = [{
+					name: '根节点',
+					infoId: 0,
+					children: res.list
+				}]
+			})
 			state.isShowDialog = true;
 		};
 		// 关闭弹窗
@@ -236,8 +248,8 @@ export default defineComponent({
 			onSubmit,
 			formRef,
 			// tree_types_2,
-      tree_types,
-      tree_category,
+			tree_types,
+			tree_category,
 			...toRefs(state),
 		};
 	},

+ 92 - 84
src/views/iot/device-tree/tree/index.vue

@@ -1,29 +1,21 @@
 <template>
   <div class="system-dic-container">
-		<el-row :gutter="10">
-			<el-col :span="5">
-				<el-card shadow="hover">
-					<el-scrollbar v-loading="treeLoading">
-						<el-input :prefix-icon="search" v-model="searchVal" placeholder="请输入设备树名称" clearable size="default" style="width: 100%;" />
+    <el-row :gutter="10">
+      <el-col :span="5">
+        <el-card shadow="hover">
+          <el-scrollbar v-loading="treeLoading">
+            <el-input :prefix-icon="search" v-model="searchVal" placeholder="请输入设备树名称" clearable size="default" style="width: 100%;" />
 
             <el-button v-if="!treeLoading && !treeData.length" type="primary" class="mt-2" @click="operateCmd('add', {})" style="width: 100%">新建节点</el-button>
-						<el-tree
-              ref="zlTreeSearchRef"
-              v-if="!treeLoading"
-              :data="treeData"
-              :props="{
-                children: 'children',
-                label: 'name'
-              }"
-              :filter-node-method="filterNode"
-              :default-expand-all="true"
-              :node-key="'id'"
-              highlight-current
-              @node-click="nodeClick">
+            <el-tree ref="zlTreeSearchRef" v-if="!treeLoading" :data="treeData" :props="{
+              children: 'children',
+              label: 'name'
+            }" :filter-node-method="filterNode" :default-expand-all="true" :node-key="'id'" highlight-current @node-click="nodeClick">
               <template #default="{ node, data }">
                 <div class="custom-tree-node">
                   <span class="tree-label">
-                    <i class="iconfont icon-wenjianjia icon-wjj mr8" />{{ node.label }}
+                    <!-- <i class="iconfont icon-wenjianjia icon-wjj mr8" /> -->
+                    {{ node.label }}
                   </span>
                   <span class="tree-options" @click.stop>
                     <slot name="operate" :data="data">
@@ -60,7 +52,7 @@
         </el-card>
       </el-col>
       <el-col :span="19">
-				<el-card shadow="hover">
+        <el-card shadow="hover">
           <el-tabs v-model="tabName">
             <el-tab-pane label="设备树信息" name="1">
               <table>
@@ -80,7 +72,7 @@
                     <td class="ant-descriptions-item-content" colspan="1">{{ treeDetail.contact }}</td>
                     <th class="ant-descriptions-item-label ant-descriptions-item-colon">联系电话</th>
                     <td class="ant-descriptions-item-content" colspan="1">{{ treeDetail.phone }}</td>
-                  </tr> 
+                  </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">{{ treeDetail.startDate }}</td>
@@ -107,22 +99,10 @@
             <el-tab-pane label="时间周期" name="2">
               <el-form :model="ruleForm" ref="formRef" size="default" label-width="80px">
                 <el-form-item label="开始日期" prop="startDate">
-                  <el-date-picker
-                    v-model="ruleForm.startDate"
-                    type="date"
-                    placeholder="选择开始日期"
-                    class="w-35"
-                    :size="'default'"
-                  />
+                  <el-date-picker v-model="ruleForm.startDate" type="date" placeholder="选择开始日期" class="w-35" :size="'default'" />
                 </el-form-item>
                 <el-form-item label="结束日期" prop="endDate">
-                  <el-date-picker
-                    v-model="ruleForm.endDate"
-                    type="date"
-                    placeholder="选择结束日期"
-                    class="w-35"
-                    :size="'default'"
-                  />
+                  <el-date-picker v-model="ruleForm.endDate" type="date" placeholder="选择结束日期" class="w-35" :size="'default'" />
                 </el-form-item>
                 <!-- <el-form-item label="类型" prop="template">
                   <el-select v-model="ruleForm.template" filterable clearable placeholder="请选择类型" class="w-35">
@@ -157,7 +137,7 @@
       </el-col>
     </el-row>
 
-    <AddOrUpdate ref="addOrUpdateRef" @finish="getTreeList"/>
+    <AddOrUpdate ref="addOrUpdateRef" @finish="getTreeList" />
   </div>
 </template>
 
@@ -226,12 +206,12 @@ export default defineComponent({
       searchVal: '',
       treeDetail: {},
       deviceList: [],
-			unitData: [
-				{ label: '秒', value: 1 },
-				{ label: '分', value: 2 },
-				{ label: '时', value: 3 },
-				{ label: '天', value: 4 },
-			],
+      unitData: [
+        { label: '秒', value: 1 },
+        { label: '分', value: 2 },
+        { label: '时', value: 3 },
+        { label: '天', value: 4 },
+      ],
     });
 
     let ruleForm = ref({
@@ -242,14 +222,14 @@ export default defineComponent({
     let zlTreeSearchRef = ref()
 
     watch(() => state.searchVal, (val) => {
-			zlTreeSearchRef.value!.filter(val);
-		});
-
-		const filterNode = (value: string, data: any) => {
-			if (!value) return true;
-			return data.name.includes(value);
-		};
-    
+      zlTreeSearchRef.value!.filter(val);
+    });
+
+    const filterNode = (value: string, data: any) => {
+      if (!value) return true;
+      return data.name.includes(value);
+    };
+
     // 初始化表格数据
     const initTableData = () => {
       getTreeList();
@@ -264,7 +244,6 @@ export default defineComponent({
     const getDeviceList = () => {
       api.device.allList({}).then((res: any) => {
         state.deviceList = res.device || [];
-        console.log('res')
       })
     }
     const typeList = () => {
@@ -310,7 +289,7 @@ export default defineComponent({
     }
 
     const operateCmd = (type: string, data: any) => {
-      switch(type) {
+      switch (type) {
         case 'add':
           addOrUpdateRef.value.openDialog(type, data)
           break
@@ -353,6 +332,11 @@ export default defineComponent({
 </script>
 
 <style scoped lang="scss">
+.el-tree ::v-deep(.el-tree-node__label) {
+  width: 100%;
+  overflow: hidden;
+  display: block;
+}
 
 // :deep(.el-card__body) {
 //   padding: 0;
@@ -360,11 +344,13 @@ export default defineComponent({
 .zl-tree-search {
   margin: 0 12px 0 0;
   border-radius: 4px;
+
   &__filter {
     padding: 4px 10px;
     border-bottom: 1px solid #EAEAEA;
   }
 }
+
 .zl-tree-search__filter :deep .el-input__wrapper {
   box-shadow: none;
 }
@@ -376,16 +362,28 @@ export default defineComponent({
   justify-content: space-between;
   font-size: 14px;
   padding-right: 8px;
+  overflow: hidden;
+
+  .tree-label {
+    width: 100%;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    margin-right: 10px;
+  }
+
   &:hover {
     .tree-options {
       display: block;
     }
   }
 }
+
 :deep(.column-right) {
   padding: 0;
   background-color: transparent;
 }
+
 .icon-wjj {
   font-size: 12px;
   color: #C4C6CF;
@@ -393,59 +391,69 @@ export default defineComponent({
 
 table {
   width: 100%;
-	border-collapse: collapse;
-	text-indent: initial;
-	border-spacing: 2px;
+  border-collapse: collapse;
+  text-indent: initial;
+  border-spacing: 2px;
 }
+
 tbody {
-	box-sizing: border-box;
-	display: table-row-group;
-	vertical-align: middle;
-	border-color: inherit;
+  box-sizing: border-box;
+  display: table-row-group;
+  vertical-align: middle;
+  border-color: inherit;
 }
 
 tr {
-	display: table-row;
-	vertical-align: inherit;
-	border-color: inherit;
+  display: table-row;
+  vertical-align: inherit;
+  border-color: inherit;
 }
+
 .ant-descriptions-view {
-	width: 100%;
-	overflow: hidden;
-	border-radius: 4px;
+  width: 100%;
+  overflow: hidden;
+  border-radius: 4px;
 }
+
 .ant-descriptions-view {
-	border: 1px solid #e8e8e8;
+  border: 1px solid #e8e8e8;
 }
+
 .ant-descriptions-view table {
-	width: 100%;
-	table-layout: fixed;
+  width: 100%;
+  table-layout: fixed;
 }
-.ant-descriptions-view > table {
-	table-layout: auto;
+
+.ant-descriptions-view>table {
+  table-layout: auto;
 }
+
 .ant-descriptions-row {
-	border-bottom: 1px solid #e8e8e8;
+  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;
+  color: rgba(0, 0, 0, 0.85);
+  font-weight: 400;
+  font-size: 14px;
+  line-height: 1.5;
 }
+
 .ant-descriptions-item-label {
-	padding: 16px;
-	border-right: 1px solid #e8e8e8;
+  padding: 16px;
+  border-right: 1px solid #e8e8e8;
 }
+
 .ant-descriptions-item-label {
-	background-color: #fafafa;
+  background-color: #fafafa;
 }
+
 .ant-descriptions-item-content {
-	padding: 16px;
-	border-right: 1px solid #e8e8e8;
-	display: table-cell;
-	color: rgba(0, 0, 0, 0.65);
-	font-size: 14px;
-	line-height: 1.5;
+  padding: 16px;
+  border-right: 1px solid #e8e8e8;
+  display: table-cell;
+  color: rgba(0, 0, 0, 0.65);
+  font-size: 14px;
+  line-height: 1.5;
 }
 </style>