zzw
14 小时以前 5643f9caa25e78810e05073468c846411a373d04
emergency-repair-web/src/components/ProductTreePicker.vue
@@ -7,7 +7,9 @@
          ref="tree"
          :data="tree"
          node-key="id"
          default-expand-all
          v-loading="loading"
          lazy
          :load="loadNode"
          show-checkbox
          check-strictly
          :filter-node-method="filterNode"
@@ -51,7 +53,7 @@
    selectedIds: { type: Array, default: () => [] }
  },
  data() {
    return { localVisible: false, keyword: '', tree: [], checkedCount: 0, selectedDevices: [] }
    return { localVisible: false, keyword: '', tree: [], checkedCount: 0, selectedDevices: [], selectedMap: {}, loading: false }
  },
  computed: {
    treeProps() {
@@ -74,52 +76,82 @@
  methods: {
    load() {
      const lockedXNo = String(this.xNo || '').trim()
      api.get('/system/tree', { params: { type: 'product' } }).then(res => {
        const source = res.data || []
        this.tree = lockedXNo ? this.filterTreeByXNo(source, lockedXNo) : source
      this.loading = true
      const ids = (this.selectedIds || []).map(String).filter(Boolean)
      const treeRequest = lockedXNo
        ? api.get('/system/tree/product/side-roots', { params: { xNo: lockedXNo } })
        : api.get('/system/tree/product/roots')
      const selectedRequest = ids.length
        ? api.get('/system/tree/product/selected', { params: { ids: ids.join(',') } })
        : Promise.resolve({ data: [] })
      Promise.all([treeRequest, selectedRequest]).then(([treeRes, selectedRes]) => {
        this.tree = treeRes.data || []
        this.selectedMap = (selectedRes.data || []).reduce((map, node) => {
          map[String(node.id)] = node
          return map
        }, {})
        this.keyword = ''
        this.$nextTick(this.restoreChecked)
        this.$nextTick(() => {
          this.expandLockedRoots(lockedXNo)
          this.restoreChecked()
          this.syncSelected()
        })
      }).finally(() => { this.loading = false })
    },
    expandLockedRoots(lockedXNo) {
      if (!lockedXNo || !this.$refs.tree) return
      this.tree.forEach(node => {
        const treeNode = this.$refs.tree.getNode(node.id)
        if (treeNode) treeNode.expand()
      })
    },
    filterTreeByXNo(nodes, xNo) {
      const result = []
      ;(nodes || []).forEach(node => {
        if (Number(node.nodeLevel) === 2) {
          if (String(node.name || '').trim() === xNo) result.push(node)
          return
        }
        const children = this.filterTreeByXNo(node.children || [], xNo)
        if (children.length || node.nodeType === 'DEVICE') {
          result.push(children.length ? { ...node, children } : node)
        }
      })
      return result
    loadNode(node, resolve) {
      if (!node || !node.data || !node.data.id) {
        resolve([])
        return
      }
      api.get('/system/tree/product/children', { params: { parentId: node.data.id } })
        .then(res => {
          resolve(res.data || [])
          this.$nextTick(this.restoreChecked)
        })
        .catch(() => resolve([]))
    },
    restoreChecked() {
      if (!this.$refs.tree) return
      const ids = (this.selectedIds || []).map(String).filter(Boolean)
      const ids = Object.keys(this.selectedMap).filter(id => Boolean(this.$refs.tree.getNode(id)))
      this.$refs.tree.setCheckedKeys(ids)
      this.syncSelected()
    },
    handleCheck(node) {
      const tree = this.$refs.tree
      const treeNode = tree && tree.getNode(node.id)
      this.syncSelected()
      if (treeNode && treeNode.checked) {
        const selected = this.deviceNodes().map(item => this.decorateNode(item))
        const xNos = Array.from(new Set(selected.map(item => item.xNo).filter(Boolean)))
        const xNos = Array.from(new Set(this.selectedDevices.map(item => item.xNo).filter(Boolean)))
        if (xNos.length > 1) {
          tree.setChecked(node.id, false, true)
          this.$message.warning('同一故障只能选择同一个X号下的设备')
          this.syncSelected()
          this.$message.warning('同一故障只能选择同一个rk_X号下的设备')
        }
      }
      this.syncSelected()
    },
    syncSelected() {
      const selected = this.deviceNodes().map(node => this.decorateNode(node))
      this.selectedDevices = selected
      this.checkedCount = selected.length
      const tree = this.$refs.tree
      if (!tree) return
      const selectedMap = { ...this.selectedMap }
      const checked = tree.getCheckedNodes().filter(node => node.nodeType === 'DEVICE')
      const checkedIds = new Set(checked.map(node => String(node.id)))
      Object.keys(selectedMap).forEach(id => {
        if (tree.getNode(id) && !checkedIds.has(id)) delete selectedMap[id]
      })
      checked.forEach(node => { selectedMap[String(node.id)] = this.decorateNode(node) })
      this.selectedMap = selectedMap
      this.selectedDevices = Object.values(selectedMap)
      this.checkedCount = this.selectedDevices.length
    },
    decorateNode(node) {
      if (!this.$refs.tree) return { ...node }
      const pathNodes = []
      let current = this.$refs.tree.getNode(node.id)
      while (current && current.data) {
@@ -134,8 +166,10 @@
      return { ...node, pathNames: pathNodes.map(item => item.name), parentPathNames, xNo: xNode ? xNode.name : '' }
    },
    removeSelected(device) {
      if (!this.$refs.tree) return
      this.$refs.tree.setChecked(device.id, false, true)
      const selectedMap = { ...this.selectedMap }
      delete selectedMap[String(device.id)]
      this.selectedMap = selectedMap
      if (this.$refs.tree && this.$refs.tree.getNode(device.id)) this.$refs.tree.setChecked(device.id, false, true)
      this.syncSelected()
    },
    deviceNodes() {
@@ -147,12 +181,12 @@
      return (data.name || '').includes(value) || (data.code || '').includes(value)
    },
    confirm() {
      const nodes = this.deviceNodes()
      const nodes = this.selectedDevices
      if (!nodes.length) return this.$message.warning('请选择设备')
      const selected = nodes.map(node => this.decorateNode(node))
      const selected = nodes
      const xNos = Array.from(new Set(selected.map(item => item.xNo).filter(Boolean)))
      if (xNos.length > 1) {
        return this.$message.warning('同一故障只能选择同一个X号下的设备')
        return this.$message.warning('同一故障只能选择同一个rk_X号下的设备')
      }
      this.$emit('select', selected)
      this.localVisible = false