跳到主要内容

Soln SDK

当 Studio 脚本需要查询或写入记录、读取表单元数据、创建文件资产、查询组织目录数据、处理审批运行时数据,或从已挂载的工作空间应用发送消息时,可以使用 studioScriptContext。

这组 SDK 可用于按钮设计、布局设计、审批服务调用、集成流程等位置配置的 Studio 脚本。

基础用法​

export default async function main(payload: StudioScriptRuntimeContextPayload, context: StudioScriptContext) {
const created = await context.form.create({
formApiName: 'orders',
title: 'SO-1001',
data: {
orderNo: 'SO-1001',
amount: 1200,
},
});

return {
ok: true,
recordId: created.id,
};
}

payload 始终使用 soln.runtime-context/v1,调用方传入的值位于 payload.input。每个远程 SDK 方法都以一个对象承载文档声明的输入;输入标记为可选的方法可以不传参数。禁止使用位置参数或多个参数。面向表单的 API 使用 formApiName,面向已有记录的 API 使用 recordId;例如更新记录应调用 context.form.update({ recordId, data })。脚本中不要硬编码表单 ID。

SDK 返回会按表单字段元数据格式化表单数据:date 字段返回 YYYY-MM-DD,datetime 字段返回 YYYY-MM-DD HH:mm:ss。

所有需要分页的 SDK 方法只使用游标分页。首次请求省略 cursor,下一次请求传入上一次返回的 nextCursor,并保持其他查询条件和 limit 不变。旧的 page、pageSize 参数不再接受。当 hasMore 为 false 且 nextCursor 为 null 时,表示已经读取完毕。

Client​

interface StudioScriptContext {
runtime: StudioScriptRuntimeInfo;
logger: StudioScriptLogger;
http: StudioScriptHttpClient;
file: StudioScriptFileClient;
form: StudioScriptFormClient;
formSavedFilter: StudioScriptFormSavedFilterClient;
formSchema: StudioScriptFormSchemaClient;
formTableView: StudioScriptFormTableViewClient;
approval: StudioScriptApprovalClient;
organization: StudioScriptOrganizationClient;
department: StudioScriptDepartmentClient;
member: StudioScriptMemberClient;
iam: StudioScriptIamClient;
}

type StudioScriptRuntimeInfo = {
tenantId: string;
assetId: string;
assetCode: string;
workspaceAppCode: string | null;
executionId: string;
startedAt: string;
traceId: string;
};

type StudioScriptLogger = {
log: (...args: unknown[]) => void;
info: (...args: unknown[]) => void;
warn: (...args: unknown[]) => void;
error: (...args: unknown[]) => void;
debug: (...args: unknown[]) => void;
};

interface StudioScriptHttpClient {
request(input: StudioScriptHttpRequestInput): Promise<StudioScriptHttpResponse>;
requestJson<TData = unknown>(input: StudioScriptHttpRequestInput): Promise<StudioScriptHttpJsonResponse<TData>>;
}

interface StudioScriptFormClient {
list(input: StudioScriptFormListInput): Promise<StudioScriptFormRecordList>;
find(input: StudioScriptFormFindInput): Promise<StudioScriptFormRecord | null>;
get(input: { recordId: string }): Promise<StudioScriptFormRecord | null>;
batchGet(input: { recordIds: string[] }): Promise<StudioScriptFormBatchGetResult>;
create(input: StudioScriptFormCreateInput): Promise<StudioScriptFormRecord | StudioScriptFormCreateResult>;
createWithChildTables(input: StudioScriptFormCreateWithChildTablesInput): Promise<StudioScriptFormCreateWithChildTablesResult>;
batchCreate(input: StudioScriptFormBatchCreateInput): Promise<StudioScriptFormBatchCreateResult>;
batchCreateWithChildTables(input: StudioScriptFormBatchCreateWithChildTablesInput): Promise<StudioScriptFormBatchCreateWithChildTablesResult>;
batchUpdate(input: StudioScriptFormBatchUpdateInput): Promise<StudioScriptFormBatchUpdateResult>;
updateWithChildTables(input: StudioScriptFormUpdateWithChildTablesInput): Promise<StudioScriptFormUpdateWithChildTablesResult | null>;
batchUpdateWithChildTables(input: StudioScriptFormBatchUpdateWithChildTablesInput): Promise<StudioScriptFormBatchUpdateWithChildTablesResult>;
update(input: StudioScriptFormUpdateInput): Promise<StudioScriptFormRecord | null>;
trash(input: StudioScriptFormDeleteInput): Promise<{ trashed: boolean }>;
batchTrash(input: StudioScriptFormBatchDeleteInput): Promise<StudioScriptFormBatchTrashResult>;
restore(input: StudioScriptFormRestoreInput): Promise<StudioScriptFormRecord | null>;
batchDelete(input: StudioScriptFormBatchDeleteInput): Promise<StudioScriptFormBatchDeleteResult>;
delete(input: StudioScriptFormDeleteInput): Promise<{ deleted: boolean }>;
}

interface StudioScriptFormSavedFilterClient {
list(input: { formApiName: string }): Promise<{ items: StudioScriptFormSavedFilter[] }>;
save(input: { formApiName: string; id?: string | null; name: string; condition: Record<string, unknown> }): Promise<StudioScriptFormSavedFilter>;
delete(input: { filterId: string }): Promise<{ id: string }>;
}

interface StudioScriptFormTableViewClient {
list(input: { formApiName: string }): Promise<{ items: StudioScriptFormTableView[] }>;
save(input: { formApiName: string; id?: string | null; name: string; layoutIds?: string[] | null; groupFieldIds?: string[] | null; scopes?: string[] | null; bordered?: boolean | null; showRowNumber?: boolean | null; groups?: StudioScriptFormTableViewGroup[] | null }): Promise<StudioScriptFormTableView>;
delete(input: { viewId: string }): Promise<{ id: string }>;
}

interface StudioScriptFormSavedFilter {
id: string;
tenantId: string;
formId: string;
ownerType: string;
ownerId: string;
name: string;
condition: unknown;
sortOrder: number;
createdAt: string;
updatedAt: string;
}

interface StudioScriptFormTableViewGroup {
id: string;
name: string;
fieldIds: string[];
level: 1 | 2 | 3;
parentId: string | null;
}

interface StudioScriptFormTableView {
id: string;
tenantId: string;
formId: string;
ownerType: string;
ownerId: string;
name: string;
layoutIds: string[];
groupFieldIds: string[];
scopes: string[];
bordered: boolean;
showRowNumber: boolean;
groups: StudioScriptFormTableViewGroup[];
sortOrder: number;
createdAt: string;
updatedAt: string;
}

Context Client:

Client类型说明
runtimeStudioScriptRuntimeInfo当前执行元数据,包括租户、资产、已校验的工作空间应用、执行和 trace ID
loggerStudioScriptLogger写入 Studio 运行日志
httpStudioScriptHttpClient在服务端 Studio runtime 中发起外部 HTTP 请求
fileStudioScriptFileClient解析和创建文件资产
formStudioScriptFormClient查询和写入表单记录
formSavedFilterStudioScriptFormSavedFilterClient查询和管理表单保存筛选器
formSchemaStudioScriptFormSchemaClient查询表单和字段元数据
formTableViewStudioScriptFormTableViewClient查询和管理表单表格视图
approvalStudioScriptApprovalClient提交记录审批,并处理审批运行时数据
organizationStudioScriptOrganizationClient查询组织记录和组织树
departmentStudioScriptDepartmentClient查询部门数据和部门树
memberStudioScriptMemberClient查询成员数据
iamStudioScriptIamClient查询当前成员或指定成员的角色摘要

表单 Client 方法:

方法入参返回值说明
listStudioScriptFormListInputStudioScriptFormRecordList按条件批量获取记录
findStudioScriptFormFindInputStudioScriptFormRecord | null单条记录查询:按条件返回第一条匹配记录
get{ recordId: string }StudioScriptFormRecord | null按记录 ID 查询一条记录
batchGet{ recordIds: string[] }{ items: StudioScriptFormRecord[]; total: number }按记录 ID 批量查询记录
createStudioScriptFormCreateInputStudioScriptFormRecord | StudioScriptFormCreateResult新建一条表单记录,可选提交审批
createWithChildTablesStudioScriptFormCreateWithChildTablesInputStudioScriptFormCreateWithChildTablesResult在一个事务中创建一条主表记录和明细表记录
batchCreateStudioScriptFormBatchCreateInputStudioScriptFormBatchCreateResult在一个事务中创建多条表单记录
batchCreateWithChildTablesStudioScriptFormBatchCreateWithChildTablesInputStudioScriptFormBatchCreateWithChildTablesResult在一个事务中批量创建多条主表记录及各自的明细表记录
batchUpdateStudioScriptFormBatchUpdateInputStudioScriptFormBatchUpdateResult在一个事务中更新多条表单记录
updateWithChildTablesStudioScriptFormUpdateWithChildTablesInputStudioScriptFormUpdateWithChildTablesResult | null在一个事务中更新一条主表记录和明细表记录
batchUpdateWithChildTablesStudioScriptFormBatchUpdateWithChildTablesInputStudioScriptFormBatchUpdateWithChildTablesResult在一个事务中批量更新多条主表记录及各自的明细表记录
updateStudioScriptFormUpdateInputStudioScriptFormRecord | null更新一条表单记录
trashStudioScriptFormDeleteInput{ trashed: boolean }将一条表单记录移入回收站
batchTrashStudioScriptFormBatchDeleteInputStudioScriptFormBatchTrashResult将多条表单记录移入回收站
restoreStudioScriptFormRestoreInputStudioScriptFormRecord | null恢复一条回收站记录,并可在恢复时更新标题、数据和状态
batchDeleteStudioScriptFormBatchDeleteInputStudioScriptFormBatchDeleteResult永久删除多条表单记录
deleteStudioScriptFormDeleteInput{ deleted: boolean }永久删除一条表单记录

trash 是默认业务删除操作,会将记录移入回收站,通常可以通过产品流程恢复。delete 是硬删除,只应在脚本明确需要永久删除记录时使用。

保存筛选器和表格视图方法:

Client方法入参返回值说明
formSavedFilterlist{ formApiName: string }{ items: StudioScriptFormSavedFilter[] }查询一个表单的保存筛选器
formSavedFiltersave{ formApiName: string; id?: string; name: string; condition: object }StudioScriptFormSavedFilter新建或更新一个保存筛选器
formSavedFilterdelete{ filterId: string }{ id: string }删除一个保存筛选器
formTableViewlist{ formApiName: string }{ items: StudioScriptFormTableView[] }查询一个表单的表格视图
formTableViewsave{ formApiName: string; id?: string; name: string; layoutIds?; groupFieldIds?; scopes?; bordered?; showRowNumber?; groups? }StudioScriptFormTableView新建或更新一个表格视图;没有 columns 入参
formTableViewdelete{ viewId: string }{ id: string }删除一个表格视图

Runtime、Logger 与 HTTP​

使用 context.runtime 读取执行标识,使用 context.logger 写运行日志,使用 context.http 发起服务端外部请求。

export default async function main(payload: StudioScriptRuntimeContextPayload, context: StudioScriptContext) {
context.logger.info('execution', context.runtime.executionId);

const response = await context.http.requestJson({
url: 'https://example.com/api/orders',
method: 'POST',
json: payload,
timeoutMs: 10000,
retry: {
maxAttempts: 2,
},
});

return {
ok: response.ok,
status: response.status,
data: response.data,
traceId: context.runtime.traceId,
};
}

HTTP 请求入参:

type StudioScriptHttpRequestInput = {
url: string;
method?: string;
query?: Record<string, unknown>;
headers?: Record<string, unknown>;
json?: unknown;
body?: unknown;
timeoutMs?: number;
retry?: number | {
maxAttempts?: number;
baseDelayMs?: number;
maxDelayMs?: number;
factor?: number;
retryableStatusCodes?: number[];
};
expect?: 'json' | 'text';
throwOnHttpError?: boolean;
idempotency?: boolean | string | {
key?: string;
headerName?: string;
};
};

type StudioScriptHttpResponse = {
ok: boolean;
status: number;
code: string;
url: string;
method: string;
headers: Record<string, string>;
requestId: string;
traceId: string | null;
idempotencyKey: string | null;
durationMs: number;
attempts: number;
bodyText: string;
bodyJson: unknown;
};

type StudioScriptHttpJsonResponse<TData = unknown> = StudioScriptHttpResponse & {
data: TData | null;
};

requestJson 是便捷封装,会设置 expect: 'json',并把解析后的 JSON 响应放在 data。

Logger 方法按日志级别使用:

方法用途
context.logger.debug仅用于调试执行细节
context.logger.info / log记录正常执行阶段和关键标识
context.logger.warn记录可继续执行的异常状态
context.logger.error记录已经失败或即将返回失败的操作

不要记录密钥、Authorization Header、完整个人资料或文件内容。

HTTP 使用规则:

  • 服务端脚本使用 context.http,不要直接使用 fetch
  • 每次外部请求都设置有界的 timeoutMs
  • JSON 接口优先使用 requestJson;文本或自定义响应使用 request
  • 脚本需要自行处理 4xx/5xx 时设置 throwOnHttpError: false 并检查 response.ok
  • 会产生外部写入的请求使用稳定的 idempotency key;审批和自动化场景通常可以使用 context.runtime.traceId
  • 不在脚本中硬编码凭证;使用 OpenLink 集成系统配置外部鉴权

记录结构​

type StudioScriptFormRecord = {
id: string;
tenantId: string;
formId: string;
formName: string;
title: string;
data: Record<string, unknown>;
dataStatus: 'draft' | 'active' | 'archived' | 'trashed';
approvalStatus: 'none' | 'pending' | 'approved' | 'rejected' | 'returned' | 'canceled';
approvalFlowInstanceId: string | null;
createdAt: string;
updatedAt: string;
createdBy?: StudioScriptFormRecordPrincipal;
updatedBy?: StudioScriptFormRecordPrincipal;
};

type StudioScriptFormCreateResult = StudioScriptFormRecord & {
approval: {
queued: true;
submitted: false;
jobId: string;
action: 'create';
record: {
recordId: string;
formId: string;
};
};
};

type StudioScriptFormBatchCreateResult = {
items: Array<StudioScriptFormRecord | StudioScriptFormCreateResult>;
total: number;
};

type StudioScriptFormCreateWithChildTablesResult = {
record: StudioScriptFormRecord | StudioScriptFormCreateResult;
childTables: Array<{
childFormApiName: string;
items: Array<StudioScriptFormRecord | StudioScriptFormCreateResult>;
total: number;
}>;
};

type StudioScriptFormBatchCreateWithChildTablesResult = {
items: StudioScriptFormCreateWithChildTablesResult[];
total: number;
};

type StudioScriptFormRecordPrincipal = {
memberId?: string | null;
departmentId?: string | null;
organizationId?: string | null;
};

记录字段值在 data 中,key 为字段 API 名。

返回与失败行为​

表单 SDK 方法成功时会 resolve 为文档中的返回类型。业务错误、权限错误不会返回 { ok: false }。

方法成功返回空结果或目标不存在失败行为
listStudioScriptFormRecordListitems: [],hasMore: false,nextCursor: nullPromise reject
findStudioScriptFormRecordnullPromise reject
createStudioScriptFormRecord 或 StudioScriptFormCreateResult不适用Promise reject
createWithChildTablesStudioScriptFormCreateWithChildTablesResult不适用Promise reject
batchCreateStudioScriptFormBatchCreateResult不适用Promise reject
batchCreateWithChildTablesStudioScriptFormBatchCreateWithChildTablesResult不适用Promise reject
batchUpdateStudioScriptFormBatchUpdateResult不适用Promise reject
updateWithChildTablesStudioScriptFormUpdateWithChildTablesResult目标主记录不存在时返回 nullPromise reject
batchUpdateWithChildTablesStudioScriptFormBatchUpdateWithChildTablesResult不适用Promise reject
updateStudioScriptFormRecord目标记录不存在时返回 nullPromise reject
trash{ trashed: boolean }目标记录不存在时返回 { trashed: false }Promise reject
batchTrashStudioScriptFormBatchTrashResult不存在的目标记录会返回到 failed仅在入参非法或运行时级故障时 Promise reject
batchDeleteStudioScriptFormBatchDeleteResult不存在的目标记录会返回到 failed仅在入参非法或运行时级故障时 Promise reject
delete{ deleted: boolean }目标记录不存在时返回 { deleted: false }Promise reject

表单 SDK 调用失败时,会在脚本 worker 内抛出 Error。如果脚本没有捕获这个错误,整次脚本执行会失败,执行结果的 errorCode 为 STUDIO_ASSET_EXECUTION_FAILED,errorMessage 是底层错误信息,例如 IAM_PERMISSION_DENIED 或 FORMS_SCHEMA_NOT_FOUND。

如果脚本希望返回可控结构,需要自行 try/catch:

export default async function main(payload: StudioScriptRuntimeContextPayload, context: StudioScriptContext) {
try {
const record = await context.form.create({
formApiName: 'orders',
title: 'SO-1002',
data: {
orderNo: 'SO-1002',
},
});

return {
ok: true,
record,
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error.message : String(error),
};
}
}

记录查询​

查询第一条匹配记录​

const record = await context.form.find({
formApiName: 'orders',
sortFieldApiName: 'order_amount',
sortDirection: 'DESC',
condition: {
logic: 'and',
children: [
{
field: 'so_order_no',
operator: 'eq',
value: 'SO-1001',
},
],
},
});

需要按条件获取第一条匹配记录时,使用带条件入参的 find。它使用和 list 相同的过滤条件,并始终包含记录详细数据。

已经有记录 ID 时,使用 recordId 条件过滤:

const record = await context.form.find({
formApiName: 'orders',
condition: {
logic: 'and',
children: [
{
field: 'recordId',
operator: 'eq',
value: 'record-id',
},
],
},
});

条件查询入参:

type StudioScriptFormFindInput = Omit<
StudioScriptFormListInput,
'cursor' | 'limit' | 'includeDetail'
>;
const record = await context.form.find({
formApiName: 'orders',
condition: {
logic: 'and',
children: [
{
field: 'recordId',
operator: 'eq',
value: payload.record?.id,
},
],
},
});

已经有目标记录 ID 时,在 condition 中使用 field: 'recordId'。recordId 匹配记录主键 ID。

如果条件可能匹配多条记录,可以传入 sortFieldApiName 和 sortDirection 控制返回的第一条记录。排序支持 number、time、date、datetime、week、month、quarter、year 和 serial_number 字段。

参数:

参数类型必填说明
condition.children[].fieldstring是使用 recordId 按目标表单记录 ID 过滤
condition.children[].operator'eq' | 'in'是查询单条记录 ID 用 eq,多个记录 ID 可用 in
condition.children[].valuestring | string[]是目标表单记录 ID
sortFieldApiNamestring | null否返回第一条匹配记录前使用的排序字段 API 名
sortDirection'ASC' | 'DESC'否排序方向;默认 DESC

按条件批量获取记录​

const records = await context.form.list({
formApiName: 'orders',
limit: 20,
keyword: 'SO-1001',
includeDetail: true,
});

入参:

type StudioScriptFormListInput = {
formApiName: string;
cursor?: string | null;
limit?: number;
keyword?: string | null;
keywords?: string[] | null;
includeDetail?: boolean;
sortFieldApiName?: string | null;
sortDirection?: 'ASC' | 'DESC' | 'asc' | 'desc' | null;
searchFieldApiName?: string | null;
dataStatuses?: Array<'draft' | 'active' | 'archived' | 'trashed'>;
approvalStatuses?: Array<'none' | 'pending' | 'approved' | 'rejected' | 'returned' | 'canceled'>;
visibilityStates?: Array<{
dataStatus: 'draft' | 'active' | 'archived' | 'trashed';
approvalStatus: 'none' | 'pending' | 'approved' | 'rejected' | 'returned' | 'canceled';
}>;
condition?: StudioScriptFormConditionGroup | null;
};

参数:

参数类型必填说明
formApiNamestring是表单 API 名;运行时会解析为租户侧表单 ID
cursorstring | null否上一次调用返回的不透明游标 nextCursor;继续查询时其他条件必须保持不变
limitnumber否单次最多返回的记录数;默认 20,最大 200
keywordstring | null否单个搜索关键词
keywordsstring[] | null否多个搜索关键词
includeDetailboolean否列表记录是否包含详细数据;默认 false
sortFieldApiNamestring | null否排序字段 API 名;支持 number、time、date、datetime、week、month、quarter、year 和 serial_number 字段
sortDirection'ASC' | 'DESC'否排序方向;默认 DESC
searchFieldApiNamestring | null否作为关键词搜索目标的字段 API 名
dataStatusesArray<'draft' | 'active' | 'archived' | 'trashed'>否按记录数据状态过滤
approvalStatusesArray<'none' | 'pending' | 'approved' | 'rejected' | 'returned' | 'canceled'>否按审批状态过滤
visibilityStatesArray<object>否按数据状态和审批状态组合过滤
conditionStudioScriptFormConditionGroup | null否结构化字段条件

支持的操作符:

操作符含义
eq等于
neq不等于
contains包含
not_contains不包含
gt大于
gte大于等于
lt小于
lte小于等于
in在列表中
empty为空
not_empty不为空

返回:

type StudioScriptFormRecordList = {
items: StudioScriptFormRecord[];
limit: number;
projectionAsOf: string | null;
hasMore: boolean;
nextCursor: string | null;
};

type StudioScriptFormBatchGetResult = {
items: StudioScriptFormRecord[];
total: number;
};

按记录 ID 查询​

已经有记录 ID 时,直接使用 get,不要再通过 find 构造 recordId 条件:

const record = await context.form.get({
recordId: payload.record?.id || '',
});

if (!record) {
return { ok: false, message: 'Record not found.' };
}

get 返回完整记录或 null,并继续应用当前运行主体的表单、行和字段权限。

多个记录 ID 已知时使用 batchGet,单次最多 100 个 ID:

const result = await context.form.batchGet({
recordIds: selectedRecordIds,
});

return {
ok: true,
records: result.items,
total: result.total,
};

batchGet 只返回当前运行主体可读取的记录。不要假设返回数组与输入 ID 数组等长;需要建立对应关系时,应按返回记录的 id 建立 Map。

遍历全部游标分页​

需要读取全部匹配记录时,应逐页使用 nextCursor。每次请求必须保持 formApiName、筛选条件、排序和 limit 不变:

const items: StudioScriptFormRecord[] = [];
let cursor: string | null = null;

do {
const page = await context.form.list({
formApiName: 'orders',
cursor,
limit: 200,
includeDetail: true,
dataStatuses: ['active'],
sortFieldApiName: 'orderDate',
sortDirection: 'ASC',
});

items.push(...page.items);
cursor = page.hasMore ? page.nextCursor : null;
} while (cursor);

只在确实需要全部数据且数据量有明确上限时遍历所有页面。大批量同步应使用 OpenLink 分页流程或数据处理任务,避免让一个 Studio 脚本承担无界读取。

记录创建​

创建单条记录​

const record = await context.form.create({
formApiName: 'orders',
title: 'SO-1002',
data: {
orderNo: 'SO-1002',
status: 'draft',
},
submitApproval: true,
});

入参:

type StudioScriptFormCreateInput = {
formApiName: string;
title: string;
data: Record<string, unknown>;
buttonKey?: string | null;
submitApproval?: boolean;
};

参数:

参数类型必填说明
formApiNamestring是表单 API 名;运行时会解析为租户侧表单 ID
titlestring是记录标题,用于运行时列表和展示
dataRecord<string, unknown>是字段值,key 为字段 API 名;必须是对象
buttonKeystring | null否可选按钮 key,会传入运行时写入链路
submitApprovalboolean否为 true 时,在同一个事务中创建记录并写入审批提交任务

submitApproval 为 true 时,返回的记录会包含 approval 字段,其中有排队中的审批提交 jobId。后台审批提交任务使用 create 动作,审批运行时只会使用已发布且开启新建触发的审批定义。如果写入任务失败,SDK 调用会 reject,并回滚本次记录新建。

批量创建记录​

const result = await context.form.batchCreate({
formApiName: 'orders',
records: [
{
title: 'SO-1003',
data: {
orderNo: 'SO-1003',
status: 'draft',
},
},
{
title: 'SO-1004',
data: {
orderNo: 'SO-1004',
status: 'draft',
},
submitApproval: true,
},
],
});

入参:

type StudioScriptFormBatchCreateInput = {
formApiName: string;
records: Array<{
title: string;
data: Record<string, unknown>;
buttonKey?: string | null;
submitApproval?: boolean;
}>;
};

参数:

参数类型必填说明
formApiNamestring是表单 API 名;运行时会解析为租户侧表单 ID
recordsArray<object>是要创建的批次数据;每批次数据最少 1 条,最多 100 条
records[].titlestring是记录标题,用于运行时列表和展示
records[].dataRecord<string, unknown>是字段值,key 为字段 API 名;必须是对象
records[].buttonKeystring | null否可选按钮 key,会传入运行时写入链路
records[].submitApprovalboolean否为 true 时,会在同一个事务中为该记录写入审批提交任务

返回:

type StudioScriptFormBatchCreateResult = {
items: Array<StudioScriptFormRecord | StudioScriptFormCreateResult>;
total: number;
};

batchCreate 会在一个事务中创建全部记录。任意一条记录在校验、权限检查、自动编号、文件引用处理、公式计算、创建后任务写入或审批任务写入过程中失败时,SDK 调用会 reject,并回滚本批次的全部记录。

创建主子表记录​

const result = await context.form.createWithChildTables({
formApiName: 'orders',
title: 'SO-1005',
data: {
orderNo: 'SO-1005',
status: 'draft',
},
childTables: [
{
childFormApiName: 'order_items',
records: [
{
title: 'SO-1005-1',
data: {
productName: 'Keyboard',
quantity: 2,
},
},
{
title: 'SO-1005-2',
data: {
productName: 'Mouse',
quantity: 1,
},
},
],
},
],
});

入参:

type StudioScriptFormCreateWithChildTablesInput = {
formApiName: string;
title: string;
data: Record<string, unknown>;
buttonKey?: string | null;
submitApproval?: boolean;
childTables: Array<{
childFormApiName: string;
records: Array<{
title: string;
data: Record<string, unknown>;
buttonKey?: string | null;
submitApproval?: boolean;
}>;
}>;
};

参数:

参数类型必填说明
formApiNamestring是主表 API 名;运行时会解析为租户侧主表 ID
titlestring是主表记录标题,用于运行时列表和展示
dataRecord<string, unknown>是主表字段值,key 为字段 API 名;必须是对象
childTablesArray<object>是要创建的明细表批次数据;至少包含一个明细表
childTables[].childFormApiNamestring是明细表 API 名;必须是当前主表的明细表
childTables[].recordsArray<object>是明细表批次数据;每个明细表批次最少 1 条,最多 100 条
childTables[].records[].titlestring是明细表记录标题,用于运行时列表和展示
childTables[].records[].dataRecord<string, unknown>是明细表字段值,key 为字段 API 名;不要传主表关联字段;SDK 会自动填入创建后的主表记录 ID
childTables[].records[].buttonKeystring | null否可选按钮 key,会传入运行时写入链路
childTables[].records[].submitApprovalboolean否为 true 时,会在同一个事务中为该明细记录写入审批提交任务

返回:

type StudioScriptFormCreateWithChildTablesResult = {
record: StudioScriptFormRecord | StudioScriptFormCreateResult;
childTables: Array<{
childFormApiName: string;
items: Array<StudioScriptFormRecord | StudioScriptFormCreateResult>;
total: number;
}>;
};

createWithChildTables 会先创建主表记录,再把创建后的主表记录 ID 自动写入每条明细表记录的主表关联字段。整个操作在一个事务中执行。主表、明细表识别、任意明细记录、创建后任务写入或审批任务写入任一环节失败时,SDK 调用会 reject,并回滚整个操作。

批量创建主子表记录​

const result = await context.form.batchCreateWithChildTables({
formApiName: 'orders',
records: [
{
title: 'SO-1006',
data: {
orderNo: 'SO-1006',
status: 'draft',
},
childTables: [
{
childFormApiName: 'order_items',
records: [
{
title: 'SO-1006-1',
data: {
productName: 'Keyboard',
quantity: 2,
},
},
],
},
],
},
{
title: 'SO-1007',
data: {
orderNo: 'SO-1007',
status: 'draft',
},
childTables: [
{
childFormApiName: 'order_items',
records: [
{
title: 'SO-1007-1',
data: {
productName: 'Mouse',
quantity: 1,
},
},
],
},
],
},
],
});

入参:

type StudioScriptFormBatchCreateWithChildTablesInput = {
formApiName: string;
records: Array<{
title: string;
data: Record<string, unknown>;
buttonKey?: string | null;
submitApproval?: boolean;
childTables: Array<{
childFormApiName: string;
records: Array<{
title: string;
data: Record<string, unknown>;
buttonKey?: string | null;
submitApproval?: boolean;
}>;
}>;
}>;
};

参数:

参数类型必填说明
formApiNamestring是主表 API 名;运行时会解析为租户侧主表 ID
recordsArray<object>是要创建的主表批次数据;每批次最少 1 条主表记录,最多 100 条主表记录
records[].titlestring是主表记录标题,用于运行时列表和展示
records[].dataRecord<string, unknown>是主表字段值,key 为字段 API 名;必须是对象
records[].childTablesArray<object>是当前主表记录下要创建的明细表批次数据;至少包含一个明细表
records[].childTables[].childFormApiNamestring是明细表 API 名;必须是当前主表的明细表
records[].childTables[].recordsArray<object>是明细表批次数据;每个明细表批次最少 1 条,最多 100 条

返回:

type StudioScriptFormBatchCreateWithChildTablesResult = {
items: StudioScriptFormCreateWithChildTablesResult[];
total: number;
};

batchCreateWithChildTables 适合导入场景:每条主表数据都带自己的明细表数据。整个批次在一个事务中执行。任意主表记录、明细表识别、明细记录、创建后任务写入或审批任务写入失败时,SDK 调用会 reject,并回滚整个批次。

记录更新​

更新单条记录​

const updated = await context.form.update({
recordId: record.id,
data: {
status: 'confirmed',
},
});

入参:

type StudioScriptFormUpdateInput = {
recordId: string;
title?: string;
data?: Record<string, unknown>;
buttonKey?: string | null;
submitApproval?: boolean;
};

参数:

参数类型必填说明
recordIdstring是目标表单记录 ID
titlestring否新记录标题;不传则保持当前标题
dataRecord<string, unknown>否要合并进现有记录数据的字段值
buttonKeystring | null否可选按钮权限 key;传入时会校验按钮执行权限
submitApprovalboolean否为 true 时,会在同一个事务中为这条更新后的记录写入审批提交任务

data 会合并到现有记录数据中。汇总字段、动态公式字段等只读计算字段会由现有表单数据写入链路忽略。

批量更新记录​

const result = await context.form.batchUpdate({
records: [
{
recordId: 'record-id-1',
data: {
status: 'confirmed',
},
},
{
recordId: 'record-id-2',
title: 'Updated Title',
data: {
status: 'approved',
},
submitApproval: true,
},
],
});

入参:

type StudioScriptFormBatchUpdateInput = {
records: StudioScriptFormUpdateInput[];
};

返回:

type StudioScriptFormBatchUpdateResult = {
items: StudioScriptFormRecord[];
total: number;
};

参数:

参数类型必填说明
recordsStudioScriptFormUpdateInput[]是要更新的记录;最少 1 条,最多 100 条

batchUpdate 会在一个事务中更新全部记录。任意一条记录在校验、权限检查、自动字段重算、更新后任务写入或审批任务写入过程中失败时,SDK 调用会 reject,并回滚本批次的全部更新。

更新主子表记录​

const result = await context.form.updateWithChildTables({
recordId: 'parent-record-id',
title: 'SO-1005',
data: {
status: 'confirmed',
},
submitApproval: true,
childTables: [
{
childFormApiName: 'order_items',
records: [
{
recordId: 'child-record-id-1',
data: {
quantity: 2,
},
},
{
recordId: 'child-record-id-2',
data: {
quantity: 1,
},
submitApproval: true,
},
],
},
],
});

入参:

type StudioScriptFormChildTableUpdateInput = {
childFormApiName: string;
records: StudioScriptFormUpdateInput[];
};

type StudioScriptFormUpdateWithChildTablesInput = StudioScriptFormUpdateInput & {
childTables: StudioScriptFormChildTableUpdateInput[];
};

返回:

type StudioScriptFormUpdateWithChildTablesResult = {
record: StudioScriptFormRecord;
childTables: Array<{
childFormApiName: string;
items: StudioScriptFormRecord[];
total: number;
}>;
};

updateWithChildTables 会在一个事务中更新一条主表记录和指定的明细表记录。明细记录通过 recordId 更新,这个接口不会为缺失的明细记录自动新建。主记录不存在时返回 null。任意主表更新、明细表识别、明细更新、更新后任务写入或审批任务写入失败时,SDK 调用会 reject,并回滚整个事务。

批量更新主子表记录​

const result = await context.form.batchUpdateWithChildTables({
records: [
{
recordId: 'parent-record-id-1',
data: {
status: 'confirmed',
},
childTables: [
{
childFormApiName: 'order_items',
records: [
{
recordId: 'child-record-id-1',
data: {
quantity: 3,
},
},
],
},
],
},
{
recordId: 'parent-record-id-2',
data: {
status: 'approved',
},
submitApproval: true,
childTables: [
{
childFormApiName: 'order_items',
records: [
{
recordId: 'child-record-id-2',
data: {
quantity: 5,
},
submitApproval: true,
},
],
},
],
},
],
});

入参:

type StudioScriptFormBatchUpdateWithChildTablesInput = {
records: Array<StudioScriptFormUpdateInput & {
childTables: StudioScriptFormChildTableUpdateInput[];
}>;
};

返回:

type StudioScriptFormBatchUpdateWithChildTablesResult = {
items: StudioScriptFormUpdateWithChildTablesResult[];
total: number;
};

batchUpdateWithChildTables 会在一个事务中批量更新多条主表记录及各自的明细表记录。每条主记录和明细记录仍然遵循和单条更新相同的权限校验、自动字段重算、更新后任务写入与可选审批任务写入。任意主记录不存在或任意更新步骤失败时,SDK 调用会 reject,并回滚整个批次。

记录删除​

删除相关 API 分为软删除和硬删除两类:

  • trash / batchTrash:软删除,将记录移入回收站
  • delete / batchDelete:硬删除

删除审批说明:

  • trash / batchTrash 支持显式传入 submitApproval
  • submitApproval 为 true 时,会按删除动作发起删除审批;如果当前表单没有命中删除审批配置,则回退为直接软删除
  • delete / batchDelete 也暴露了 submitApproval 入参,但当前硬删除链路不支持触发删除审批;传入 true 会报 FORM_DATA_DELETE_APPROVAL_NOT_SUPPORTED

入参:

type StudioScriptFormDeleteInput = {
recordId: string;
buttonKey?: string | null;
submitApproval?: boolean;
};

type StudioScriptFormRestoreInput = {
recordId: string;
buttonKey?: string | null;
title?: string;
data?: Record<string, unknown>;
dataStatus?: 'draft' | 'active' | 'archived';
};

type StudioScriptFormBatchDeleteInput = {
recordIds: string[];
buttonKey?: string | null;
submitApproval?: boolean;
};

type StudioScriptFormBatchTrashResult = {
requestedCount: number;
trashedCount: number;
trashedRecordIds: string[];
failed: Array<{
recordId: string;
code: string;
}>;
};

type StudioScriptFormBatchDeleteResult = {
requestedCount: number;
deletedCount: number;
deletedRecordIds: string[];
failed: Array<{
recordId: string;
code: string;
}>;
};

软删除单条记录​

const result = await context.form.trash({
recordId: record.id,
submitApproval: true,
});

返回:

type StudioScriptFormTrashResult = {
trashed: boolean;
};

参数:

参数类型必填说明
recordIdstring是目标表单记录 ID
buttonKeystring | null否可选按钮权限 key;传入时会校验按钮执行权限
submitApprovalboolean否为 true 时,优先按删除动作发起删除审批;如果没有命中删除审批配置,则回退为直接软删除

submitApproval 为 true 时,SDK 会优先尝试发起删除审批。审批提交成功时,返回值中的 trashed 也会是 true;未命中删除审批配置时,记录会直接移入回收站。

硬删除单条记录​

const result = await context.form.delete({
recordId: record.id,
submitApproval: false,
});

返回:

type StudioScriptFormDeleteResult = {
deleted: boolean;
};

参数:

参数类型必填说明
recordIdstring是目标表单记录 ID
buttonKeystring | null否可选按钮权限 key;传入时会校验按钮执行权限
submitApprovalboolean否当前硬删除链路暂不支持触发删除审批;传入 true 会报 FORM_DATA_DELETE_APPROVAL_NOT_SUPPORTED

当前 Studio Script SDK 的 delete 链路用于硬删除,不支持通过审批驱动执行。需要删除审批时,请改用 trash / batchTrash 并传入 submitApproval: true。

批量软删除记录​

const result = await context.form.batchTrash({
recordIds: selectedRecordIds,
submitApproval: true,
});

返回:

type StudioScriptFormBatchTrashResult = {
requestedCount: number;
trashedCount: number;
trashedRecordIds: string[];
failed: Array<{
recordId: string;
code: string;
}>;
};

参数:

参数类型必填说明
recordIdsstring[]是要软删除的目标表单记录 ID;最少 1 条,最多 100 条
buttonKeystring | null否可选按钮权限 key;传入时会校验按钮执行权限
submitApprovalboolean否为 true 时,逐条按删除动作尝试发起删除审批;未命中删除审批配置时,回退为直接软删除

batchTrash 返回部分成功结果。无法移入回收站的记录会带运行时错误码返回到 failed,成功记录会返回到 trashedRecordIds。传入 submitApproval: true 时,每条记录都会独立判断是否命中删除审批配置。

批量硬删除记录​

const result = await context.form.batchDelete({
recordIds: staleRecordIds,
submitApproval: false,
});

返回:

type StudioScriptFormBatchDeleteResult = {
requestedCount: number;
deletedCount: number;
deletedRecordIds: string[];
failed: Array<{
recordId: string;
code: string;
}>;
};

参数:

参数类型必填说明
recordIdsstring[]是要硬删除的目标表单记录 ID;最少 1 条,最多 100 条
buttonKeystring | null否可选按钮权限 key;传入时会校验按钮执行权限
submitApprovalboolean否当前硬删除链路暂不支持触发删除审批;传入 true 会报 FORM_DATA_DELETE_APPROVAL_NOT_SUPPORTED

batchDelete 同样返回部分成功结果,失败记录会带错误码返回到 failed。当前硬删除不支持审批驱动执行;需要删除审批时,请改用 batchTrash 并传入 submitApproval: true。

恢复回收站记录​

restore 用于恢复一条已经软删除的记录,并可同时更新标题、字段数据和恢复后的数据状态:

const restored = await context.form.restore({
recordId: trashedRecordId,
dataStatus: 'active',
data: {
restoreReason: 'Confirmed by operations',
},
});

if (!restored) {
return { ok: false, message: 'Record could not be restored.' };
}
参数类型必填说明
recordIdstring是回收站中的目标记录 ID
buttonKeystring | null否需要复用产品按钮权限时传入按钮 key
titlestring否恢复时更新记录标题
dataRecord<string, unknown>否恢复时合并到记录的字段值
dataStatus'draft' | 'active' | 'archived'否恢复后的数据状态

restore 只用于软删除记录。已经硬删除的记录不能恢复。

保存筛选器 Client​

context.formSavedFilter 管理当前运行主体在指定表单下的个人保存筛选器。它不会创建全租户共享筛选器,也不会替其他成员修改筛选器。

新建或更新保存筛选器​

const saved = await context.formSavedFilter.save({
formApiName: 'orders',
name: '待处理的大额订单',
condition: {
logic: 'and',
children: [
{ field: 'status', operator: 'eq', value: 'pending' },
{ field: 'amount', operator: 'gte', value: 10000 },
],
},
});

condition 必须是根条件组,字段使用目标表单的字段 API 名。创建时省略 id;更新时必须传回现有筛选器的真实 id:

const filters = await context.formSavedFilter.list({
formApiName: 'orders',
});

const current = filters.items.find((item) => item.name === '待处理的大额订单');
if (current) {
await context.formSavedFilter.save({
formApiName: 'orders',
id: current.id,
name: current.name,
condition: {
logic: 'and',
children: [{ field: 'status', operator: 'eq', value: 'pending' }],
},
});
}

删除时使用 filterId,返回值是 { id },不是 { deleted }:

const deleted = await context.formSavedFilter.delete({
filterId: saved.id,
});

表格视图 Client​

context.formTableView 管理当前运行主体的个人表格视图。视图保存布局、分组和显示偏好;它不修改表单字段、布局设计或其他成员的视图。

新建或更新表格视图​

const view = await context.formTableView.save({
formApiName: 'orders',
name: '按客户分组',
layoutIds: [listLayoutId],
groupFieldIds: [customerFieldId],
scopes: ['list'],
bordered: true,
showRowNumber: true,
groups: [
{
id: 'customer-group',
name: '客户',
fieldIds: [customerFieldId],
level: 1,
parentId: null,
},
],
});
参数说明
formApiName目标表单 API 名,不传内部表单 ID
id更新现有视图时传入真实视图 ID;创建时省略
layoutIds视图使用的布局 ID
groupFieldIds用于分组的字段 ID,不是字段 API 名
scopes支持 list、detail、new、edit、relation;未提供有效值时使用 list
bordered是否显示表格边框
showRowNumber是否显示行号
groups最多三级的分组配置,每组通过 fieldIds 引用字段 ID

该 API 没有 columns 入参。调用前如果不知道布局 ID 或字段 ID,应先从实际表单配置中取得,不能把 API 名当成 ID。

查询与删除:

const views = await context.formTableView.list({
formApiName: 'orders',
});

const deleted = await context.formTableView.delete({
viewId: view.id,
});

删除返回 { id }。list、save 和 delete 都只作用于当前运行主体拥有的视图。

表单结构 Client​

当脚本在读写记录之前需要表单或字段元数据时,可以使用 studioScriptContext.formSchema。

interface StudioScriptFormSchemaClient {
get(input: StudioScriptFormSchemaGetInput): Promise<StudioScriptFormSchema>;
fields(input: StudioScriptFormSchemaFieldsInput): Promise<StudioScriptFormFieldList>;
field(input: StudioScriptFormSchemaFieldInput): Promise<StudioScriptFormField | null>;
}

Client 方法:

方法入参返回值说明
getStudioScriptFormSchemaGetInputStudioScriptFormSchema通过表单 API 名查询表单元数据
fieldsStudioScriptFormSchemaFieldsInputStudioScriptFormFieldList查询指定表单的字段列表,可按关键词过滤
fieldStudioScriptFormSchemaFieldInputStudioScriptFormField | null通过表单 API 名和字段 API 名查询单个字段

获取表单元数据​

const form = await context.formSchema.get({
formApiName: 'orders',
});

参数:

参数类型必填说明
formApiNamestring是表单 API 名;运行时会解析并返回当前访问主体可访问的表单元数据

表单结构​

type StudioScriptFormSchema = {
id: string;
name: string;
apiName: string;
type: string;
description: string | null;
icon: string | null;
isDefault: boolean;
enabled: boolean;
};

查询字段列表​

const fields = await context.formSchema.fields({
formApiName: 'orders',
keyword: 'amount',
});

参数:

参数类型必填说明
formApiNamestring是表单 API 名
keywordstring | null否可选关键词,用于按字段名称或字段 API 名过滤

获取单个字段​

const amountField = await context.formSchema.field({
formApiName: 'orders',
fieldApiName: 'amount',
});

参数:

参数类型必填说明
formApiNamestring是表单 API 名
fieldApiNamestring是要在目标表单中解析的字段 API 名

字段结构​

type StudioScriptFormField = {
id: string;
formId: string;
groupId: string | null;
name: string;
apiName: string;
type: string;
dataType: string;
sortOrder: number;
required: boolean;
readonly: boolean;
disabled: boolean;
hidden: boolean;
isDefault: boolean;
isIdentifier: boolean;
defaultValue: unknown;
options: unknown;
validation: unknown;
display: unknown;
specialConfig: unknown;
config: unknown;
};

字段元数据会按当前访问主体的表单和字段元数据权限过滤。

内置表单、字段和选项标签在 Studio SDK 中会返回兜底英文展示文本。产品页面仍然使用数据库中的 i18n: key 按当前页面语言翻译。

文件 Client​

当脚本需要解析表单文件字段中的文件资产,或创建新的文件资产时,可以使用 studioScriptContext.file。

interface StudioScriptFileClient {
get(input: StudioScriptFileGetInput): Promise<StudioScriptFileAsset | null>;
resolve(input: StudioScriptFileResolveInput): Promise<StudioScriptFileAsset[]>;
create(input: StudioScriptFileCreateInput): Promise<StudioScriptFileAsset>;
}

Client 方法:

方法入参返回值说明
getStudioScriptFileGetInputStudioScriptFileAsset | null通过文件 ID 查询单个文件资产
resolveStudioScriptFileResolveInputStudioScriptFileAsset[]通过文件 ID 批量解析文件资产
createStudioScriptFileCreateInputStudioScriptFileAsset通过 base64 文件内容创建文件资产

脚本需要文件展示地址时,可以使用 file.previewUrl || file.url。previewUrl 只会在当前预览器支持的文件类型上返回,例如常见图片、PDF、文本/代码文件、常见音视频文件。合法上传和下载的文件仍然可能返回 previewUrl: null。

获取单个文件​

const file = await context.file.get({
fileId: '6d4b0e70-8a36-4c11-a6f2-6ad1a7f6aa01',
});

参数:

参数类型必填说明
fileIdstring是文件资产 ID

批量解析文件​

const files = await context.file.resolve({
fileIds: ['file-id-1', 'file-id-2'],
});

参数:

参数类型必填说明
fileIdsstring[]是要解析的文件资产 ID

创建文件​

const csv = 'orderNo,amount\\nSO-1001,1200\\n';
const file = await context.file.create({
name: 'orders.csv',
mimeType: 'text/csv',
size: csv.length,
contentBase64: btoa(csv),
});

参数:

参数类型必填说明
namestring是文件展示名称
originalNamestring否原始文件名;默认使用 name
mimeTypestring是MIME 类型,例如 text/csv 或 application/pdf
sizenumber是预期文件大小,单位字节
contentBase64string是base64 编码后的文件内容
storagePolicyKeystring | null否可选存储策略 key;不传则使用默认策略

文件 API 限定在当前租户范围内。Studio 脚本不暴露硬删除文件接口。

审批 Client​

当脚本需要提交记录审批、查询审批实例,或处理当前 actor 的审批任务时,可以使用 studioScriptContext.approval。

type StudioScriptApprovalRecordListInput = {
cursor?: string | null;
limit?: number;
status?: StudioScriptApprovalStatus | null;
definitionId?: string | null;
initiatorMemberId?: string | null;
currentApproverMemberId?: string | null;
startedAtFrom?: string | null;
startedAtTo?: string | null;
keyword?: string | null;
};

type StudioScriptApprovalRecordListItem = {
id: string;
definitionId: string;
definitionName: string;
recordId: string;
recordTitle: string;
formApiName: string;
formName: string;
initiatorType: string;
initiatorId: string;
initiatorName: string;
initiatorDisplayName: string | null;
currentApproverPrincipals: Array<{ principalType: string; principalId: string; displayName: string | null }>;
taskIds: string[];
currentNodeName: string;
currentApproverName: string;
taskStatus: string;
instanceStatus: string;
instanceResult: string | null;
startedAt: string;
completedAt: string | null;
};

type StudioScriptApprovalRecordListResult = {
items: StudioScriptApprovalRecordListItem[];
hasMore: boolean;
nextCursor: string | null;
limit: number;
};
interface StudioScriptApprovalClient {
getSubmissionConfig(input: { formApiName: string; action?: 'create' | 'update' | 'delete' }): Promise<{
enabled: boolean;
allowWithdraw: boolean;
definitionId: string | null;
definitionVersionId: string | null;
definitionName: string | null;
}>;
submitRecord(input: { recordId: string; action?: 'create' | 'update' | 'delete'; beforeRecordData?: Record<string, unknown> | null }): Promise<StudioScriptApprovalSubmitRecordResult>;
listRecords(input?: StudioScriptApprovalRecordListInput): Promise<StudioScriptApprovalRecordListResult>;
listRecordInstances(input: { recordId: string }): Promise<StudioScriptApprovalRecordInstanceSummary[]>;
getInstance(input: { instanceId: string }): Promise<StudioScriptApprovalInstance | null>;
listTasks(input?: { cursor?: string | null; limit?: number; status?: string | null; memberId?: string | null; timeRange?: { from: string; to: string } | null }): Promise<{ items: StudioScriptApprovalTaskListItem[]; hasMore: boolean; nextCursor: string | null; limit: number; timeRange: { from: string; to: string } }>;
getTask(input: { taskId: string }): Promise<StudioScriptApprovalTaskDetail | null>;
decideTask(input: { taskId: string; decision: 'approved' | 'rejected' | 'returned'; comment?: string | null; returnTarget?: StudioScriptApprovalReturnTarget | null }): Promise<StudioScriptApprovalTaskDecisionResult>;
withdraw(input: { instanceId: string; comment?: string | null }): Promise<{
instance: StudioScriptApprovalInstance;
record: {
recordId: string;
formId: string;
dataStatus: string;
approvalStatus: string;
approvalFlowInstanceId: string | null;
} | null;
}>;
}

Client 方法:

方法入参返回值说明
getSubmissionConfig{ formApiName: string; action?: 'create' | 'update' | 'delete' }{ enabled; allowWithdraw; definitionId; definitionVersionId; definitionName }查询指定表单动作的审批提交配置
submitRecord{ recordId: string; action?: 'create' | 'update' | 'delete'; beforeRecordData?: Record<string, unknown> | null }StudioScriptApprovalSubmitRecordResult将记录提交审批,并返回精简提交摘要
listRecordsStudioScriptApprovalRecordListInputStudioScriptApprovalRecordListResult使用游标分页查询审批运行时可见的记录摘要
listRecordInstances{ recordId: string }StudioScriptApprovalRecordInstanceSummary[]查询一条记录关联的审批实例摘要列表
getInstance{ instanceId: string }StudioScriptApprovalInstance | null通过实例 ID 查询单个审批实例
listTasks{ cursor?: string; limit?: number; status?: string; memberId?: string; timeRange?: { from: string; to: string } }{ items: StudioScriptApprovalTaskListItem[]; hasMore: boolean; nextCursor: string | null; limit: number; timeRange: { from: string; to: string } }使用游标分页查询当前 actor 或指定成员可见/可处理的审批任务摘要列表
getTask{ taskId: string }StudioScriptApprovalTaskDetail | null通过任务 ID 查询单个审批任务摘要
decideTask{ taskId: string; decision: 'approved' | 'rejected' | 'returned'; comment?: string | null; returnTarget?: StudioScriptApprovalReturnTarget | null }StudioScriptApprovalTaskDecisionResult对审批任务执行通过、拒绝或退回
withdraw{ instanceId: string; comment?: string | null }{ instance: StudioScriptApprovalInstance; record: object | null }当前 actor 有权限时,撤回待审批实例

获取提交配置​

const config = await context.approval.getSubmissionConfig({
formApiName: 'orders',
action: 'update',
});

参数:

参数类型必填说明
formApiNamestring是表单 API 名;运行时内部解析 form ID
action'create' | 'update' | 'delete'否触发动作;默认 update

提交记录审批​

const result = await context.approval.submitRecord({
recordId: 'record-id',
action: 'update',
});

参数:

参数类型必填说明
recordIdstring是表单记录 ID
action'create' | 'update' | 'delete'否触发动作;默认 update
beforeRecordDataRecord<string, unknown> | null否更新或删除审批场景下的变更前记录数据快照

返回结构:

type StudioScriptApprovalSubmitRecordResult = {
submitted: boolean;
config: {
enabled: boolean;
definitionName: string | null;
allowWithdraw: boolean;
};
record: {
recordId: string;
dataStatus: string;
approvalStatus: string;
approvalFlowInstanceId: string | null;
};
instance: {
instanceId: string;
status: string;
result: string | null;
startedAt: string;
completedAt: string | null;
} | null;
currentTask: {
taskId: string;
status: string;
nodeKey: string;
nodeName: string;
assigneeType: string;
assigneeId: string;
assigneeDisplayName: string | null;
} | null;
};

submitRecord 面向脚本返回精简摘要,不包含完整实例快照、审批主体记录、节点历史、子表数据或表单字段数据。脚本需要完整审批运行时详情时,再调用 listRecordInstances 或 getInstance。

查询审批记录列表​

const records = await context.approval.listRecords({
limit: 20,
status: 'pending',
currentApproverMemberId: 'member-id',
});

参数:

参数类型必填说明
cursorstring | null否上一次调用返回的不透明游标 nextCursor;继续查询时其他条件必须保持不变
limitnumber否单次最多返回的记录数;默认 20,最大 100
statusStudioScriptApprovalStatus | null否按任务状态过滤
definitionIdstring | null否按审批流程过滤
initiatorMemberIdstring | null否按发起成员过滤
currentApproverMemberIdstring | null否按当前审批成员过滤
startedAtFrom / startedAtTostring | null否按发起时间范围过滤
keywordstring | null否关键词搜索

listRecords 复用审批记录页相同的审批运行时可见性和权限规则。

查询记录审批实例​

const instances = await context.approval.listRecordInstances({
recordId: 'record-id',
});

参数:

参数类型必填说明
recordIdstring是表单记录 ID

返回结构:

type StudioScriptApprovalRecordInstanceSummary = {
instanceId: string;
status: string;
result: string | null;
definitionName: string;
allowWithdraw: boolean;
subjectId: string;
startedAt: string;
completedAt: string | null;
currentTasks: Array<{
taskId: string;
status: string;
nodeKey: string;
nodeName: string;
assigneeType: string;
assigneeId: string;
assigneeDisplayName: string | null;
}>;
};

listRecordInstances 面向脚本返回实例摘要和当前待审批任务,不包含完整实例快照、审批主体记录、节点历史、子表数据或表单字段数据。脚本需要完整审批运行时详情时,再调用 getInstance。

查询审批实例​

const instance = await context.approval.getInstance({
instanceId: 'approval-instance-id',
});

参数:

参数类型必填说明
instanceIdstring是审批实例 ID

getInstance 返回完整审批实例详情,包含实例快照、节点历史、任务列表和审批主体记录。脚本只需要摘要时,优先使用 listRecordInstances。

查询审批任务​

const tasks = await context.approval.listTasks({
status: 'pending',
});

参数:

参数类型必填说明
cursorstring | null否上一页返回的游标
limitnumber否单次最多返回的任务数,默认 20,最大 100
statusstring | null否可选任务状态过滤
memberIdstring | null否指定成员 ID;不传时查询当前运行 actor
timeRange{ from: string; to: string } | null否可选的任务搜索时间范围;省略时由审批 Runtime 使用默认范围

返回结构:

type StudioScriptApprovalTaskListItem = {
taskId: string;
instanceId: string;
status: string;
nodeKey: string;
nodeName: string;
assigneeType: string;
assigneeId: string;
assigneeDisplayName: string | null;
subjectId: string;
instanceStatus: string;
createdAt: string;
};

listTasks 面向脚本返回任务摘要,不包含 tenantId、审批策略字段、审批意见、完整 subjectSnapshot、子表数据或表单字段数据。脚本需要单个任务的处理结果时,再调用 getTask。

查询单个审批任务​

const task = await context.approval.getTask({
taskId: 'task-id',
});

返回结构:

type StudioScriptApprovalTaskDetail = StudioScriptApprovalTaskListItem & {
decidedAt: string | null;
decision: string | null;
comment: string | null;
};

getTask 面向脚本返回任务摘要,不包含完整 subjectSnapshot、子表数据或表单字段数据。脚本需要完整业务记录数据时,请通过 subjectId 调用表单 SDK 查询对应记录。

审批任务决策​

await context.approval.decideTask({
taskId: 'task-id',
decision: 'approved',
comment: 'Looks good.',
});

参数:

参数类型必填说明
taskIdstring是审批任务 ID
decision'approved' | 'rejected' | 'returned'是审批决策
commentstring | null否审批意见;部分审批节点可能要求填写
returnTarget{ type: 'initiator' } | { type: 'node'; nodeKey: string } | null否退回到发起人或指定节点时使用

返回结构:

type StudioScriptApprovalTaskDecisionResult = {
task: {
taskId: string;
status: string;
decision: string | null;
comment: string | null;
decidedAt: string | null;
} | null;
instance: {
instanceId: string;
status: string;
result: string | null;
completedAt: string | null;
currentTasks: StudioScriptApprovalTaskSummary[];
};
};

decideTask 复用产品 UI 相同的审批运行时权限和节点决策规则。节点可能拒绝不支持的决策、缺失的审批意见或缺失的退回目标。

撤回审批实例​

const result = await context.approval.withdraw({
instanceId: 'approval-instance-id',
comment: 'Withdraw by script.',
});

参数:

参数类型必填说明
instanceIdstring是待撤回的审批实例 ID
commentstring | null否撤回说明

只有当前 actor 有权撤回且实例仍在待审批中时,withdraw 才会成功。

组织记录 Client​

当脚本需要只读访问组织表中的组织记录时,可以使用 studioScriptContext.organization。

interface StudioScriptOrganizationClient {
get(input: StudioScriptOrganizationGetInput): Promise<StudioScriptOrganization | null>;
list(input?: StudioScriptOrganizationListInput): Promise<StudioScriptOrganizationList>;
tree(input?: Record<string, never>): Promise<StudioScriptOrganizationTree>;
}

Client 方法:

方法入参返回值说明
getStudioScriptOrganizationGetInputStudioScriptOrganization | null通过组织 ID 查询单个组织
listStudioScriptOrganizationListInputStudioScriptOrganizationList查询组织列表,可按关键词过滤
treeRecord<string, never>StudioScriptOrganizationTree查询组织树;不需要参数

查询组织列表​

const organizations = await context.organization.list({
keyword: 'Sales',
condition: {
logic: 'and',
children: [{ field: 'so_status', operator: 'eq', value: 'active' }],
},
});

参数:

参数类型必填说明
keywordstring | null否按组织名称或编码过滤
conditionStudioScriptFormConditionGroup | null否按组织资料表单字段 API 名执行结构化条件查询;操作符与表单记录查询一致

获取组织树​

const tree = await context.organization.tree();

tree 不需要参数。

获取单个组织​

const organization = await context.organization.get({
organizationId: 'organization-id',
});

参数:

参数类型必填说明
organizationIdstring是组织 ID

组织记录 Client 在 Studio 脚本中只读,不暴露组织的新建、更新、移动、停用或删除操作。

部门 Client​

当脚本需要只读访问部门数据时,可以使用 studioScriptContext.department。

interface StudioScriptDepartmentClient {
get(input: StudioScriptDepartmentGetInput): Promise<StudioScriptDepartment | null>;
list(input?: StudioScriptDepartmentListInput): Promise<StudioScriptDepartmentList>;
tree(input?: { organizationId?: string | null }): Promise<StudioScriptDepartmentTree>;
}

Client 方法:

方法入参返回值说明
getStudioScriptDepartmentGetInputStudioScriptDepartment | null通过部门 ID 查询单个部门
listStudioScriptDepartmentListInputStudioScriptDepartmentList查询部门列表,可按关键词和组织过滤
tree{ organizationId?: string | null }StudioScriptDepartmentTree查询部门树,可按组织 ID 过滤

查询部门列表​

const departments = await context.department.list({
keyword: 'Sales',
condition: {
logic: 'and',
children: [{ field: 'so_status', operator: 'eq', value: 'active' }],
},
});

参数:

参数类型必填说明
keywordstring | null否按部门名称或编码过滤
organizationIdstring | null否按组织 ID 过滤部门
conditionStudioScriptFormConditionGroup | null否按部门资料表单字段 API 名执行结构化条件查询;操作符与表单记录查询一致

获取部门树​

const tree = await context.department.tree();

参数:

参数类型必填说明
organizationIdstring | null否按组织 ID 过滤部门树

获取单个部门​

const department = await context.department.get({
departmentId: 'department-id',
});

参数:

参数类型必填说明
departmentIdstring是部门 ID

部门 Client 在 Studio 脚本中只读,不暴露部门的新建、更新、移动、停用或删除操作。

成员 Client​

当脚本需要只读访问成员数据时,可以使用 studioScriptContext.member。

interface StudioScriptMemberClient {
current(input?: Record<string, never>): Promise<StudioScriptCurrentMember | null>;
get(input: StudioScriptMemberGetInput): Promise<StudioScriptMemberProfileData | null>;
list(input?: StudioScriptMemberListInput): Promise<StudioScriptMemberList>;
}

Client 方法:

方法入参返回值说明
currentRecord<string, never>StudioScriptCurrentMember | null查询触发当前脚本的成员资料表单数据;不需要参数
getStudioScriptMemberGetInputStudioScriptMemberProfileData | null通过成员 ID 查询单个成员的资料表单数据
listStudioScriptMemberListInputStudioScriptMemberList查询成员资料表单数据列表,可按关键词、组织、部门和分页条件过滤

获取当前成员​

const member = await context.member.current();

current 不需要参数。当脚本不是由登录成员上下文触发时,返回 null。

返回结构:

type StudioScriptCurrentMember = {
data: Record<string, unknown>;
};

data 是当前成员的资料表单数据。

查询成员列表​

const members = await context.member.list({
departmentId: 'department-id',
includeDescendants: true,
limit: 20,
condition: {
logic: 'and',
children: [{ field: 'so_avatar', operator: 'not_empty' }],
},
});

items 只包含成员资料表单数据:

type StudioScriptMemberList = {
items: Array<{ data: Record<string, unknown> }>;
hasMore: boolean;
nextCursor: string | null;
limit: number;
summary: {
active: number;
inactive: number;
};
};

参数:

参数类型必填说明
keywordstring | null否按成员姓名、邮箱、手机号或员工编号过滤
organizationIdstring | null否按组织 ID 过滤成员
departmentIdstring | null否按部门 ID 过滤成员
includeDescendantsboolean否传入 departmentId 时,是否包含子部门成员
cursorstring | null否上一次调用返回的不透明游标 nextCursor;继续查询时其他条件必须保持不变
limitnumber否单次最多返回的成员数;默认 20,最大 100
conditionStudioScriptFormConditionGroup | null否按成员资料表单字段 API 名执行结构化条件查询;操作符与表单记录查询一致

获取单个成员​

const member = await context.member.get({
memberId: 'member-id',
});

get 返回和 current 一样的 { data } 结构。

参数:

参数类型必填说明
memberIdstring是成员 ID

成员 Client 在 Studio 脚本中只读,不暴露成员的新建、更新、停用或删除操作。

IAM Client​

当脚本需要判断当前运行主体的有效角色时,可以使用 studioScriptContext.iam。这是只读运行时 SDK,不是角色管理 API。

interface StudioScriptIamClient {
currentRoleSummary(input?: Record<string, never>): Promise<{
roles: StudioScriptIamRole[];
roleCodes: string[];
}>;
memberRoleSummary(input: { memberId: string }): Promise<{
memberId: string;
roles: StudioScriptIamRole[];
roleCodes: string[];
}>;
memberRoleSummaries(input: { memberIds: string[] }): Promise<{
items: Array<{
memberId: string;
roles: StudioScriptIamRole[];
roleCodes: string[];
}>;
}>;
}

Client 方法:

方法入参返回值说明
currentRoleSummaryRecord<string, never>{ roles: StudioScriptIamRole[]; roleCodes: string[] }查询当前运行主体的角色摘要;不需要参数
memberRoleSummary{ memberId: string }{ memberId: string; roles: StudioScriptIamRole[]; roleCodes: string[] }查询指定成员的角色摘要
memberRoleSummaries{ memberIds: string[] }{ items: Array<MemberRoleSummary> }批量查询指定成员的角色摘要

查询当前角色摘要​

const summary = await context.iam.currentRoleSummary();

currentRoleSummary 不需要参数。它会返回当前 actor 通过成员、部门、组织主体匹配到的有效角色,并同时返回去重后的 roleCodes,适合脚本里做简单分支判断。

查询指定成员角色摘要​

const summary = await context.iam.memberRoleSummary({
memberId: 'member-id',
});

参数:

参数类型必填说明
memberIdstring是当前租户中的成员 ID

memberRoleSummary 会返回目标成员通过成员、部门、组织主体匹配到的有效角色,并同时返回去重后的 roleCodes。

批量查询指定成员角色摘要​

const summaries = await context.iam.memberRoleSummaries({
memberIds: ['member-id-1', 'member-id-2'],
});

参数:

参数类型必填说明
memberIdsstring[]是当前租户中的成员 ID;单次最多 100 个

memberRoleSummaries 会按请求顺序返回每个成员的角色摘要。

角色结构​

type StudioScriptIamRole = {
id: string;
code: string;
name: string;
description: string | null;
builtIn: boolean;
systemProtected: boolean;
status: 'active';
bindings: Array<{
id: string;
principalType: 'MEMBER' | 'DEPARTMENT' | 'ORGANIZATION';
principalId: string;
precedence: number;
startAt: string | null;
endAt: string | null;
}>;
};

角色字段:

字段类型说明
idstring角色 ID;需要和角色绑定或其他角色记录关联时使用
codestring稳定的角色编码,适合脚本分支判断,例如 space_admin 或自定义角色编码
namestring角色展示名称
descriptionstring | null角色说明,可为空
builtInboolean是否为系统内置角色
systemProtectedboolean是否受系统保护,普通用户侧操作不能随意修改
status'active'角色状态;SDK 只返回启用角色
bindingsStudioScriptIamRoleBinding[]匹配当前 actor 或指定成员的有效角色绑定列表

绑定字段:

字段类型说明
idstring角色绑定 ID
principalType'MEMBER' | 'DEPARTMENT' | 'ORGANIZATION'授予该角色的主体类型
principalIdstring成员、部门或组织主体的 ID
precedencenumber匹配优先级;数字越小越具体:成员绑定为 0,部门绑定为 1,组织绑定为 2
startAtstring | null绑定开始时间;null 表示立即生效
endAtstring | null绑定结束时间;null 表示不自动过期

只返回启用且处于有效时间窗口内的绑定。禁用角色和无效绑定会被过滤。

自定义登录页​

安装​

npm i @soln/custom-login-sdk

使用完整 demo​

从 GitHub 或 GitCode 下载 demo。SDK 调用已完整接入,代码中的英文注释 SOLN INTEGRATION 1–9 标记了各接入位置。

修改 examples/config.js:

export const config = {
issuer: 'https://console.example.com', // Your trusted Soln control-plane origin.
workspaceLoginUrl: 'https://work.example.com/auth/start', // Your workspace login entry.
brandName: 'Your brand',
faviconUrl: './assets/favicon-192x192.png',
locale: 'zh-CN',
};

将 issuer 替换为你的可信控制面地址,workspaceLoginUrl 替换为工作区的 /auth/start 地址。按需修改 examples/index.html 中的 Logo、examples/messages.js 中的文案和 examples/styles.css 中的样式。将 examples/ 和 dist/ 一起部署到 HTTPS 站点,保留相对目录关系。

在 系统管理 → 组织资料 → 编辑 中,将部署后的 /examples/ 地址填入 自定义登录页地址 并保存;留空恢复默认登录页。从工作区发起登录即可使用,配置 workspaceLoginUrl 后也可直接打开 demo,无需先登录。

接入自己的页面​

页面打开时创建客户端,将对应方法绑定到自己的表单。issuer 填写可信控制面地址。

import {
createSolnLoginClient,
type LoginResult,
} from '@soln/custom-login-sdk';

const login = createSolnLoginClient({
issuer: 'https://console.example.com',
locale: 'zh-CN',
});

const context = await login.getContext();
// If context.passwordSetup is present, show the new-password form.

function finish(result: LoginResult) {
if (result.nextStep === 'set_password') {
// Show the new-password form for result.email.
return;
}
login.complete(result);
}

// Bind to the password-login form.
async function submitPassword(email: string, password: string) {
finish(await login.loginWithPassword({ email, password }));
}

// Bind to the send-code button.
async function sendCode(email: string) {
await login.sendEmailCode({ email });
}

// Bind to the email-code form. The code has six digits.
async function submitCode(email: string, code: string) {
finish(await login.verifyEmailCode({ email, code }));
}

// Bind to the new-password form. Use at least eight characters.
async function submitNewPassword(newPassword: string) {
finish(await login.setupPassword({ newPassword }));
}

调用失败时用自己的消息组件显示错误,在 finally 中恢复按钮状态。人机验证由 SDK 按需自动打开,完整 demo 已包含这些处理。

返回 complete 时调用 complete() 完成登录并进入工作区。登录请求过期后,从工作区 /auth/start 重新发起即可。

权限与错误​

Studio SDK 调用会以当前脚本运行主体执行,并复用租户侧产品运行时的权限检查。它不会绕过表单可见性、行权限、字段权限、按钮权限、审批任务权限或租户文件边界。

当 SDK 调用抛错且脚本没有捕获时,整次脚本执行会失败,执行结果的 errorCode 为 STUDIO_ASSET_EXECUTION_FAILED。执行结果的 errorMessage 会保留底层运行时错误码,例如 IAM_PERMISSION_DENIED、FORMS_SCHEMA_NOT_FOUND 或 FORM_DATA_RECORD_ID_REQUIRED。

权限规则​

Client权限行为
form通过 formApiName 解析表单,检查表单可见性;读取时应用行权限和字段权限;写入时进入正常的新建、更新、删除运行时链路;传入 buttonKey 时,会应用和产品按钮一致的按钮执行权限校验
formSchema只返回当前访问主体可见的表单和字段元数据;表单禁用或不可访问时会拒绝
file只能解析和创建当前租户内的文件资产;其他租户的文件 ID 不可访问
approval使用正常审批运行时的可见性和操作规则;任务处理和撤回必须对当前访问主体或该方法支持的成员上下文可执行
organization / department / member只读;返回当前租户可见的资料表单数据;不暴露新建、更新、停用、移动或删除接口
iam只读;返回当前成员或指定成员的角色摘要;不暴露角色管理或绑定修改接口

错误处理​

当脚本需要把 SDK 失败转换成可控返回值或用户可见运行时效果时,使用 try/catch。

export default async function main(_payload: StudioScriptRuntimeContextPayload, context: StudioScriptContext) {
try {
const record = await context.form.find({
formApiName: 'orders',
condition: {
logic: 'and',
children: [
{
field: 'recordId',
operator: 'eq',
value: 'record-id',
},
],
},
});

return {
ok: true,
record,
};
} catch (error) {
const code = error instanceof Error ? error.message : String(error);
return {
ok: false,
message: code,
notification: {
type: 'error',
title: '操作失败',
description: code,
},
};
}
}

批量方法有两类失败语义:

  • batchTrash 和 batchDelete 返回部分成功结果。单条记录失败会进入 failed,并带 code
  • 事务型批量新建、批量更新方法中任意记录失败时,SDK 调用会 reject,整个事务回滚

常见错误码​

通用 Studio SDK 错误:

错误码含义
STUDIO_ASSET_EXECUTION_FAILED脚本抛出未捕获错误;底层 SDK 错误会作为 errorMessage 返回
STUDIO_FORM_API_INPUT_INVALID表单 SDK 入参必须是对象
STUDIO_FORM_SCHEMA_API_INPUT_INVALID表单结构 SDK 入参必须是对象
STUDIO_FORM_SAVED_FILTER_API_INPUT_INVALID保存筛选器 SDK 入参必须是对象
STUDIO_FORM_TABLE_VIEW_API_INPUT_INVALID表格视图 SDK 入参必须是对象
STUDIO_FILE_API_INPUT_INVALID文件 SDK 入参必须是对象
STUDIO_APPROVAL_API_INPUT_INVALID审批 SDK 入参必须是对象
STUDIO_ORG_API_INPUT_INVALID组织、部门或成员 SDK 入参必须是对象
STUDIO_FORM_API_OPERATION_INVALID未知的表单 SDK 操作
STUDIO_FORM_SCHEMA_API_OPERATION_INVALID未知的表单结构 SDK 操作
STUDIO_FORM_SAVED_FILTER_API_OPERATION_INVALID未知的保存筛选器 SDK 操作
STUDIO_FORM_TABLE_VIEW_API_OPERATION_INVALID未知的表格视图 SDK 操作
STUDIO_FILE_API_OPERATION_INVALID未知的文件 SDK 操作
STUDIO_APPROVAL_API_OPERATION_INVALID未知的审批 SDK 操作
STUDIO_ORG_API_OPERATION_INVALID未知的组织、部门或成员 SDK 操作
STUDIO_IAM_API_OPERATION_INVALID未知的 IAM SDK 操作

表单与表单结构错误:

错误码含义
FORMS_SCHEMA_API_NAME_REQUIRED缺少 formApiName
FORMS_SCHEMA_NOT_FOUND表单 API 名无法解析或当前用户不可访问
FORMS_SCHEMA_DISABLED目标表单已禁用
FORMS_FIELD_API_NAME_REQUIRED缺少 fieldApiName
FORM_DATA_RECORD_ID_REQUIRED缺少 recordId
FORM_DATA_NOT_FOUND目标记录不存在或当前用户不可访问
FORM_DATA_APPROVAL_PENDING_READ_ONLY记录处于审批中状态,不能直接修改
FORM_DATA_APPROVAL_FLOW_REQUIRED当前操作需要审批流程实例
FORM_DATA_APPROVAL_TRANSITION_INVALID请求的审批状态流转不允许
FORM_DATA_DELETE_APPROVAL_NOT_SUPPORTED硬删除不支持发起审批;请使用 trash 或 batchTrash 并传入 submitApproval: true
FORM_DATA_FOREIGN_KEY_RESTRICTED关联记录或关系受数据权限或关系规则限制
IAM_PERMISSION_DENIED当前访问主体没有所需权限
STUDIO_FORM_API_DATA_INVALIDdata 不是对象
STUDIO_FORM_API_RECORDS_REQUIRED批量新建或批量更新至少需要一条记录
STUDIO_FORM_API_RECORDS_LIMIT_EXCEEDED批量新建或批量更新超过最大记录数
STUDIO_FORM_API_RECORD_IDS_REQUIRED批量删除至少需要一个记录 ID
STUDIO_FORM_API_RECORD_IDS_LIMIT_EXCEEDED批量删除超过最大记录 ID 数量
STUDIO_FORM_API_CHILD_TABLES_REQUIRED主子表新建或更新需要传入子表数据
STUDIO_FORM_API_CHILD_TABLE_NOT_FOUND子表 API 名不是当前主表的子表
STUDIO_FORM_API_CHILD_RECORDS_REQUIRED子表操作至少需要一条子表记录
STUDIO_FORM_API_CHILD_RECORDS_LIMIT_EXCEEDED子表操作超过最大子表记录数
FORM_DATA_BATCH_UPDATE_RECORD_NOT_FOUND批量更新的目标记录不存在或不可访问

文件错误:

错误码含义
FILES_ID_REQUIRED缺少 fileId
FILES_IDS_REQUIRED缺少 fileIds 或数组为空
FILES_NAME_REQUIRED缺少文件展示名
FILES_ORIGINAL_NAME_REQUIRED缺少原始文件名
FILES_MIME_TYPE_REQUIRED缺少 MIME 类型
FILES_CONTENT_REQUIRED缺少 base64 文件内容
FILES_NOT_FOUND文件资产不存在或当前用户不可访问

审批错误:

错误码含义
APPROVAL_TRIGGER_ACTION_INVALID审批动作必须是 create、update 或 delete
APPROVAL_TASK_ID_REQUIRED缺少 taskId
APPROVAL_INSTANCE_ID_REQUIRED缺少 instanceId
APPROVAL_TASK_DECISION_INVALID任务决定必须是 approved、rejected 或 returned
APPROVAL_TASK_NOT_FOUND审批任务不存在或当前用户不可见
APPROVAL_TASK_NOT_ACTIONABLE当前访问主体或当前任务状态不允许处理该任务
APPROVAL_TASK_ALREADY_DECIDED审批任务已经处理过
APPROVAL_TASK_COMMENT_REQUIRED当前审批策略要求填写审批意见
APPROVAL_INSTANCE_NOT_FOUND审批实例不存在或当前用户不可见
APPROVAL_INSTANCE_ALREADY_PENDING记录已经存在审批中的实例
APPROVAL_INSTANCE_NOT_ACTIONABLE当前审批实例状态不允许执行该操作
APPROVAL_INSTANCE_WITHDRAW_DISABLED当前审批定义不允许撤回
APPROVAL_INSTANCE_WITHDRAW_FORBIDDEN当前访问主体不能撤回该审批实例
APPROVAL_RETURN_TARGET_INVALID退回目标无效
APPROVAL_RETURN_TARGET_NODE_REQUIRED退回到节点时必须传入 nodeKey

组织、部门、成员和 IAM 错误:

错误码含义
ORGANIZATIONS_ID_REQUIRED缺少 organizationId
DEPARTMENTS_ID_REQUIRED缺少 departmentId
MEMBERS_ID_REQUIRED缺少 memberId
STUDIO_IAM_MEMBER_ID_REQUIRED查询角色摘要时缺少 memberId
STUDIO_IAM_MEMBER_IDS_REQUIRED缺少 memberIds 或数组为空
STUDIO_IAM_MEMBER_IDS_LIMIT_EXCEEDEDmemberIds 超过最大数量 100