Skip to main content
Version: 1.x

独立使用UI

背景

项目没那么复杂,不需要使用 BFF,去掉 BFF 层

改造

1. 配置 config.ts

首先配置 app/config/config.ts 的 base 地址,根据环境是 development 或者是 production 进行判断

isDev = process.env.NODE_ENV === 'development';
base: isDev ? 'http://127.0.0.1:8889' : '';

2. 配置 layout

新增配置文件 app/layouts/index.ts,需要注意的是路径和文件名不可以自定义。

开发环境时,提供两种获取数据的方式,有两种设计方案,分别是:

方案一,一般是服务端没有提供接口,也没有提供接口文档的情况下,直接使用 Promise.resolve() 返回定义的数据;

方案二,当使用 API 调用请求方法时,可分为两种场景:一种已经提供了接口文档,但没有提供接口;另一种是已经提供接口或者是两者都提供了

具体案例如下:

  • 方案一 使用方案一时不会依赖 mock 服务,开发人员使用 Promise.resolve() 返回按照约定的自定义的数据,以完成一些简单的功能。
import defaultLayouts from '@/containers/defaultLayouts';
import { cloneDeep } from 'lodash';
import { Util } from '@gza/quantex-utils';

// 这里需要先深拷贝一份配置
const layouts = cloneDeep(defaultLayouts);

/*
* 假设需要登录 GZA UI 系统,可以使用以下数据格式,所有字段不可更改:
* {
* code: "用户编码",
* name: "用户名",
* token : token
* }
*/

layouts.login.login = async (params) => {
params.loginPassword = Util.sha256Encode(params.loginPassword);
return Promise.resolve({
code: 200,
data: {
code: 'test',
name: 'test',
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6I...6MTU4NzQzNTc2NX0.I5McYxR4y0luSTWeaFGDmV',
},
msg: '操作成功!',
});
};

// 此处只做覆盖,不做任何逻辑
layouts.login.logout = async () => {
return Promise.resolve();
};

// 此处只做覆盖,不做任何逻辑
layouts.login.getMicroApp = () => {
return Promise.resolve({ code: 200, data: { list: [] } });
};

/*
* GZA UI 系统菜单数据,可以使用以下格式,所有字段不可更改:
* 若是一级菜单需要按照以下格式,且父子菜单ID需要一致:
* {
* id: 子菜单ID,
* pId: 父菜单ID,
* icon: 菜单图标, (一级菜单需要)
* appId: APP ID,
* name: 菜单名称
* }
* 若不是是一级菜单需要按照以下格式:
* {
* id: 子菜单ID,
* pId: 父菜单ID,
* appId: APP ID,
* name: 菜单名称
* url: 菜单地址, (子菜单需要,appId/路径,路径是相对于 app/pages 的路径)
* }
*/

layouts.main.getUserMenu = () => {
return Promise.resolve({
code: 200,
data: {
list: [
{
id: 10,
pId: 10,
icon: 'chanpinguanli',
appId: 'portal',
name: '应用管理',
},
{
id: 11,
pId: 10,
appId: 'portal',
name: '应用管理',
url: 'portal/system/Application',
},
{
id: 12,
pId: 10,
appId: 'portal',
name: '菜单管理',
url: 'portal/system/Menu',
},
],
},
msg: '操作成功!',
});
};

export default layouts;
  • 方案二 使用 Util 工具库封装的 API 功能实现接口请求功能,使用方案二的场景有两种,分别是: 场景一,假设只提供了接口文档,未提供接口,开发人员可以依赖 mock 服务,实现接口功能,在本地按照约定创建数据。 场景二,假设已经提供接口或者是两者都提供,此时不需要依赖 mock 服务,直接从后端获取数据。

    有两点需要注意: 一是两种场景的使用方式是一样的,因此以下只以一种场景做演示; 二是 mock 服务的优先级比后台优先级高,在使用重名接口的调用时 mock 优先访问,所以当使用场景二的时候,需要将 app/pages/_mock.(js|ts) 文件删除

假设开发人员的使用场景是场景一,那在开发之前需要在 app/pages 目录先建立 _mock.(ts|js) 文件,并添加接口数据,若是场景二,可直接跳过这一步。按照约定数据格式如下:

// app/pages/_mock.js
module.exports = {
'POST /auth/api/users/login': {
code: 200,
data: {
code: 'a',
roleCodes: 'admin',
loginTime: 1587435765100,
loginName: 'a',
name: 'a',
roleNames: '超级管理员',
exp: 1587522165,
token: 'eyJhbGciOiLo...uSTWeaFGDmVLEh8mIramo7HlWPwiWtgI',
},
msg: '操作成功!',
},
'PUT /auth/api/users/logout': {
code: 200,
data: {},
msg: '退出成功!',
},
'GET /auth/api/users/:code/menus': {
code: 200,
data: {
list: [
{
id: 10,
pId: 10,
icon: 'chanpinguanli',
appId: 'portal',
name: '菜单名称',
},
{
id: 11,
pId: 10,
appId: 'portal',
name: '应用管理',
url: 'portal/system/Application',
},
{
id: 12,
pId: 10,
appId: 'portal',
name: '菜单管理',
url: 'portal/system/Menu',
},
],
},
msg: '操作成功!',
},
};
菜单规则:
1. 设置一级菜单时,id 和 pId 需设置一致,且数值唯一。
2. 设置 icon 时,是一级菜单需提供 icon 值,反之不设值。
3. 设置 url 时,不是一级菜单需提供 url 值(格式 appID/路径,路径是相对于 app/pages 目录,如: portal/system/ServiceProxy ),反之不设值。
4. 设置 appId 时,值必须和 app/config/config.ts 文件的属性 APP_ID 的值一致,且不可以设置为关键字 portal。

两种场景的代码格式是一样的,因此这里不做区分。

import defaultLayouts from '@/containers/defaultLayouts';
import { cloneDeep } from 'lodash';
import { Util, API } from '@gza/quantex-utils';
import appWindow from '@/common/appWindow';

// 这里需要先深拷贝一份配置
const layouts = cloneDeep(defaultLayouts);

// 两种场景直接使用 Util 工具库的 API 类生成一个实例,根据接口的请求类型调用对应请求方法即可获取到数据
// 比如 /auth/api/users/login 是一个 post 方法,直接使用 new API('auth').post('/api/users/login',params) 即可实现功能
// 场景一时,API 会获取本地的 mock 数据。场景二时,API获取后端数据。 但要注意,使用场景二的时候一定要删除 app/pages 下的 _mock.(ts|js) 文件
layouts.login.login = async (params) => {
params.loginPassword = Util.sha256Encode(params.loginPassword);
return new API('auth').post('/api/users/login', params);
};

layouts.login.logout = async () => {
return new API('auth').put('/api/users/logout');
};

// 此处只做覆盖,不做任何逻辑
layouts.login.getMicroApp = () => {
return Promise.resolve({ code: 200, data: { list: [] } });
};

layouts.main.getUserMenu = () => {
const userInfo = appWindow.userLocalStore.getItem('userInfo');
return new API('auth').get('/api/users/{code}/menus', {
code: userInfo.code,
});
};