zzw
3 天以前 757dcb3fcad665eaef93074a4981c4134f7a027e
emergency-repair-web/src/views/system/TreeManage.vue
@@ -3,7 +3,7 @@
    <div class="page-title">
      <div>
        <h2>{{ isProduct ? '产品结构树管理' : '设备基础库管理' }}</h2>
        <p>{{ isProduct ? '型号 → X号 → 一级系统 → 二级系统 → 设备' : '一级系统 → 二级系统 → 设备' }}</p>
        <p>{{ isProduct ? '型号 → rk_X号 → 一级系统 → 二级系统 → 设备' : '一级系统 → 二级系统 → 设备' }}</p>
      </div>
      <div>
        <el-button icon="el-icon-plus" @click="addRoot">新增一级节点</el-button>
@@ -18,7 +18,10 @@
          ref="tree"
          :data="tree"
          node-key="id"
          default-expand-all
          v-loading="loading"
          :lazy="isProduct"
          :load="loadNode"
          :default-expand-all="!isProduct"
          highlight-current
          :filter-node-method="filterNode"
          :props="{ label: 'name', children: 'children' }"
@@ -27,7 +30,7 @@
          <span slot-scope="{ data }" class="tree-node">
            <span class="level-badge">{{ levelText(data.nodeLevel) }}</span>
            <span>{{ data.name }}</span>
            <small>{{ data.code }}</small>
            <small v-if="!isProduct && data.code">{{ data.code }}</small>
          </span>
        </el-tree>
      </section>
@@ -44,19 +47,14 @@
          <el-form :model="form" label-width="100px">
            <el-form-item label="节点层级"><el-tag type="info">{{ levelText(form.nodeLevel) }}</el-tag></el-form-item>
            <el-form-item label="名称"><el-input v-model="form.name"></el-input></el-form-item>
            <el-form-item label="编码"><el-input v-model="form.code"></el-input></el-form-item>
            <el-form-item v-if="!isProduct" label="编码"><el-input v-model="form.code"></el-input></el-form-item>
            <el-form-item v-if="isProduct" label="节点类型">
              <el-select v-model="form.nodeType" :disabled="form.nodeLevel < 5" style="width:100%">
                <el-option label="型号" value="MODEL"></el-option>
                <el-option label="X号" value="X_NO"></el-option>
                <el-option label="rk_X号" value="X_NO"></el-option>
                <el-option label="一级系统" value="SYSTEM1"></el-option>
                <el-option label="二级系统" value="SYSTEM2"></el-option>
                <el-option label="设备" value="DEVICE"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item v-if="isProduct && form.nodeLevel === 5" label="基础设备">
              <el-select v-model="form.baseEquipmentId" filterable placeholder="关联设备基础库设备" style="width:100%">
                <el-option v-for="item in baseDevices" :key="item.id" :label="item.path + ' / ' + item.name" :value="item.id"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="排序"><el-input-number v-model="form.sortNo" :min="1" style="width:180px"></el-input-number></el-form-item>
@@ -73,23 +71,38 @@
import api from '@/api'
export default {
  name: 'TreeManage',
  props: {
    treeType: { type: String, required: true }
  },
  data() {
    return { tree: [], keyword: '', form: {}, saving: false, baseDevices: [] }
    return { tree: [], keyword: '', form: {}, saving: false, loading: false }
  },
  computed: {
    treeType() { return this.$route.meta.treeType },
    isProduct() { return this.treeType === 'product' },
    maxLevel() { return this.isProduct ? 5 : 3 },
    levelNames() { return this.isProduct ? ['型号', 'X号', '一级系统', '二级系统', '设备'] : ['一级系统', '二级系统', '设备'] }
    levelNames() { return this.isProduct ? ['型号', 'rk_X号', '一级系统', '二级系统', '设备'] : ['一级系统', '二级系统', '设备'] }
  },
  watch: {
    keyword(value) { this.$refs.tree && this.$refs.tree.filter(value) },
    '$route.meta.treeType'() { this.form = {}; this.load() }
    treeType() { this.form = {}; this.load() }
  },
  created() { this.load() },
  methods: {
    load() {
      api.get('/system/tree', { params: { type: this.treeType } }).then(res => { this.tree = res.data || [] })
      this.loading = true
      const request = this.isProduct
        ? api.get('/system/tree/product/roots')
        : api.get('/system/tree', { params: { type: this.treeType } })
      request.then(res => { this.tree = res.data || [] }).finally(() => { this.loading = false })
    },
    loadNode(node, resolve) {
      if (!this.isProduct || !node || !node.data || !node.data.id) {
        resolve([])
        return
      }
      api.get('/system/tree/product/children', { params: { parentId: node.data.id } })
        .then(res => resolve(res.data || []))
        .catch(() => resolve([]))
    },
    levelText(level) { return this.levelNames[(level || 1) - 1] || ('第' + level + '级') },
    filterNode(value, data) {
@@ -98,31 +111,16 @@
    },
    selectNode(node) {
      this.form = { ...node }
      if (this.isProduct && node.nodeLevel === 5) this.loadBaseDevices()
    },
    nodeTypeForLevel(level) {
      return this.isProduct ? ['MODEL', 'X_NO', 'SYSTEM1', 'SYSTEM2', 'DEVICE'][level - 1] : 'BASE_' + level
    },
    addRoot() {
      this.form = { parentId: 0, nodeLevel: 1, nodeType: this.nodeTypeForLevel(1), name: '', code: '', sortNo: 1, remark: '' }
      if (this.isProduct) this.form.baseEquipmentId = null
    },
    addChild() {
      const level = (this.form.nodeLevel || 1) + 1
      this.form = { parentId: this.form.id, nodeLevel: level, nodeType: this.nodeTypeForLevel(level), name: '', code: '', sortNo: 1, remark: '', baseEquipmentId: null }
      if (this.isProduct && level === 5) this.loadBaseDevices()
    },
    loadBaseDevices() {
      api.get('/system/tree', { params: { type: 'base' } }).then(res => { this.baseDevices = this.flattenBase(res.data || [], []) })
    },
    flattenBase(nodes, parents) {
      const result = []
      nodes.forEach(node => {
        const path = parents.concat(node.name)
        if (node.nodeLevel === 3) result.push({ ...node, path: path.slice(0, -1).join(' / ') })
        if (node.children) result.push(...this.flattenBase(node.children, path))
      })
      return result
      this.form = { parentId: this.form.id, nodeLevel: level, nodeType: this.nodeTypeForLevel(level), name: '', code: '', sortNo: 1, remark: '' }
    },
    save() {
      if (!this.form.name) return this.$message.warning('请输入节点名称')
@@ -147,7 +145,7 @@
</script>
<style scoped>
.tree-layout { display: grid; grid-template-columns: 420px minmax(0, 1fr); gap: 12px; }
.tree-panel, .detail-panel { min-height: calc(100vh - 140px); padding: 14px; border: 1px solid #dce4ec; border-radius: 4px; background: #fff; }
.tree-panel, .detail-panel { min-height: calc(100vh - 180px); padding: 14px; border: 1px solid #dce4ec; border-radius: 4px; background: #fff; }
.tree-node { display: flex; align-items: center; gap: 7px; }
.tree-node small { color: #95a2b0; }
.level-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 50px; height: 20px; padding: 0 5px; border-radius: 3px; color: #2f658f; background: #e9f3fb; font-size: 11px; }