基于JEECG-BOOT制作“左树右表”交互页面

Posted 瀚岳-诸葛弩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于JEECG-BOOT制作“左树右表”交互页面相关的知识,希望对你有一定的参考价值。

前置知识:

1、ant-design-vue

2、vue的slot概念

需求效果:

如上界面所示。

后端不改动,基于jeecg-boot生成的代码,前端自定义,分为左右两块,典型的“左树右表”结构。实现目的:

1、左边树结构从两张表生成,并封装成控件,方便后期重复调用;

2、右边列表,默认展示点击的叶子节点的关联数据,点击保存后,保存最终结果;

3、通过ant-design-vue统一UI风格

具体开发:

1、树控件的封装

(1)后端代码:从数据库取出要生成的树结构的节点数据;

首先,定义树结构属性。此处,定义了一个通用类,按照jeecg-boot推荐,按规范建立目录和文件

(2)构建后端节点生成代码

(3)构建前端代码,封装成控件

script下的代码比较简单,直接看代码。

import  getAction  from '@api/manage'

export default 
  name: 'DictDeviceTypeTree',
  data() 
    return 
      treeData: [],
      componentHeight: document.documentElement.clientHeight - 185
    
  ,
  methods: 
    onLoadData(selectedNode) 
      let that = this

      let catalogId = 0
      if (selectedNode != null) 
        catalogId = selectedNode.dataRef.id
      

      let params = new Object()
      params.catalogId = catalogId



      return new Promise(resolve => 
        getAction('/jeecg-product/dict.device_catalog_type/queryByCatalogId', params).then(function(res) 
          res.result.forEach(function(treeNode) 

            let node = new Object()

            node.key = treeNode.key
            node.title = treeNode.title
            node.isLeaf = treeNode.isLeaf
            node.id = treeNode.id
            node.pid = treeNode.pid
            node.icon = <a-icon type=treeNode.icon />
            node.nodeType = treeNode.nodeType
            node.children = []


            if (selectedNode != null) 
              node.path = selectedNode.dataRef.path + '-' + node.title
             else 
              node.path = node.title
            
            if (selectedNode == null) 
              that.treeData.push(node)
             else 
              selectedNode.dataRef.children.push(node)
            
          )
        )
        resolve()
      )
    ,
    onSelectNode(nodeId, e) 
      let param = new Object()
      param.node = e.node.dataRef
      param.id = e.node.dataRef.key
      param.path = e.node.dataRef.path
      param.title = e.node.dataRef.title
      param.nodeType = e.node.dataRef.nodeType
      this.$emit('SelectNode', param)
    
  ,
  created() 
    this.onLoadData()
  

注意两个地方:

(1)节点的属性构建。可以构建任意树节点的非必须属性,通过dataRef进行访问

(2)广播事件时,可以将一些常用的信息打包在一个object中,方便复用。我的做法如下:

2、列表

 

Template的布局如下:

Script代码结构:

需要注意的地方:

(1)scopedSlots和slots(官网文档讲的不是很清,要看代码)

scopedSlots:插槽table的cell区域

slots:插槽table的title区域,使用了slots,column就不能有单独的title属性,否则slots失效。

(2)利用jeecg-boot封装好的前端控件,各种控件可看官网,也可直接到生成的vue文件下找。如本文例子用用到的,与表关联的dropdownlist:

<j-dict-select-tag type='list' dictCode='dict_device_item_type,item_type,id' v-model='record.itemTypeId' style='width:100%' />
<template>
  <a-row :gutter='16'>
    <a-col :span='4'>
      <DictDeviceTypeTree @SelectNode='nodeClick'></DictDeviceTypeTree>
    </a-col>
    <a-col :span='20'>
      <a-button type="primary" @click='saveData'>保存</a-button>
      <a-table :columns="columns" :data-source="data" :pagination='false' style='background: #fff'>
          <span slot="itemTypeId" slot-scope="text, record">
              <j-dict-select-tag type='list' dictCode='dict_device_item_type,item_type,id' v-model='record.itemTypeId' style='width:100%' />
          </span>
          <span slot="itemName" slot-scope="text, record">
              <a-input v-model='record.itemName' />
          </span>
          <span slot="dataShowingTypeId" slot-scope="text, record">
              <j-dict-select-tag type='list' dictCode='dict_data_showing_type,data_showing_type,id' v-model='record.dataShowingTypeId' style='width:100%' />
          </span>
          <span slot="defaultValue" slot-scope="text, record">
              <a-input v-model='record.defaultValue' />
          </span>
          <span slot="unit" slot-scope="text, record">
              <a-input v-model='record.unit' />
          </span>
          <span slot="plcPlace" slot-scope="text, record">
              <a-input v-model='record.plcPlace' />
          </span>
          <span slot="plcType" slot-scope="text, record">
              <a-input v-model='record.plcType' />
          </span>
          <span slot="isObservingItem" slot-scope="text, record">
              <a-switch checked-children="是" un-checked-children="否" v-model='record.isObservingItem' />
          </span>
          <span slot="isMaintainingItem" slot-scope="text, record">
              <a-switch checked-children="是" un-checked-children="否" v-model='record.isMaintainingItem' />
          </span>

          <span slot="operTitle">
            <a-button type="primary" @click='addRow'>+</a-button>
          </span>
          <span slot="oper" slot-scope="text, record">
              <a-button type="danger" @click='delRow(record.key)'>—</a-button>
          </span>
      </a-table>
    </a-col>
  </a-row>
</template>

<script>
import DictDeviceTypeTree from '@comp/product/DictDeviceTypeTree'
import  httpAction, getAction  from '@api/manage'

export default 
  name: 'test',
  components: 
    DictDeviceTypeTree
  ,
  data()
    return 
      columns:[
        title: '指标类型', dataIndex: 'itemTypeId', key: 'itemTypeId', width: 80, scopedSlots:customRender:'itemTypeId',
        title: '指标名称', dataIndex: 'itemName', key: 'itemName', width:120,scopedSlots:customRender:'itemName',
        title: '显示类型', dataIndex: 'dataShowingTypeId', key: 'dataShowingTypeId', width:80,scopedSlots:customRender:'dataShowingTypeId',
        title: '默认值', dataIndex: 'defaultValue', key: 'defaultValue', width: 80,scopedSlots:customRender:'defaultValue',
        title: '单位', dataIndex: 'unit', key: 'unit', width: 80,scopedSlots:customRender:'unit',
        title: 'PLC地址', dataIndex: 'plcPlace', key: 'plcPlace', width: 80,scopedSlots:customRender:'plcPlace',
        title: 'PLC数据类型', dataIndex: 'plcType', key: 'plcType', width: 100,scopedSlots:customRender:'plcType',
        title: '是否重点观测', dataIndex: 'isObservingItem', key: 'isObservingItem', width: 80,scopedSlots:customRender:'isObservingItem',
        title: '是否维修监控', dataIndex: 'isMaintainingItem', key: 'isMaintainingItem', width: 80,scopedSlots:customRender:'isMaintainingItem',
        dataIndex: 'oper', key: 'oper', width: 80,scopedSlots:customRender:'oper',slots:title:'operTitle',
      ],
      data:[],
      selectedDeviceTypeId:''
    
  ,
  methods: 
    nodeClick: function(selectedNode) 
      let that = this
      if(selectedNode.nodeType == "deviceType")
        that.selectedDeviceTypeId = selectedNode.id;
        that.data = []
        let params  = new Object()

        params.DeviceTypeId = that.selectedDeviceTypeId

        getAction('/jeecg-product/dict.device_item/dictDeviceItem/queryDeviceTypeId', params).then(function(res) 
          res.forEach(function(item) 
            let deviceItem = new Object()
            deviceItem.deviceTypeId = that.selectedDeviceTypeId
            deviceItem.key = item.id
            deviceItem.itemTypeId = item.itemTypeId
            deviceItem.itemName = item.itemName
            deviceItem.dataShowingTypeId = item.dataShowingTypeId
            deviceItem.defaultValue = item.defaultValue
            deviceItem.unit = item.unit
            deviceItem.plcPlace = item.plcPlace
            deviceItem.plcType = item.plcType
            deviceItem.isObservingItem = item.isObservingItem
            deviceItem.isMaintainingItem = item.isMaintainingItem

            that.data.push(deviceItem)
          )
        )
      
      else
        this.selectedDeviceTypeId = ''
        this.$message.warning("请选择设备型号。")
      
    ,
    addRow:function()
      if(this.selectedDeviceTypeId == '')
        this.$message.warning("请选择设备型号。")
      
      else
        this.data.push(
          
            key:this.guid(),
            deviceTypeId:this.selectedDeviceTypeId,
            itemTypeId:'',
            itemName:'',
            dataShowingTypeId:'',
            defaultValue:'',
            unit:'',
            plcPlace:'',
            plcType:'',
            isObservingItem:0,
            isMaintainingItem:0
          
        )
      

    ,
    delRow:function(key)
      // alert(key)
      let that = this
      this.data.forEach(function(item, index) 
        if(item.key == key)
            that.data.splice(index,1)
        
      )
    ,
    saveData:function()
      let that = this
      if(this.data.length == 0)
        let httpurl='/jeecg-product/dict.device_item/dictDeviceItem/delByDeviceTypeId'

        let params = new Object();
        params.deviceTypeId = that.selectedDeviceTypeId

        getAction(httpurl, params).then(function(res) 
          that.$message.success(res.message);
          that.$emit('ok');
        )

      
      else
        let httpurl='/jeecg-product/dict.device_item/dictDeviceItem/delAndSaveBatch'
        let method = 'post'

        this.data.forEach(function(item)
          item.isObservingItem = (item.isObservingItem==true?1:0)
          item.isMaintainingItem = (item.isMaintainingItem==true?1:0)
        )
        httpAction(httpurl,this.data,method).then((res)=>
          if(res.success)
            that.$message.success(res.message);
            that.$emit('ok');
          else
            that.$message.warning(res.message);
          
        ).finally(() => 
          that.confirmLoading = false;
        )
      
    ,
    guid:function()
      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) 
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
      )
    
  

</script>

<style scoped>

</style>

以上是关于基于JEECG-BOOT制作“左树右表”交互页面的主要内容,如果未能解决你的问题,请参考以下文章

基于JEECG-BOOT制作“左树右表”交互页面

JVS低代码配置平台基于树形字典的纯配置实现左树右表

代码审计入门之Jeeplus代码审计

JEESITE快速开发平台代码生成模块介绍及使用

记一个基于JEECG-BOOT的比较复杂的增删改功能的实现

基于JEECG-BOOT的list页面的地址栏参数传递