从零实现一套低代码(保姆级教程)【后端服务】 --- 【9】实现Table表格组件以及数据展示

摘要

经过前面几章的内容,我们的后端服务已经支持了对页面的管理,对图片的管理,并且也支持了在XinBuilder中如何去使用它们。其实到目前为止,我们的XinBuilderServer服务,已经具备了基本的功能了。

可能是因为我是前端开发的原因,所以我在做这个项目重点一直是放在前端的功能实现的。后端代码比较少。

话说回来,这一篇继续回归到XinBuilder的项目里,再上一篇中,我们实现了和实体相关的后端内容,也就是我们有了持久化的数据存储。但是有了数据之后,我们如何能够在低代码项目里面使用?

对于数据的使用无非就是数据的处理以及数据的展示,在数据展示上,我们有很多种方式,比较常见的有表格,列表等等。

本篇主要通过Table组件来串通数据在XinBuilder中如何展示。

1.创建一张Student表

前期的准备工作,我们就在平台下创建一张Student表。

创建好后,我们来到swagger中,给这张表增加几条数据。

这里可以多加一些数据,方便后续的展示。

有了数据之后,我们希望的是,在XinBuilder中实现一个Table组件,可以去展示这些数据。或者去展示某张表的部分数据。

所以Table组件是一定需要一个属性,去选择对应的实体以及字段。

2.创建Table组件,实现选择实体的功能

Table组件我们放在数据展示分组里面,之前写过很多组件的创建。至于创建组件的过程,这里就不去贴代码了。

我们要实现的是给Table组件能够选择实体的功能。

所以在tableAttribute中,我们需要一个弹窗类型的属性。

javascript 复制代码
  {
    label: '选择实体',
    value: 'entityCode',
    type: 'modal',
    modalType: 'EntitySelect'
  },

同时,在modal下新建一个EntitySelect的文件夹。用来去选择对应的实体,和实体下面的字段。

我们要实现出一个可以选择实体,以及实体下字段的弹窗。

上面的Select选择器用来选择对应的实体,然后再通过Switch去选择该实体下的字段。 所以对于表格组件就需要两个属性。

entityCode:实体编码 schemaList:需要展示的字段

这里我们贴一下弹窗的代码:

javascript 复制代码
import { useEffect, useState } from 'react';
import { Modal, Select, Switch, message } from 'antd';
import { getComById } from '../../../utils/nodeUtils'
import Store from '../../../store/index'
import axios from 'axios';

export interface Entity {
  entityCode: string,
  entityName: string,
  entitySchema: EntitySchema
}

interface EntitySchema {
  [key: string]: string
}

const EntitySelect: React.FunctionComponent = (props: any) => {
  const { openModal, setOpenModal, valueKey } = props;
  const comList = JSON.parse(JSON.stringify(Store.getState().comList))
  const selectCom = Store.getState().selectCom
  const selectNode = getComById(selectCom, comList)
  const [nodeSchemaList, setNodeSchemaList] = useState([...(selectNode.schemaList || [])])

  const [entityList, setEntityList] = useState<Entity []>([])
  const [selectEntity, setSelectEntity] = useState(selectNode.entityCode || '')

  useEffect(() => {
    axios.post("http://localhost:4000/entity/getEntityList")
    .then(res => {
      if(res.data.data) {
        setEntityList(res.data.data)
      }else {
        message.error("请求实体列表失败")
      }
    })
  }, [])

  const handleCancel = () => {
    setOpenModal(false)
    setSelectEntity(selectNode.entityCode || '')
    setNodeSchemaList([...(selectNode.schemaList || [])])
  }

  const handleOk = () => {
    if(selectNode) {
      selectNode[valueKey as keyof typeof selectNode] = selectEntity;
      selectNode.schemaList = nodeSchemaList;
    }
    Store.dispatch({type: 'changeComList', value:comList})
    setOpenModal(false)
    setSelectEntity(selectNode.entityCode || '')
    setNodeSchemaList([...(selectNode.schemaList || [])])
  }

  const getOptions = () => {
    return entityList.map((item: Entity) => {
      return {
        value: item.entityCode,
        label: item.entityCode
      }
    })
  }

  const changeEntity = (value: string) => {
    setSelectEntity(value)
    setNodeSchemaList([])
  }

  const changeSwitch = (schemaCode: string) => {
    return (value: boolean) => {
      if(value && !nodeSchemaList.includes(schemaCode)) {
        nodeSchemaList.push(schemaCode)
      }else if(!value && nodeSchemaList.includes(schemaCode)) {
        const index = nodeSchemaList.indexOf(schemaCode);
        nodeSchemaList.splice(index,1)
      }
      setNodeSchemaList([...nodeSchemaList])
    }
  }

  const getSchemaList = () => {
    const entity = entityList.find((item: Entity) => item.entityCode === selectEntity);
    const schemaList = Object.keys(entity?.entitySchema || {}) || [];
    return <div style={{display:'flex', width:400, justifyContent:'flex-start',flexWrap:'wrap'}}>
      {
        schemaList.map(item => {
          return <div style={{width:'100px'}}>
            <p>{item}</p>
            <Switch onChange={changeSwitch(item)} value={nodeSchemaList.includes(item)}></Switch>
          </div>
        })
      }
    </div>
  }
  
  return <Modal closable={false} open={openModal} onOk={handleOk} onCancel={handleCancel}>
    <div style={{width:250, display:'flex',justifyContent:'space-between'}}>
      <div style={{marginTop:'5px', fontWeight:1000}}>选择实体:</div>
      <Select onChange={changeEntity} value={selectEntity} style={{width: 150}} options={getOptions()}></Select>
    </div>
    <div>
      {
        getSchemaList()
      }
    </div>
  </Modal>;
};

export default EntitySelect;

Ok,有了这个弹窗之后,我们就可以给表格组件赋予这两个属性了。

3.实现表格的数据展示

当表格组件有了这两个属性之后,我们就可以在表格内部通过ajax请求到对应的数据。 赋给表格的columns属性和datasource属性。

javascript 复制代码
import { useState, useEffect } from 'react';
import { Table as AntTable, message } from 'antd';
import axios from 'axios';

const Table: React.FunctionComponent = (props: any) => {
    const { entityCode, schemaList, size, bordered, showHeader = true, pagination = false, comStyle } = props;
    const [entityData, setEntityData] = useState([])
  

    useEffect(() => {
        axios.post("http://localhost:4000/entity/getEntityData", {entityCode})
        .then(res => {
            if(res.data.data) {
                setEntityData(res.data.data)
            }
        })
    }, [entityCode])

    const getColumns = () => {
        return schemaList.map((item: any) => {
            return {
                title: item,
                dataIndex: item,
                key: item
            }
        })
    }

    const getData = () => {
        return entityData.map((item: any) => {
            return {
                key: item._id,
                ...item
            }
        })
    }
 
    return <AntTable
        dataSource={getData()}
        columns={getColumns()}
        size={size}
        pagination={pagination}
        bordered={bordered}
        showHeader={showHeader}
        style={{...comStyle}}
    />;
};

export default Table;

4.补充表格的其他属性

最后我们在给表格补充一下其他属性和样式。 就可以通过关联对应的实体,确定表格的columns和data。从而正常展示数据库中的数据了。

这部分代码提交在github上
github.com/TeacherXin/...
commit: fix: 第十九节:增加Table组件

相关推荐
阿伟来咯~3 分钟前
记录学习react的一些内容
javascript·学习·react.js
吕彬-前端8 分钟前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱11 分钟前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
bysking1 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
Oo_Amy_oO6 小时前
【极限编程(XP)】
低代码·极限编程
September_ning6 小时前
React.lazy() 懒加载
前端·react.js·前端框架
web行路人6 小时前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
番茄小酱0016 小时前
Expo|ReactNative 中实现扫描二维码功能
javascript·react native·react.js
逆天的蝈蝈8 小时前
开源与商业的碰撞TPFLOW与Gadmin低代码的商业合作
低代码·开源
勤研科技8 小时前
低代码环境中的领域与根实体解析
低代码