【阿里低代码引擎实战】— 自定义插件-多页面管理(二)

【阿里低代码引擎实战】--- 自定义插件-多页面管理(二)

本文正在参加阿里低代码引擎征文活动

上一篇笔记简单实现了一个多页面管理,页面数据通过调接口来获取,后端项目使用 egg.js 搭建,上篇指路:juejin.cn/post/734457...

这篇我们在上一篇的基础上,使用低代码引擎demo拖拉拽生成自已的页面,通过调接口将不同页面的schema数据保存在 mysql 数据库中,并且根据不同页面路由回显相对应的页面数据。

本篇代码github地址:github.com/JoeXu727/al...

github.com/JoeXu727/lo...

一. 新建数据库表

  1. 安装 MySQLnavicat 的过程不做赘述,本文使用 MySQL8.0版本;

  2. 新建数据库表 lowcodepage_schema 字段用于存储页面schema,page_type 用于存储页面类型,延续上一篇,页面有两种类型(home 和 user),并且 page_type 还可以直接作为该表的主键;

  1. 直接在表里新增两条数据,如图:

二. 在eggjs项目中操作数据库

egg官方文档:www.eggjs.org/zh-CN/tutor...

  1. egg.js 项目使用mysql8.0,首先安装 egg-mysql

    css 复制代码
    $ cnpm i --save egg-mysql

    分别在 plugin.js 和 config.default.js 添加如下代码:

    java 复制代码
    plugin.js
    ​
    module.exports = {
      mysql: {
        enable: true,
        package: "egg-mysql",
      },
    };
    arduino 复制代码
    config.default.js
    ​
    module.exports = (appInfo) => {
      // mysql数据库配置
      config.mysql = {
        // 单数据库信息配置
        client: {
          // host
          host: '127.0.0.1',
          // 端口号
          port: '3306',
          // 用户名
          user: 'root',
          // 密码
          password: '123456',
          // 数据库名
          database: 'lowcode',
        },
        // 是否加载到 app 上,默认开启
        app: true,
        // 是否加载到 agent 上,默认关闭
        agent: false,
      }
    }

    配置完成后,启动egg项目可能会遇到如下报错:nodejs.ER_NOT_SUPPORTED_AUTH_MODEError: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client;

    报错原因:登录数据库的客户端跟mysql8.0不兼容了,mysql8.0密码认证采用了新的密码格式;

    解决方法:登录数据库后输入如下命令,将your password改为你自己的密码:

    sql 复制代码
    mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your password';

    最后再输入以下命令,回车,现在就可以正常启动egg项目连接数据库了;

    ini 复制代码
    mysql> FLUSH PRIVILEGES;
  1. 接着开始写 controller 层的逻辑,新建 admin.js :

    csharp 复制代码
    controller/admin.js
    ​
    const { Controller } = require('egg');
    ​
    class AdminController extends Controller {
        // 查询页面schema
        async getSchema() {
            const { ctx } = this;
            const { page_type } = ctx.query;
            const result = await ctx.service.admin.getPageSchema(page_type);
            ctx.body = {
                status: 200,
                msg: '查询成功',
                data: result,
            };
        }
        // 保存页面schema
        async saveSchema() {
            const { ctx } = this;
            const params = ctx.request.body;
            const result = await ctx.service.admin.savePageSchema(params);
            if (result) {
                ctx.body = {
                    status: 200,
                    msg: '保存成功',
                    data: result,
                };
            } else {
                ctx.body = {
                    status: 201,
                    msg: '保存失败',
                    data: {},
                };
            }
        }
    ​
    }
    ​
    module.exports = AdminController;
  2. 加上admin对应的路由:

    ini 复制代码
    router.js
    ​
    module.exports = app => {
      const { router, controller } = app;
      router.get('/admin', controller.admin.getSchema);
      router.post('/admin', controller.admin.saveSchema);
    };
  3. 在 service 层新建 admin.js ,进行数据库操作:

    csharp 复制代码
    service/admin.js
    ​
    const Service = require('egg').Service;
    ​
    class AdminService extends Service {
    ​
        // 查询页面schema
        async getPageSchema(page_type) {
            try {
                const params = {
                    page_type
                };
                const result = await this.app.mysql.get('lowcode', params);
                return result;
            } catch (error) {
                console.log(error);
            }
        }
    ​
        // 保存页面schema
        async savePageSchema(params) {
            try {
                const row = {
                    page_schema: params.page_schema,
                };
                // 主键是自定义的page_type,需要在 `where` 里配置
                const options = {
                    where: {
                        page_type: params.page_type
                    }
                };
                const result = await this.app.mysql.update('lowcode', row, options);
                return result;
            } catch (error) {
                console.log(error);
            }
        }
    }
    ​
    module.exports = AdminService;
  4. 在postman中测试下查询和保存这两个接口:

    查询页面schema:

    保存页面schema:

三. lowcode-demo 项目

  1. 将项目里本来的 保存到本地 功能改为 保存,存入数据库中;在代码中修改按钮名称,并传入页面类型pageType:

    javascript 复制代码
    plugin-save-sample/index.tsx
    ​
    // 保存功能示例
    const SaveSamplePlugin = (ctx: IPublicModelPluginContext) => {
      return {
        async init() {
          const { skeleton, hotkey, config } = ctx;
          const scenarioName = config.get('scenarioName');
    ​
          const match = location.search.match(/?page=([^&#]+)/);
          const menuType = match ? match[1] : 'home';
          const pageType = menuType === 'home' ? 1 : 2;
    ​
          skeleton.add({
            name: 'saveSample',
            area: 'topArea',
            type: 'Widget',
            props: {
              align: 'right',
            },
            content: (
              <Button onClick={() => saveSchema(pageType)}>
                保存
              </Button>
            ),
          });
          ...
        },
      };
    }
  2. 修改 mockService 中的 saveSchema 方法,调接口保存在mysql中:

    php 复制代码
    mockService.ts
    ​
    export const saveSchema = async (page_type: number = 1) => {
      const schema = project.exportSchema();
      const url = 'http://127.0.0.1:7001/admin';
      const response = await fetch(url, {
        method: 'POST',
        mode: 'cors',
        cache: 'no-cache',
        credentials: 'same-origin',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          page_schema: JSON.stringify(schema),
          page_type: page_type,
        })
      });
      Message.success('成功保存页面schema');
    };
  3. 处理页面查询逻辑,注意从 project.exportSchema() 获取到的 schema 在使用的时候要用 schema.componentsTree[0]

    typescript 复制代码
    plugin-editor-init/index.tsx
    ​
    const EditorInitPlugin = (ctx: IPublicModelPluginContext, options: any) => {
      return {
        async init() {
          ...
    ​
          const match = location.search.match(/?page=([^&#]+)/);
          const menuType = match ? match[1] : 'home';
          const pageType = menuType === 'home' ? 1 : 2;
          const schema = await getProjectSchema(pageType, scenarioName);
          // 加载 schema
          project.importSchema(schema as any);
        },
      };
    };
    ini 复制代码
    mockService.ts
    ​
    export const getProjectSchema = async (
      pageType: number = 1,
      scenarioName: string = 'unknown',
    ): Promise<IPublicTypeProjectSchema> => {
      const pageSchema = await getPageSchema(pageType, scenarioName);
      return generateProjectSchema(pageSchema, DefaultI18nSchema);
    };
    ​
    export const getPageSchema = async (
      pageType: number = 1,
      scenarioName: string = 'unknown',
    ) => {
      let pageSchema;
      let url = `http://127.0.0.1:7001/admin?page_type=${pageType}`;
      pageSchema = await fetchData(url).then((res) => {
        let schema = JSON.parse(res.data.page_schema)
        return schema.componentsTree[0];
      });
    ​
      if (pageSchema) {
        return pageSchema;
      }
    };

四. 结果演示

在demo中随意搭建一个home页面,点击右上角保存后刷新页面,查看页面是否保存成功:

左侧菜单切换到user页面,再搭建一个,点击保存:

切换菜单,正确展示出对应页面,大功告成~

==========================================================

以上为个人工作学习笔记总结,供学习参考交流,未经允许禁止转载或商用。

个人博客地址:joexu727.github.io/

相关推荐
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang2 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、5 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
郝晨妤6 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui
喝旺仔la6 小时前
vue的样式知识点
前端·javascript·vue.js
别忘了微笑_cuicui6 小时前
elementUI中2个日期组件实现开始时间、结束时间(禁用日期面板、控制开始时间不能超过结束时间的时分秒)实现方案
前端·javascript·elementui