界面服务
iBizHUB从数据流维度可清晰地划分为界面层、界面服务层和数据服务层三个核心层级。iBizHUB界面服务作为核心中间层,封装了部件服务、代码表服务、计数器服务、消息通知服务等可复用的前端业务能力模块,向上通过标准接口为界面层提供功能支撑,使得界面层可以专注于交互呈现而无需关心复杂业务逻辑。向下则通过统一的数据访问规范与数据服务层进行通信,有效解耦前端交互与后端数据处理。
部件服务
部件服务作为界面组件与数据服务之间的桥梁,其核心价值在于为各类界面部件提供标准化的业务能力封装。该服务不仅实现了界面部件与底层数据的解耦,更重要的是通过预置的业务逻辑为不同形态的部件组件提供开箱即用的功能支持。
以编辑表单场景为例,部件服务内置了完整的增删改查(CRUD)能力,使得表单组件只需通过简单的服务调用即可实现复杂的数据操作,而无需关注底层实现细节。在数据转换方面,部件服务承担了界面数据与实体数据之间的双向映射职责,例如树部件服务能够自动将标准的实体数据转换为树节点数据,同时保持数据语义的完整性和一致性。
代码表服务
代码表,即数字字典。代码表服务专门承担为UI界面供数及数据转化的功能,内部包含代码表取数逻辑、数据缓存等功能。如果代码项与代码项之间具有父子关系,代码表服务会将数据处理为树型数据。
在iBizHUB中代码表主要分为静态代码表和动态代码表两类:
| 类型 | 说明 |
|---|---|
| 静态代码表 | 代码项值直接在可视化配置工具ModelingIDE创建即可,代码表数据存放在模型JSON中 |
| 动态代码表 | 动态代码表和应用实体绑定,代码项值可通过ModelingIDE建模配置和实体数据映射,代码表数据存放在数据库中 |
// 获取应用实例
const app = ibiz.hub.getApp(this.context.srfappid);
// 获取指定代码表所有代码表项
const items = await app.codeList.get(
codeListId, // 代码表标识
this.context, // 上下文
this.params, // 视图参数
)
// 获取代码表模型
const codeList = app.codeList.getCodeList(codeListId);
// 获取指定代码表指定值对应的代码表项
const item = app.codeList.getItem(codeListId, value, this.context, this.params);动态代码表
动态代码表会请求后台数据,为了避免重复请求的问题,动态代码表内置了缓存机制(默认缓存60分钟)。
在iBizHUB中预置如下动态代码表:
| 代码表预置类型 | 说明 |
|---|---|
| OPERATOR | 系统操作者 |
| RUNTIME | 运行时代码表 |
| MODULEINST | 模块副本 |
| DEMAINSTATE | 实体主状态 |
动态代码表便通常都与实体数据绑定,当实体数据变更时,需及时通知外部组件。iBiz在核心包@ibiz-template/vue3-util中提供了监听代码表变更的工具方法:
/**
* 监听指定代码表数据变更
*
* @param {(string | undefined)} appCodeListId 代码表标识
* @param {string} srfappid 应用标识
* @param {((data: CodeListItem[] | undefined) => void)} fn 回调
*/
function useCodeListListen(
appCodeListId: string | undefined,
srfappid: string,
fn: (data: CodeListItem[] | undefined) => void,
): void计数器服务
计数器服务服务于界面中某些具体项的计数徽标显示,比如菜单,工具栏、树等。视图在初始化时会构建出计数器服务,当调用计数器服务时会传入当前绑定计数器项标识获取到计数数量并显示到页面。
// 获取计数器引用对象
const counter = await CounterService.getCounterByRef(
appCounterRef, // 计数器模型
this.context, // 上下文
this.params, // 视图参数
);
// 界面使用(计数器数据在data中)
<div>{{counter.data.count}}</div>
// 监听计数器改变
counter.onChange((cunter: object) => {}, true)
// 取消监听
counter.offChange((cunter: object) => {});消息通知服务
iBizHUB内置有界面消息中心,可以发送前端消息并接收前端和后端消息,为应用提供消息通知。消息类型分为两大类:日志消息和命令消息。
命令消息包含以下几种类型:
| 消息子类型 | 说明 | 场景 |
|---|---|---|
| MARKOPENDATA | 标注打开数据 | - 发送用户打开视图通知 - 发送用户更新数据通知 - 发送用户编辑数据通知 - 发送用户关闭视图通知 - 展示协同编辑人员信息 |
| ASYNCACTION | 异步作业 | - 异步界面行为 - 数据导入 |
| INTERNALMESSAGE | 站内信 | - 系统用户通知 |
| OBJECTUPDATED | 数据更新 | - 前端实体级通知,刷新页面 |
| OBJECTREMOVED | 数据删除 | - 前端实体级通知,刷新页面 |
| OBJECTCREATED | 数据创建 | - 前端实体级通知,刷新页面 |
| ADDINCHANGED | 添加更改 | - 外挂插件操作通知 |
// 日志消息
ibiz.mc.console.send(msg); // 发送消息
ibiz.mc.console.on(()= > {}); // 监听消息
ibiz.mc.console.off(()= > {}); // 取消监听
// 新建数据指令消息
// msg:需为实体数据
// meta: { triggerKey?: string } 触发源的key,防止触发源页面刷新
ibiz.mc.command.create.send(msg, meta); // 发送消息
ibiz.mc.command.create.on(()= > {}); // 监听消息
ibiz.mc.command.create.off(()= > {}); // 取消监听
// 更新数据指令消息
// msg:需为实体数据
// meta: { triggerKey?: string } 触发源的key,防止触发源页面刷新
ibiz.mc.command.update.send(msg, meta); // 发送消息
ibiz.mc.command.update.on(()= > {}); // 监听消息
ibiz.mc.command.update.off(()= > {}); // 取消监听
// 删除数据指令消息
// msg:需为实体数据
// meta: { triggerKey?: string } 触发源的key,防止触发源页面刷新
ibiz.mc.command.remove.send(msg, meta); // 发送消息
ibiz.mc.command.remove.on(()= > {}); // 监听消息
ibiz.mc.command.remove.off(()= > {}); // 取消监听
// 异步指令消息
ibiz.mc.command.asyncAction.send(msg); // 发送消息
ibiz.mc.command.asyncAction.on(()= > {}); // 监听消息
ibiz.mc.command.asyncAction.off(()= > {}); // 取消监听
// 站内信指令消息
// msg:必须包含 content_type 和 content
// 系统会根据不同的 content_type 使用不同的组件去绘制消息内容 content
ibiz.mc.command.internalMessage.send(msg); // 发送消息
ibiz.mc.command.internalMessage.on(()= > {}); // 监听消息
ibiz.mc.command.internalMessage.off(()= > {}); // 取消监听
// 标注打开数据指令消息
// msg: 必须包含 action,entity,key
// 系统会根据不同的 action 显示不同的协同编辑信息
ibiz.mc.command.markOpenData.send(msg); // 发送消息
ibiz.mc.command.markOpenData.on(()= > {}); // 监听消息
ibiz.mc.command.markOpenData.off(()= > {}); // 取消监听
// 添加更改指令消息
// msg: 必须包含 title,content 以便界面展示
ibiz.mc.command.addInChanged.send(msg); // 发送消息
ibiz.mc.command.markOpenData.on(()= > {}); // 监听消息
ibiz.mc.command.markOpenData.off(()= > {}); // 取消监听
// 自定义指令消息
// msg: 必须包含 subtype 以便系统对指令消息进行分发
ibiz.mc.command.next(msg); // 发送消息
ibiz.mc.command.on(()= > {}); // 监听消息
ibiz.mc.command.off(()= > {}); // 取消监听应用功能组件服务
应用功能组件服务主要针对界面初始化时加载运行时动态设计模型数据和界面设计完成保存动态设计模型数据两部分内容。
// 获取应用实例
const app = ibiz.hub.getApp(this.context.srfappid);
// 获取指定应用功能模型
const appUtilModel = app.getAppUtil(`${UtilId}`);
// 初始化应用功能服务
const service = new UtilService(appUtilModel);
// 加载指定服务数据
service.load(tag, context, params);
// 保存指定服务数据
service.save(tag, context, params, data);预置应用功能组件服务:
| 应用场景 | 标识 | 说明 |
|---|---|---|
| 菜单 | DYNAMENU | 用于存储自定义菜单的模型数据 |
| 应用数据看板 | 动态看板功能标识 | 用于存储自定义数据看板的模型数据 |
应用配置存储服务
该服务主要为用户提供自定义的数据存储服务。
// 初始化应用配置存储服务
// folder:存储目录
// tag: 存储标记
const service = new ConfigService(this.context.srfappid, folder, tag);
// 加载数据
service.load();
// 保存数据
service.save(data);
// 重置数据
service.reset();预置应用配置存储服务:
| 应用场景 | 标识 | 说明 |
|---|---|---|
| 应用 | 存储目录:PSSysApp存储标记: ${srfappid} | 用于存储应用级的数据 |
| 实体数据服务 | 存储目录:PSAppDataEntity存储标记: ${appDataEntityId} | 用于存储实体级的数据 |
| 应用菜单 | 存储目录:menu存储标记: menu_${view.name.toLowerCase()}_${ctrl.codeName?.toLowerCase()} | 当应用没有配置标识为DYNAMENU的应用功能组件服务时,用于存储自定义菜单的模型数据 |
| 应用数据看板 | 存储目录:dynadashboard存储标记: dynadashboard_${appDataEntityId?.toLowerCase() || 'app'}_${ctrl.codeName?.toLowerCase()} | 当应用数据看板没有绑定应用功能组件服务时,用于存储自定义数据看板的模型数据 |
| 搜索表单 | 存储目录:dynafilter存储标记: searchform_${appDataEntityId?.toLowerCase() || 'app'}_${ctrl.codeName?.toLowerCase()} | 用于存储过滤条件数据 |