# Neo OpenAPI SDK 使用文档

## 在自定义组件项目中安装 Neo OpenAPI SDK

```
npm install --save neo-open-api
```

# 对接 Neo 平台实体数据源

在自定义组件中，可通过 **Neo OpenAPI SDK**（`neo-open-api`）访问平台实体数据源，用于查询或写入业务对象数据。

---

## 业务对象 API（xObject）

### 1. 查询业务对象数据列表

使用通用查询接口获取业务对象数据，支持分页与排序。

```typescript
import { xObject } from 'neo-open-api';

// 基本查询（无 where）
const result = await xObject.query({
  xObjectApiKey: 'xxObject', // 业务对象 API Key
  fields: ['name', 'phone', 'email'], // 查询字段
  page: 1, // 页码（可选）
  pageSize: 10, // 每页数量（可选）
  orderBy: 'id asc' // 排序（可选，仅支持 id）
});

// where 为字符串：与通用查询 SQL 语法一致，拼接到 `select ... from ...` 之后
const byString = await xObject.query({
  xObjectApiKey: 'xxObject',
  fields: ['name', 'city'],
  where: "city = '北京' and name like '张%'",
  page: 1,
  pageSize: 20
});

// where 为字符串数组：多项以 ` and ` 连接，便于拆分、复用条件片段
const byArray = await xObject.query({
  xObjectApiKey: 'xxObject',
  fields: ['name', 'status'],
  where: ["status = '生效'", "name like '李%'"],
  page: 1,
  pageSize: 20
});
// 与 where: "status = '生效' and name like '李%'" 等价
```

**参数说明**

| 参数 | 说明 |
|------|------|
| `xObjectApiKey` | 业务对象的 API Key |
| `fields` | 待查询字段数组；会自动补充 `id` |
| `where`（可选） | 过滤条件。**字符串**：完整 `WHERE` 子句内容（不含关键字 `where`），语法与平台通用查询一致（见下文「查询条件与 SQL」）。**字符串数组**：每段为一条条件表达式，默认按顺序用 ` and ` 拼接；空串、`null`、`undefined` 会被忽略。若需 `or` 或复杂嵌套，请使用字符串形式，例如 `(a = 1 or b = 2) and c = 3`。 |
| `page` | 页码，默认 `1` |
| `pageSize` | 每页条数，默认 `10` |
| `orderBy` | 排序表达式，**仅支持对 `id` 排序**，例如 `id asc` 或 `id desc` |

**查询条件与 SQL 说明（与 `/rest/data/v2/query` 通用查询一致）**

`xObject.query` 会将 `fields`、`xObjectApiKey`、`where`、`orderBy` 与分页参数拼装为 SQL，通过请求参数 `q` 提交。下列限制适用于该查询能力。

**不支持的字段类型（查询条件中）**

多选、文本域、地理位置、图片、引用。

**SELECT**

- 由 `fields` 生成；不支持 `*`，须显式列出字段；未传入时也会自动加入 `id`。

**FROM**

- 由 `xObjectApiKey` 生成；可查询**所有自定义对象**，以及**本文档涉及的标准对象**。

**WHERE**

- 由 `where` 生成；各对象字段定义可通过该对象的 **description** 接口获取。
- **不支持**对「多值字段」做取值条件，此类字段**仅**可使用 `is null` 或 `is not null`。
- **支持的操作符**：`=`、`!=`、`like`、`not like`、`not in`、`is not null`、`is null`、`>`、`<`、`<>`、`>=`、`<=`、`in`、`between ... and ...`。
- **`=`、`like`、`in` 补充说明**
  - **`=`**（字符串）为**精确匹配**。例如 `city = '北京'` 仅匹配字段值等于「北京」的记录。
  - **`like`** 须用 `%` 做模糊匹配，例如 `city like '北京%'` 表示以「北京」**开头**。当前**仅支持**将 `%` 写在**已知内容之后**（如 `'北京%'`），**不支持** `city like '%北京'` 等形式。
  - SQL 中含 `%` 等需编码的字符时，应对 SQL 做 **URL 编码**。SDK 使用 GET，将 SQL 作为查询参数 `q` 传递（axios 会序列化 `params`；若自行拼 URL，请确保编码正确）。
  - **支持 `in`**，**不支持**子查询形式的 `in (...)`。
- **逻辑运算符**：`and`、`or`。

**ORDER BY**

- 由 `orderBy` 生成；支持 `asc` / `desc`；**当前仅支持对 `id` 排序**。其他字段排序可在取回列表后在客户端处理。

**LIMIT**

- 由 `page`、`pageSize` 生成。

**返回结构**

```typescript
{
  status: boolean;   // true 表示成功
  code: number;      // 返回码
  msg: string;       // 多为错误信息
  totalSize: number; // 总条数
  data: any[];       // 数据行
}
```

---

### 2. 获取业务类型列表

获取指定业务对象下的业务类型列表。

```typescript
import { xObject } from 'neo-open-api';

const result = await xObject.getEntityTypeList('xObjectApiKey', {
  // 其他请求选项
});
```

**参数说明**

| 参数 | 说明 |
|------|------|
| `xObjectApiKey` | 业务对象的 API Key |
| `options`（可选） | 可选请求配置 |

**返回结构**

```typescript
{
  status: boolean;   // true 表示成功
  code: number;      // 返回码
  msg: string;       // 提示信息
  totalSize: number; // 总条数
  data: any[];       // 业务类型列表数据
}
```

---

### 3. 获取实体列表

获取系统中的对象列表（标准对象、自定义对象或二者）。

```typescript
import { xObject } from 'neo-open-api';

// 标准对象 + 自定义对象（有权限的）
const { data: allEntities } = await xObject.getEntityList({
  active: true
});

// 仅标准对象
const { data: standardObjects } = await xObject.getEntityList({
  custom: false,
  active: true
});

// 仅自定义对象
const { data: customObjects } = await xObject.getEntityList({
  custom: true,
  active: true
});
```

**参数说明**

| 参数 | 说明 |
|------|------|
| `custom`（可选） | 是否限定为自定义对象。`false` 仅标准对象，`true` 仅自定义对象；不传则返回全部实体 |
| `active`（可选） | 是否仅返回当前用户有权限的对象，默认 `true` |

**返回结构**

```typescript
{
  status: boolean;       // true 表示成功
  code: number;          // 返回码
  msg: string;           // 提示信息
  totalSize: number;     // 总条数
  data: Array<EntityDesc>; // 实体描述列表
}
```

---

### 4. 创建业务数据

```typescript
import { xObject } from 'neo-open-api';

const result = await xObject.create('xObjectApiKey', {
  data: {
    name: '张三',
    phone: '13800138000',
    email: 'zhangsan@example.com'
  }
});
```

**参数说明**

- `xObjectApiKey`：业务对象的 API Key  
- `options.data`：待创建字段键值  

**返回结构**

```typescript
{
  status: boolean;
  code: number;
  msg: string;
  totalSize: number;
  data: Object; // 新建记录
}
```

---

### 5. 更新业务数据

```typescript
import { xObject } from 'neo-open-api';

const result = await xObject.update('xObjectApiKey', 'xObjectId', {
  data: {
    name: '李四',
    phone: '13900139000'
  }
});
```

**参数说明**

- `xObjectApiKey`：业务对象的 API Key  
- `xObjectId`：记录主键  
- `options.data`：待更新字段  

**返回结构**

```typescript
{
  status: boolean;
  code: number;
  msg: string;
  data: Object;
}
```

---

### 6. 获取业务数据详情

```typescript
import { xObject } from 'neo-open-api';

// 方式一：对象参数
const result = await xObject.get({
  xObjectApiKey: 'xxKey',
  objectId: 'xxId',
  option: {
    // 其他请求选项
  }
});

// 方式二：位置参数
const result2 = await xObject.get('xObjectApiKey', 'xObjectId', {
  // 其他请求选项
});
```

**参数说明**

- `xObjectApiKey`：业务对象的 API Key  
- `xObjectId`：记录 ID  
- `options`：可选请求配置  

**返回结构**

```typescript
{
  status: boolean;
  code: number;
  msg: string;
  data: Object;
}
```

---

### 7. 删除业务数据

```typescript
import { xObject } from 'neo-open-api';

const result = await xObject.delete('xObjectApiKey', 'xObjectId');
```

**参数说明**

- `xObjectApiKey`：业务对象的 API Key  
- `xObjectId`：待删除记录 ID  

**返回结构**

```typescript
{
  status: boolean;
  code: number;
  msg: string;
}
```

---

### 8. 获取业务对象描述（字段元数据）

获取指定业务对象的元数据信息，包括实体属性及所有字段的定义。

```typescript
import { xObject } from 'neo-open-api';

const result = await xObject.getDesc('xObjectApiKey');
```

**参数说明**

| 参数 | 说明 |
|------|------|
| `xObjectApiKey` | 业务对象的 API Key |

**返回结构**

```typescript
{
  status: boolean;    // true 表示成功
  code: string;       // 返回码，如 "200"
  msg: string;        // 提示信息，成功时为 "OK"
  data: {             // 实体描述数据
    apiKey: string;           // 实体 API Key
    custom: boolean;          // 是否自定义对象
    label: string;            // 实体显示名称
    disabled: boolean;        // 是否已禁用
    createable: boolean;      // 是否可新建
    deletable: boolean;       // 是否可删除
    updateable: boolean;      // 是否可更新
    queryable: boolean;       // 是否可查询
    feedEnabled: boolean;     // 是否启用动态
    fields: FieldItem[];      // 字段定义列表
  }
}
```

#### data 字段说明

| 字段 | 类型 | 说明 |
|------|------|------|
| `apiKey` | `string` | 实体的 API Key，作为该实体在系统中的唯一标识 |
| `custom` | `boolean` | 是否为自定义对象。`false` 表示标准对象，`true` 表示自定义对象 |
| `label` | `string` | 实体的显示名称，如"销售机会"、"客户" |
| `disabled` | `boolean` | 实体是否已被禁用 |
| `createable` | `boolean` | 当前用户是否有权在该实体上新建记录 |
| `deletable` | `boolean` | 当前用户是否有权删除该实体的记录 |
| `updateable` | `boolean` | 当前用户是否有权更新该实体的记录 |
| `queryable` | `boolean` | 当前用户是否有权查询该实体的记录 |
| `feedEnabled` | `boolean` | 该实体是否启用了动态（Feed）功能 |
| `fields` | `FieldItem[]` | 该实体的字段定义数组，描述每个字段的元信息 |

#### fields 数组元素（FieldItem）字段说明

| 字段 | 类型 | 说明 |
|------|------|------|
| `apiKey` | `string` | 字段的 API Key，全局唯一标识 |
| `label` | `string` | 字段的显示名称 |
| `type` | `string` | 字段类型。可选值包括：`text`（单行文本）、`textarea`（多行文本）、`int`（整数）、`currency`（金额）、`picklist`（单选下拉）、`boolean`（布尔）、`date`（日期）、`datetime`（日期时间）、`reference`（引用关系）、`owner`（所属人）、`entitytype`（业务类型）、`dimension`（维度）、`formula_real`（公式-数值）、`email`（邮箱）、`phone`（电话）、`url`（网址）等 |
| `itemType` | `string` | 字段的 Java 数据类型，如 `String`、`Long`、`Integer`、`Double`、`Boolean` 等 |
| `defaultValue` | `any` | 默认值，无默认值时返回 `null` |
| `enabled` | `boolean` | 该字段是否启用 |
| `required` | `boolean` | 该字段是否为必填项 |
| `createable` | `boolean` | 新建记录时是否可填写该字段 |
| `updateable` | `boolean` | 更新记录时是否可修改该字段 |
| `sortable` | `boolean` | 该字段是否支持排序 |
| `minLength` | `number` \| `null` | 最小长度限制，无限制时为 `null` |
| `maxLength` | `number` \| `null` | 最大长度限制，无限制时为 `null` |
| `dependentPropertyName` | `string` \| `null` | 级联依赖的父字段 API Key，独立字段时为 `null` |
| `unique` | `boolean` | 该字段值是否唯一 |
| `encrypt` | `boolean` | 该字段值是否加密存储 |
| `nameField` | `boolean` | 该字段是否为实体的名称字段（Name Field） |
| `referTo` | `object` \| `null` | 引用关系的目标实体信息。引用字段（`type: "reference"`）时非 `null`，包含 `apiKey` 字段表示目标实体的 API Key。其他类型为 `null` |
| `selectitem` | `SelectItem[]` | 下拉选项列表，仅 `type: "picklist"` 时有值，否则为空数组 |
| `checkitem` | `CheckItem[]` | 复选选项列表，通常为空数组 |

---

### 9. 获取业务对象字段列表 `getFileds`

获取指定业务对象的字段列表，仅返回字段定义数组。

```typescript
import { xObject } from 'neo-open-api';

const result = await xObject.getFileds('xObjectApiKey', {
  // 其他请求选项
});
```

**参数说明**

| 参数 | 说明 |
|------|------|
| `xObjectApiKey` | 业务对象的 API Key |
| `options`（可选） | 可选请求配置 |

**返回结构**

```typescript
{
  status: boolean;    // true 表示成功
  code: number;       // 返回码
  msg: string;        // 提示信息
  data: FieldItem[];  // 字段定义数组（同 getDesc 的 fields）
}
```

---

## 平台自定义 API（customApi）

### 调用自定义 API（`customApi.run`）

```typescript
import { customApi } from 'neo-open-api';

const result = await customApi.run({
  apiUrl: '/rest/custom/api/endpoint', // 自定义 API 路径
  methodType: 'POST', // GET、POST、PUT、DELETE 等，可选，默认 POST
  data: {
    key1: 'value1',
    key2: 'value2'
  }
});
```

**参数说明**

- `apiUrl`：自定义 API 地址（必填）  
- `methodType` 或 `method`：HTTP 方法，默认 `POST`  
- `data`：请求体，通常会包装在 `data` 字段中发送  

**返回结构**

```typescript
{
  status: boolean;
  code: number | string;
  msg: string;
  data: any;
}
```

**示例：执行自定义 API 并拉取已注册列表**

```typescript
import { customApi } from 'neo-open-api';

const result = await customApi.run({
  apiUrl: '/rest/custom/api/processData',
  methodType: 'POST',
  data: {
    param1: 'value1',
    param2: 'value2'
  }
});

const { data: apiList } = await customApi.getList({
  pageNo: 1,
  pageSize: 100
});
```

---

### 获取自定义 API 列表（`customApi.getList`）

```typescript
import { customApi } from 'neo-open-api';

const result = await customApi.getList({
  pageNo: 1,     // 可选
  pageSize: 1000 // 可选
});
```

**参数说明**

- `pageNo`：页码，默认 `1`  
- `pageSize`：每页条数，默认 `1000`  

**返回结构**

```typescript
{
  status: boolean;
  code: number | string;
  msg: string;
  totalSize: number;
  data: any[];
}
```

---

## 通用请求（`request`）

若上述封装不足以覆盖场景，可使用基于 axios 封装的 `request` 自行发起请求（支持 GET、POST、PATCH、DELETE 等）。

```typescript
import { request } from 'neo-open-api';

const result = await request({
  url: '/api/endpoint',
  method: 'GET',
  data: { key: 'value' },
  headers: { 'Custom-Header': 'value' },
  timeout: 30000
});
```

**参数说明**

| 参数 | 类型 | 说明 |
|------|------|------|
| `url` | `string` | 请求路径 |
| `method`（可选） | `string` | HTTP 方法，默认 `GET` |
| `data`（可选） | `any` | 请求数据；GET 时会转为 `params` |
| `headers`（可选） | `object` | 请求头；默认包含 `Content-Type: application/json` |
| `timeout`（可选） | `number` | 超时（毫秒），默认 `30000` |

**返回结构**

```typescript
{
  status: boolean;  // true 表示成功
  code: number;     // 返回码
  msg: string;      // 提示信息
  data: any;        // 响应数据
}
```

**白名单路径（拦截器限制）**

仅允许访问以下类型的接口路径（示例前缀，以实际环境为准）：

- 自定义 API：`/rest/data/v2.0/scripts`  
- 自定义 API 列表：`/rest/metadata/v2.0/dx/logic/extpoints/openapi`  
- 实体 Open API：`/rest/data/v2.0/xobjects`  
- 实体列表（元数据过滤）：`/rest/metadata/v2.0/xobjects/filter`  
- 通用查询：`/rest/data/v2/query`  
- BI：`/rest/neobi/v2.0`  
- AI Agent：`/rest/ai/v2.0/agent`  

---

## 综合示例（联系人）

```typescript
import { xObject } from 'neo-open-api';

const { data: contacts } = await xObject.query({
  xObjectApiKey: 'Contact',
  fields: ['name', 'phone', 'email'],
  page: 1,
  pageSize: 20,
  orderBy: 'id desc'
});

const { data: newContact } = await xObject.create('Contact', {
  data: {
    name: '王五',
    phone: '13700137000',
    email: 'wangwu@example.com'
  }
});

const { data: updatedContact } = await xObject.update('Contact', newContact.id, {
  data: {
    name: '王五（更新）'
  }
});

const { data: contactDetail } = await xObject.get('Contact', newContact.id);

await xObject.delete('Contact', newContact.id);
```
