自定义页面手工编辑
INFO
此文档面向技术同学使用,用于排障等
每一张 React 自定义页面相当于一个独立的前端 React 源码工程,可以通过点击右上角“编辑页面”进入手工编辑状态。
可以在线对代码做任意修改,并保存发布。
<grid> <column width-ratio="0.499859">
</column> <column width-ratio="0.500141">
</column> </grid>
文件路径规范
使用**相对路径,**推荐结构:
- 入口:
src/app/index.jsx - 样式:
src/app/index.css - 多语言词包:
src/locales/index.js - 组件:
src/components/*.jsx
编码规范
允许使用的组件白名单
在所有代码和文件(包括 `src/**`、配置文件、脚本等)中,导入仅限于以下包及其子路径:
-
react@18-
react-dom@18-
lodash@4-
dayjs@1-
antd@5-
@ant-design/icons@5-
echarts@5
可供使用的全局方法
可在任意 jsx 文件的 React 组件中通过以下方式引入上下文能力:
JavaScript
import { useSdkClient, useI18n, useNavigate, useLocation } from "@/context/app-context";
const client = useSdkClient(); // 用于访问后端数据和服务
const $i18n = useI18n(); // 国际化多语言实例
const navigate = useNavigate(); // 路由跳转实例
const location = useLocation(); // 浏览器 location 实例Client API 使用指南
通过
clientAPI 可以访问后端数据和服务。client实例通过useSdkClientHook 获取,支持三类操作:- dataset 操作:
client.models提供对指定数据集进行 CRUD、筛选、聚合等操作。 - BFF 执行:
client.bff提供调用已定义的后端函数(Backend For Frontend)。 - 自定义 SQL 执行:
client.sql提供执行已定义的 SQL 查询。
- dataset 操作:
使用原则
- 优先使用 dataset 操作:单个数据集的增删改查、筛选、聚合等,优先使用
client.models。 - 复杂操作查 BFF/SQL:跨数据集、多步骤、业务逻辑复杂的操作,优先查找已有的 BFF 或自定义 SQL。
- 不能创建新函数:BFF 和自定义 SQL 只能调用已有的函数/查询,不能动态创建。
- 优先使用 dataset 操作:单个数据集的增删改查、筛选、聚合等,优先使用
Dataset 操作
- 对指定数据集(dataset)进行数据操作。调用格式:
TypeScript
await client.models.<dataset_code>.<function_name>(params);- 其中
<dataset_code>是数据集的唯一标识(如dataset_8d2dcbae08b54bdd84c00be558ed48df),具体值需通过工具或文档获取。 - 支持的操作
| 操作 | 方法 | 说明 |
|---|---|---|
| 筛选查询 | .filter({ where: {...}, currentPage, pageSize }) | 获取符合条件的分页数据列表 |
| 单条查询 | .getOne(id) | 根据主键 ID 获取单条记录 |
| 创建 | .create(data) | 新增一条记录 |
| 单条更新 | .update(id, data) | 更新指定 ID 的记录 |
| 批量更新 | .update([id1, id2], data) | 批量更新多条记录 |
| 单条删除 | .delete(id) | 删除指定 ID 的记录 |
| 批量删除 | .delete([id1, id2]) | 批量删除多条记录 |
| 导出 Excel | .excelExport(filters) | 按条件导出,返回下载文件 URL |
| 聚合查询 | .aggregate({ aggregate: [...] }) | 执行聚合(如求和、平均值) |
- 示例
TypeScript
// 筛选查询
const response =
await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.filter({
where: {
status: "active",
},
currentPage: 1,
pageSize: 20,
});
// 根据 ID 查询
const user =
await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.getOne(
"user-id",
);
// 创建
const newUser =
await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.create({
name: "John Doe",
email: "john@example.com",
});
// 更新
const updated =
await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.update(
"user-id",
{
status: "active",
},
);
// 批量更新
await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.update(
["id1", "id2"],
{ status: "inactive" },
);
// 删除
await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.delete("user-id");
// 批量删除
await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.delete([
"id1",
"id2",
]);
// 导出 Excel
const fileUrl =
await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.excelExport({
status: "active",
createTime: "2026-01-01",
});
// 聚合查询
const stats =
await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.aggregate({
aggregate: [
{ field: "amount", type: "sum", alias: "totalAmount" },
{ field: "age", type: "avg", alias: "averageAge" },
],
});BFF 执行
调用已定义的后端函数(BFF),适用于复杂业务逻辑、跨数据集操作、第三方服务调用等。
- API签名
TypeScript
client.bff.execute<T>({
scriptName: string; // 已有 BFF 函数名称
params?: Record<string, any>; // 可选参数
}): Promise<T>- 使用示例
TypeScript
const price = await client.bff.execute({
scriptName: "calculatePrice",
params: { productId: "prod-001", quantity: 10 },
});
console.log(price);TypeScript
interface PriceParams {
productId: string;
quantity: number;
couponCode?: string;
}
interface PriceResult {
unitPrice: number;
subtotal: number;
discount: number;
total: number;
}
const result = await client.bff.execute<PriceResult>({
scriptName: "calculateOrderPrice",
params: { productId: "p1", quantity: 2, couponCode: "SAVE10" },
});
console.log(`总价: ${result.total}`);TypeScript
interface DashboardStats {
userCount: number;
orderCount: number;
revenue: number;
topProducts: Array<{ name: string; sales: number }>;
}
const stats = await client.bff.execute<DashboardStats>({
scriptName: "getDashboardStats",
params: { timeRange: "last7days" },
});自定义 SQL 执行
执行已定义的 SQL 查询(只读或受控写入)。返回结构固定,必须先检查 execSuccess。
- API 签名
TypeScript
interface SqlExecuteResult<T> {
execSuccess: boolean; // 是否执行成功
execResult?: T[]; // 查询结果数组(成功时存在)
}
client.sql.execute<T>({
sqlCode: string; // 已有 SQL 查询代码
params?: Record<string, any>;
}): Promise<SqlExecuteResult<T>>- **重要:**必须检查执行结果
TypeScript
const result = await client.sql.execute({ sqlCode: "xxxxx-xxxxx" });
if (result.execSuccess && result.execResult) {
// 安全使用 result.execResult
result.execResult.forEach((row) => console.log(row));
} else {
console.error("SQL 执行失败");
}- 示例
TypeScript
interface UserQueryParams {
userId: number;
status: string;
}
interface UserRow {
id: number;
name: string;
email: string;
status: string;
}
const result = await client.sql.execute<UserRow>({
sqlCode: "getUsersByStatus",
params: { userId: 123, status: "active" },
});
if (result.execSuccess) {
console.log(`找到 ${result.execResult?.length} 个用户`);
for (const user of result.execResult ?? []) {
console.log(user.name);
}
}错误处理建议
所有 API 都可能抛出异常(网络错误、权限不足、参数错误等)。建议使用 try/catch 包裹:
TypeScript
try {
const data = await client.models.dataset_xxx.filter({ currentPage: 1 });
// 处理 data
} catch (error) {
console.error("操作失败:", error);
// 显示用户友好提示
}对于 client.sql.execute,除了 try/catch,还务必检查 execSuccess 字段。