Skip to content

自定义页面手工编辑

INFO

此文档面向技术同学使用,用于排障等

每一张 React 自定义页面相当于一个独立的前端 React 源码工程,可以通过点击右上角“编辑页面”进入手工编辑状态。

可以在线对代码做任意修改,并保存发布。

<grid> <column width-ratio="0.499859"> 点击右上角“编辑页面” </column> <column width-ratio="0.500141"> 进入 React 页面手工编辑状态 </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 使用指南

  • 通过 client API 可以访问后端数据和服务。client 实例通过 useSdkClient Hook 获取,支持三类操作:

    • dataset 操作client.models 提供对指定数据集进行 CRUD、筛选、聚合等操作。
    • BFF 执行client.bff 提供调用已定义的后端函数(Backend For Frontend)。
    • 自定义 SQL 执行client.sql 提供执行已定义的 SQL 查询。
  • 使用原则

    1. 优先使用 dataset 操作:单个数据集的增删改查、筛选、聚合等,优先使用 client.models
    2. 复杂操作查 BFF/SQL:跨数据集、多步骤、业务逻辑复杂的操作,优先查找已有的 BFF 或自定义 SQL。
    3. 不能创建新函数:BFF 和自定义 SQL 只能调用已有的函数/查询,不能动态创建。

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 字段。

基于飞书知识库同步生成,内容以飞书源文档为准