在设计插件视图时,初衷是为了自定义展示工作表内的数据。尽管插件功能强大,但由于可供获取动态数据的接口仅限于少数几个与工作表相关的 API,这在一定程度上限制了插件的应用范围,使其作用主要集中在视图展示上。
在上一个版本中,我们大幅扩展了插件可以调用的接口数量(文档)使得插件能够在用户的权限范围内获取与其关联的任何应用的数据。这样一来,插件的功能性和灵活性得到了显著增强。以下面这个标签生成工具为例,具体说明这一变化带来的可能性。
这个工具允许用户选择其网络内可见的应用和工作表。用户设计好标签后,可以将标签内的文字映射到相应的工作表字段。点击打印时,工具会获取指定表内的记录,并将数据渲染成标签,生成 PDF 文件。设计完成的模板可以保存,后续用户可以直接从模板列表中选择记录进行打印。
这个插件开发的过程与之前相比没有变化,主要的区别在于可调用的接口增加了。不同之处在于表对于插件的角色转变。视图插件表是内容的载体,而插件仅仅是内容的一种展示方式,但这里表则变成了插件的数据库,是为插件服务的。
使用工作表作为插件数据库具体做法是在工作表中创建两个文本字段:一个是 key
,另一个是 value
。
字段定义:
key
字段用于唯一标识每一条记录。value
字段用来存储实际的数据内容,比如模板的具体配置或者信息。
存储模板列表:
- 当需要保存一个新的模板时,向工作表中添加一条新的记录。
key
的格式设定为"label-template-$id"
,其中$id
是一个唯一的标识符,可以是自增编号或者是其他能够确保唯一性的字符串。value
中则存放该模板的实际内容或配置信息。
检索模板列表:
- 为了获取所有的模板列表,使用筛选器条件“开头是”并设置筛选值为
"label-template-"
。这样可以直接列出所有以 key 以 "label-template-" 开头的记录。 - 例如,如果要获取某个特定模板的信息,可以根据具体的 key 设置筛选条件中的文本等于条件来查找对应的
value
。
假设你想要保存一个标签模板,并且这个模板的 ID 是 12345。那么:
- 在新增记录时,
key
将被设置为"label-template-12345"
。 value
字段将包含该模板的所有详细信息,如布局、样式等。
当你需要列出所有模板时,只需设置筛选条件让 key
“开头是” "label-template-"
即可得到所有相关的记录。
这种方法不仅使得数据管理变得简单直观,而且利用现有的工作表功能就能轻松实现复杂的数据查询和处理需求。
模板的 CURD 方法:
const { worksheetId } = config;
const keyControlId = env.key[0];
const valueControlId = env.value[0];
export function getLabelTemplates() {
return apis.worksheet
.getFilterRows({
worksheetId,
filterControls: [
{
spliceType: 1,
isGroup: true,
groupFilters: [
{
controlId: keyControlId,
dataType: 2,
spliceType: 1,
filterType: 3,
dateRange: 0,
dateRangeType: 1,
isDynamicsource: false,
dynamicSource: [],
values: ["label-template-"],
},
],
},
],
})
.then((res) => {
const rows = res.data;
return rows.map((row) => ({
rowId: row.rowid,
...JSON.parse(row[valueControlId]),
}));
});
}
export function createLabelTemplate(data) {
return apis.worksheet.addWorksheetRow({
worksheetId,
receiveControls: [
{
controlId: keyControlId,
type: 2,
value: "label-template-" + data.id,
controlName: "key",
dot: 0,
},
{
controlId: valueControlId,
type: 2,
value: JSON.stringify(data),
controlName: "value",
dot: 0,
},
],
});
}
export function updateLabelTemplate(rowId, data) {
return apis.worksheet.updateWorksheetRow({
worksheetId,
rowId,
newOldControl: [
{
controlId: valueControlId,
type: 2,
value: JSON.stringify(data),
},
],
});
}
export function deleteLabelTemplate(id) {
return apis.worksheet.deleteWorksheetRows({
worksheetId,
rowId: id,
});
}
这样是否有数据泄露的风险? 这样不会增加数据泄露的风险,因为插件是以当前用户的身份调用接口,只能访问该用户有权限的数据。这意味着用户在主站看不到的数据,在插件中也无法访问,权限控制与主站保持一致。
利用这些特性,用户无需对我们的系统进行二次开发,就可以创建自己专属的平台工具。
今年的伙伴大会我们新增了"伙伴集市"这种新的互动方式,届时会有一个"HAP 插件与二次开发"摊位。对上面插件感兴趣的同学,可以来到现场体验。如果您是开发者,欢迎来我们的摊位交流,告诉我们插件目前存在哪些问题,以及您希望添加哪些功能。即便您不是开发者,我们也欢迎您前来分享,告诉我们您希望通过插件实现什么功能,这将帮助我们制定未来插件的设计方向。