Browse Source

feat(tree): support default checked nodes

Casper Dai 2 years ago
parent
commit
d33bb08caf

+ 56 - 42
src/components/tree/DeviceTree/index.vue

@@ -1,46 +1,48 @@
 <template>
   <div
     v-loading="loading"
-    class="l-flex--col u-color--black u-font-size--sm u-relative"
-    :class="{ shrink: shrinkState }"
+    class="l-flex--col c-device-tree u-color--black u-font-size--sm u-relative"
+    :class="{ 'support-shrink': shrink, shrink: shrinkState }"
   >
-    <el-tabs
-      v-if="exact"
-      v-model="active"
-      class="c-tabs has-bottom-padding"
-    >
-      <el-tab-pane
-        label="按部门"
-        name="group"
-      />
-      <el-tab-pane
-        label="按分辨率"
-        name="ratio"
-      />
-      <el-tab-pane
-        label="按宽高比"
-        name="productType"
-      />
-    </el-tabs>
-    <warning
-      v-if="error"
-      @click="getDevices"
-    />
-    <template v-else>
-      <div class="l-flex__none l-flex--row c-sibling-item--v u-overflow--hidden">
-        <div class="l-flex__auto" />
-        <search-input
-          v-model.trim="deviceName"
-          class="l-flex__none"
-          placeholder="设备名称"
-          @search="onSearch"
+    <div class="l-flex__fill l-flex--col c-device-tree__content">
+      <el-tabs
+        v-if="exact"
+        v-model="active"
+        class="c-tabs has-bottom-padding"
+      >
+        <el-tab-pane
+          label="按部门"
+          name="group"
+        />
+        <el-tab-pane
+          label="按分辨率"
+          name="ratio"
+        />
+        <el-tab-pane
+          label="按宽高比"
+          name="productType"
         />
-      </div>
-      <c-tree
-        class="l-flex__fill c-sibling-item--v"
-        :root-option="rootOption"
+      </el-tabs>
+      <warning
+        v-if="error"
+        @click="getDevices"
       />
-    </template>
+      <template v-else>
+        <div class="l-flex__none l-flex--row c-sibling-item--v u-overflow--hidden">
+          <div class="l-flex__auto" />
+          <search-input
+            v-model.trim="deviceName"
+            class="l-flex__none"
+            placeholder="设备名称"
+            @search="onSearch"
+          />
+        </div>
+        <c-tree
+          class="l-flex__fill c-sibling-item--v"
+          :root-option="rootOption"
+        />
+      </template>
+    </div>
     <i
       v-if="shrink"
       class="o-shrink-icon u-color--black u-font-size--lg has-active"
@@ -137,6 +139,7 @@ export default {
         if (this.exact) {
           this.$productCache = productCacheOptions.cache
         }
+        this.$emit('loaded', data)
         return this.getDevicesByActive()
       })
     },
@@ -218,7 +221,7 @@ export default {
     },
     onSearch () {
       const regx = this.deviceName ? new RegExp(this.deviceName) : null
-      const rootOption = this.createNode()
+      const rootOption = this.createRootNode()
       this.setNodes(rootOption, this.onFilter(rootOption, this.$nodes, regx))
       this.rootOption = rootOption
       this.customExpand = !!this.deviceName
@@ -254,15 +257,26 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-.shrink {
-  box-sizing: border-box;
-  width: $spacing !important;
+.c-device-tree {
+  &.support-shrink {
+    padding-right: $spacing--lg !important;
+
+    &.shrink {
+      box-sizing: border-box;
+      width: $spacing--lg !important;
+
+      .c-device-tree__content {
+        width: 0;
+        overflow: hidden;
+      }
+    }
+  }
 }
 
 .o-shrink-icon {
   position: absolute;
   top: 50%;
-  right: 0;
+  right: calc(($spacing--lg - $spacing) / 2);
   transform: translateY(-50%);
 }
 </style>

+ 52 - 2
src/components/tree/tree.js

@@ -24,6 +24,10 @@ export default {
     hideDisabled: {
       type: [Boolean, String],
       default: true
+    },
+    defaultCheckedNodes: {
+      type: Array,
+      default: null
     }
   },
   data () {
@@ -52,15 +56,49 @@ export default {
     }
   },
   methods: {
+    initDefaultCheckedNodesCache () {
+      if (this.checkbox && this.defaultCheckedNodes && this.defaultCheckedNodes.length) {
+        const map = {}
+        this.defaultCheckedNodes.forEach(item => {
+          map[item.id] = item
+        })
+        console.log('selected nodes', map)
+        return map
+      }
+      return null
+    },
     emitChange () {
       if (!this.checkbox) {
         return
       }
+      if (this.$nodeCache) {
+        const diff = Object.values(this.$nodeCache)
+        console.log('node diff', diff)
+        if (diff.length) {
+          this.$emit(
+            'change',
+            [
+              ...this.flatNode(this.rootOption, []),
+              ...diff
+            ]
+          )
+          return
+        }
+      }
       this.$emit(
         'change',
         this.flatNode(this.rootOption, [])
       )
     },
+    createRootNode () {
+      this.$nodeCache = this.initDefaultCheckedNodesCache()
+      return {
+        disabled: false,
+        checked: false,
+        indeterminate: false,
+        children: []
+      }
+    },
     createNode (item, parent) {
       return {
         parent,
@@ -72,19 +110,31 @@ export default {
       }
     },
     createLeafNode (parent, item) {
+      let checked = false
+      if (this.$nodeCache) {
+        const id = item.id
+        checked = !!this.$nodeCache[id]
+        if (checked) {
+          delete this.$nodeCache[id]
+        }
+      }
       return {
         parent,
         disabled: false,
-        checked: false,
+        checked,
         ...item
       }
     },
     setNodes (parent, nodes) {
       parent.children = this.hideDisabled ? nodes.filter(({ disabled }) => !disabled) : nodes
       parent.disabled = !nodes.some(({ disabled }) => !disabled)
+      if (this.$nodeCache) {
+        parent.checked = !parent.children.some(({ disabled, checked }) => !disabled && !checked)
+        parent.indeterminate = !parent.checked && parent.children.some(({ disabled, checked, indeterminate }) => !disabled && (checked || indeterminate))
+      }
     },
     flatNode (node, arr) {
-      const { checked, indeterminate, children, ...info } = node
+      const { disabled, checked, indeterminate, children, parent, ...info } = node
       if (!children && checked) {
         arr.push(info)
       } else if (children && (checked || indeterminate)) {

+ 1 - 1
src/views/dashboard/components/DeviceGroupTree.vue

@@ -24,7 +24,7 @@ export default {
   },
   methods: {
     init () {
-      const rootOption = this.createNode()
+      const rootOption = this.createRootNode()
       if (this.groups.length === 1 && (!this.groups[0].id || !this.groups[0].name)) {
         this.setNodes(rootOption, this.transformDevices(this.groups[0].children, rootOption))
       } else {

+ 1 - 1
src/views/platform/upgrade/deploy/components/DeviceTypeTree.vue

@@ -56,7 +56,7 @@ export default {
           const map = {}
           const groups = []
           const arr = []
-          const rootOption = this.createNode()
+          const rootOption = this.createRootNode()
           data.forEach(({ id, name, remark }) => {
             if (remark) {
               if (!map[remark]) {