1
0
forked from erp-dev/erp
Files
erpnew/docs/haobuye-api.md
2026-05-19 23:41:34 +08:00

1121 lines
24 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# API Documentation
Base URL:
```text
http://<host>:<port>
```
Response content type:
```text
application/json; charset=utf-8
```
## Authorization
所有 API 都要求固定的 `Authorization` 请求头。
配置文件:
```yaml
auth:
secret: "your-fixed-authorization-secret"
```
请求示例:
```http
Authorization: your-fixed-authorization-secret
```
说明:
- 服务端会把 `Authorization` 头的原始值与 `auth.secret` 做精确匹配
- 如果你想使用 `Bearer xxx` 风格,也可以直接把 `auth.secret` 配成完整的 `Bearer xxx`
未授权响应:
```json
{
"error": "unauthorized"
}
```
## Logging
服务端会输出两级日志:
- `WARNING`
- `ERROR`
当前会重点记录:
- 未授权访问
- 参数错误
- 数据库相关失败
- 图片查找失败
当图片不存在时,日志里会带上尝试过的完整路径,便于排查 Windows 部署目录问题。
## 1. Health Check
`GET /healthz`
用途:
- 检查 API 进程是否存活
- 检查数据库连接是否可用
成功响应:
```json
{
"ok": true
}
```
## 2. Query Records
`GET /api/v1/records`
### 2.1 增量同步模式
不传 `id_start` / `id_end` 时,接口按当前游标做增量读取:
- 条件:`ID > cursor`
- 排序:`ORDER BY ID ASC`
- 默认 `limit=100`
- 默认 `update_cursor=true`
- 如果查到数据且 `update_cursor=true`,游标推进到本次结果最后一条记录的 `ID`
- 返回结果会自动补上主表里的 `KhID`,并额外附带客户表 `dbo.B_Khzl` 的客户信息
- 返回结果会根据客户表 `KHLbID` 自动关联地区表 `dbo.B_Khlb`,并平铺返回 `area`
- 返回结果也会根据订单表 `HpID` 自动关联布料表 `dbo.B_Hpzl`,并平铺返回 `HpName`
参数:
- `update_cursor`: 可选,布尔值,默认 `true`
- `limit`: 可选,正整数,默认 `100`
示例:
```http
GET /api/v1/records
Authorization: your-fixed-authorization-secret
```
```http
GET /api/v1/records?update_cursor=false&limit=20
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"mode": "incremental",
"cursor_before": 1200,
"cursor_after": 1250,
"origin_cursor": 1000,
"last_record_id": 1250,
"updated": true,
"count": 50,
"records": [
{
"ID": 1201,
"KhID": 88,
"BianHaoID": "...",
"area": "华东地区",
"HpName": "某某布料",
"customer": {
"KhID": 88,
"KhName": "某某客户"
}
}
]
}
```
字段说明:
- `mode`: 固定为 `incremental`
- `cursor_before`: 本次请求开始前的游标
- `cursor_after`: 本次请求完成后的游标。如果 `update_cursor=false`,这里会返回本次结果最后一条记录的 ID但不会实际写入状态文件
- `origin_cursor`: 最近一次手工修改游标前的值;自动增量同步不会改它
- `last_record_id`: 本次返回结果中的最后一条记录 ID无数据时不存在
- `updated`: 本次是否实际更新了游标状态
- `count`: 返回记录数
- `records[].KhID`: 主表记录中的客户 ID
- `records[].customer`: 客户表补充信息,当前默认包含 `KhID``KhName`
- `records[].area`: 客户地区,来自 `dbo.B_Khlb``MingCheng`
- `records[].HpName`: 布料表 `dbo.B_Hpzl` 中关联到的布料名称
### 2.2 范围查询模式
传了 `id_start``id_end` 时,接口进入范围查询模式:
- 条件:`ID >= id_start AND ID <= id_end`
- 排序:`ORDER BY ID ASC`
- 不会更新游标
- 必须显式传 `update_cursor=false`
参数:
- `id_start`: 必填,非负整数
- `id_end`: 必填,非负整数
- `update_cursor`: 必填,且必须为 `false`
- `limit`: 可选,正整数,默认 `100`
示例:
```http
GET /api/v1/records?id_start=2000&id_end=2100&update_cursor=false
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"mode": "range",
"cursor_before": 1250,
"cursor_after": 1250,
"origin_cursor": 1000,
"last_record_id": 2050,
"updated": false,
"count": 51,
"id_start": 2000,
"id_end": 2100,
"records": [
{
"ID": 2000,
"BianHaoID": "..."
}
]
}
```
### 2.3 参数校验规则
- `limit` 必须大于 0
- `id_start``id_end` 必须同时出现
- `id_start``id_end` 必须是非负整数
- `id_start` 不能大于 `id_end`
- 范围查询模式必须显式传 `update_cursor=false`
## 3. Query Current Order Snapshot
`GET /api/v1/records/by-order`
用途:
-`external_order_id` 精确查询当前整单快照
- 返回该 `BianHaoID` 下当前全部 records
- 不读取 cursor也不推进 cursor
- 返回字段会继续附带现有的 `customer``area``HpName`
参数:
- `external_order_id`: 必填,字符串,精确对应主表 `D_KhDhd.BianHaoID`
示例:
```http
GET /api/v1/records/by-order?external_order_id=KD20432358
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"mode": "snapshot",
"external_order_id": "KD20432358",
"status": "active",
"snapshot_at": "2026-04-16T10:12:34Z",
"total_count": 3,
"records": [
{
"ID": 1000001,
"BianHaoID": "KD20432358",
"KhID": "KH00999",
"HpName": "120克本白四面弹单定",
"area": "周边",
"customer": {
"KhID": "KH00999",
"KhName": "鸿烨服饰"
}
}
]
}
```
字段说明:
- `mode`: 固定为 `snapshot`
- `external_order_id`: 当前查询的订单号
- `status`: 当前快照状态;查询命中时固定为 `active`
- `snapshot_at`: 服务端生成本次快照响应的时间
- `total_count`: 当前订单快照下 records 数量
- `records`: 当前订单下的全部 records字段宽度与现有 `GET /api/v1/records` 保持一致
未命中响应示例:
```json
{
"external_order_id": "KD20432358",
"status": "not_found",
"message": "未找到该 external_order_id 对应的订单"
}
```
## 4. Query Customer Orders
`GET /api/v1/records/by-customer`
用途:
- 按客户名精确查询该客户名下全部订单
- 底层先查询 `D_KhDhd` 明细,再按 `BianHaoID` 聚合为订单主体
- 每个订单主体下的明细结构与现有 `GET /api/v1/records/by-order` 完全一致
- 不读取 cursor也不推进 cursor
- 结果按配置项 `customer_orders.sort_column` 倒序排列,默认 `KdRiQi`
参数:
- `customer_name_b64`: 必填,客户名的 Base64URL 编码;精确匹配客户表 `dbo.B_Khzl.KhName`
示例:
```http
GET /api/v1/records/by-customer?customer_name_b64=6bi_54OI5pyN6aWw
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"mode": "customer_orders",
"customer_name": "鸿烨服饰",
"status": "active",
"snapshot_at": "2026-05-09T10:12:34Z",
"total_orders": 2,
"orders": [
{
"mode": "snapshot",
"external_order_id": "KD20432358",
"status": "active",
"snapshot_at": "2026-05-09T10:12:34Z",
"total_count": 2,
"records": [
{
"ID": 1000001,
"BianHaoID": "KD20432358",
"KhID": "KH00999",
"HpName": "120克本白四面弹单定",
"area": "周边",
"customer": {
"KhID": "KH00999",
"KhName": "鸿烨服饰"
}
}
]
}
]
}
```
字段说明:
- `mode`: 固定为 `customer_orders`
- `customer_name`: 当前查询的客户名
- `status`: 查询命中时固定为 `active`
- `snapshot_at`: 服务端生成本次响应的时间
- `total_orders`: 当前客户名下聚合后的订单数
- `orders`: 订单列表;每个订单元素的结构与 `GET /api/v1/records/by-order` 返回结构保持一致
未命中响应示例:
```json
{
"customer_name": "鸿烨服饰",
"status": "not_found",
"message": "未找到该 customer_name 对应的订单"
}
```
配置:
```yaml
customer_orders:
sort_column: "KdRiQi"
```
- `sort_column` 用于控制订单聚合结果的排序字段,默认值为 `KdRiQi`
## 5. Query Customer List
`GET /api/v1/customers`
用途:
- 按客户主档表 `dbo.B_Khzl` 拉取客户列表
- 每次固定返回 `10` 个客户
- 只返回 `KhID``KhName`
- 用于外部系统按客户维度做同步
- 使用游标参数 `cursor_id` 续拉,不使用 `page` / `pageSize`
排序与游标规则:
- 底层按 `ZZRQ ASC, KhID ASC` 排序
- `ZZRQ` 越早的客户越先返回,避免从新到旧翻页时遗漏新数据
- `cursor_id` 传上一页最后一条客户的 `KhID`
- 服务端会先查出该 `KhID` 对应的 `ZZRQ`,再从 `(ZZRQ, KhID)` 这个排序位置之后继续取下一批 `10`
- 如果多个客户 `ZZRQ` 相同,会继续用 `KhID` 做稳定次序
参数:
- `cursor_id`: 可选,上一页最后一条客户的 `KhID`
示例:
```http
GET /api/v1/customers
Authorization: your-fixed-authorization-secret
```
```http
GET /api/v1/customers?cursor_id=KH01485
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"mode": "customers",
"cursor_id": "KH01485",
"next_cursor_id": "KH01495",
"snapshot_at": "2026-05-14T15:00:00Z",
"count": 10,
"customers": [
{
"customer_id": "KH01486",
"customer_name": "A亿佳服饰"
}
]
}
```
字段说明:
- `mode`: 固定为 `customers`
- `cursor_id`: 本次请求使用的游标;首批为空
- `next_cursor_id`: 本页最后一条客户的 `KhID`;下一页继续传它即可
- `snapshot_at`: 服务端生成本次响应的时间
- `count`: 当前返回客户数,最大固定为 `10`
- `customers[].customer_id`: 客户 ID对应 `dbo.B_Khzl.KhID`
- `customers[].customer_name`: 客户名称,对应 `dbo.B_Khzl.KhName`
未命中游标响应示例:
```json
{
"cursor_id": "KH99999",
"status": "not_found",
"message": "未找到该 cursor_id 对应的客户"
}
```
## 6. Query I_Sale Records By BianHaoID
`GET /api/v1/i-sale/by-bianhao`
用途:
-`BianHaoID` 查询 `dbo.I_Sale` 中的业务明细记录
- 为收款和退款记录补充对应业务单据的信息
- 返回 `I_Sale` 的全量字段
- 不读取 cursor也不推进 cursor
注意:
- 同一个 `BianHaoID``I_Sale` 中可能命中多条明细行
- 因此该接口返回的是 `records[]`,不是单对象详情
参数:
- `bianhao_id`: 必填,精确匹配 `dbo.I_Sale.BianHaoID`
示例:
```http
GET /api/v1/i-sale/by-bianhao?bianhao_id=XT20203911
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"mode": "i_sale_records",
"bianhao_id": "XT20203911",
"status": "active",
"snapshot_at": "2026-05-14T15:10:00Z",
"total_count": 1,
"records": [
{
"BianHaoID": "XT20203911",
"DanType": "客户退货单",
"KhID": "KH01204"
}
]
}
```
字段说明:
- `mode`: 固定为 `i_sale_records`
- `bianhao_id`: 当前查询的业务单号
- `status`: 查询命中时固定为 `active`
- `snapshot_at`: 服务端生成本次响应的时间
- `total_count`: 当前 `BianHaoID` 命中的 `I_Sale` 明细行数
- `records`: `I_Sale` 全量字段明细列表
未命中响应示例:
```json
{
"bianhao_id": "XT404",
"status": "not_found",
"message": "未找到该 bianhao_id 对应的 I_Sale 记录"
}
```
## 7. Query I_Sale Records By Customer
`GET /api/v1/i-sale/by-customer`
用途:
- 按客户 ID 查询 `dbo.I_Sale` 中的业务明细记录
- 用于补足按客户统计时对 `I_Sale` 的直接拉取能力
- 不分页、不使用游标;一次返回当前客户在指定分类下的全部命中记录
- 返回字段不是 `I_Sale` 全 119 列,而是“核心标识 + 全部金额字段 + 全部数量字段 + 备注字段”
当前分类策略:
- `sale`:只取 `DanType = '成品销售单' AND BianHaoID LIKE 'XS%'`
- `sale_return`:只取 `DanType = '客户退货单' AND BianHaoID LIKE 'XT%'`
当前实现决策:
- 用户明确接受低频调用,因此本接口不做分页和游标
- 但为了避免把 `I_Sale` 全 119 列直接暴露给同步方,当前只返回与统计/业务核对最相关的字段组
- 该字段组已结合项目内 `I_SALE_FIELD_ANALYSIS.md` 与线上 `db/columns` 验证
参数:
- `customer_id`: 必填,精确匹配 `dbo.I_Sale.KhID`
- `category`: 必填,当前只支持 `sale``sale_return`
示例:
```http
GET /api/v1/i-sale/by-customer?customer_id=KH00308&category=sale
Authorization: your-fixed-authorization-secret
```
```http
GET /api/v1/i-sale/by-customer?customer_id=KH00308&category=sale_return
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"mode": "i_sale_customer_records",
"customer_id": "KH00308",
"category": "sale",
"status": "active",
"snapshot_at": "2026-05-14T20:00:00Z",
"total_count": 2,
"records": [
{
"SubID": 1,
"BianHaoID": "XS20367431",
"DanType": "成品销售单",
"KhID": "KH00308",
"RiQi": "2026-05-14T00:00:00Z",
"KdRiQi": "2026-05-14T19:08:23Z",
"JieSunFS": "欠款",
"HpID": "HP00001",
"JianShu": "1.00",
"ShuLiang": "20.00",
"ShuLiangT": "20.00",
"DanJia": "32.000000",
"JinE": "640.000000",
"DingJin": "0.00",
"YfJinE": "0.00",
"SfJinE": "0.00",
"ZkJinE": "0.00",
"LjQK": "0.00",
"BeiZhu": "",
"BeiZhuC": "",
"BeiZhuD": "",
"MeoD": "普通单据"
}
]
}
```
字段说明:
- `mode`: 固定为 `i_sale_customer_records`
- `customer_id`: 当前查询的客户 ID
- `category`: 当前查询的分类
- `status`: 查询命中时固定为 `active`
- `snapshot_at`: 服务端生成本次响应的时间
- `total_count`: 当前客户在该分类下命中的 `I_Sale` 明细行数
- `records`: 当前字段集包含以下几类字段
核心标识字段:
- `SubID`
- `BianHaoID`
- `DanType`
- `KhID`
- `RiQi`
- `KdRiQi`
- `JieSunFS`
- `HpID`
- `JiJiaDW`
数量相关字段:
- `JianShu`
- `ShuLiang`
- `ShuLiangZ`
- `ShuLiangK`
- `ShuLiangS`
- `JianShuT`
- `ShuLiangT`
- `ShuLiangZT`
- `ShuLiangKT`
- `ShuLiangST`
- `Sl1` ~ `Sl10`
金额相关字段:
- `DingJin`
- `YfJinE`
- `SfJinE`
- `ZkJinE`
- `LjQK`
- `DanJia`
- `JinE`
- `DanJiaT`
- `JinET`
- `DanJiaCB`
- `JinECB`
- `JinE_SL`
备注相关字段:
- `BeiZhu`
- `BeiZhuC`
- `BeiZhuD`
- `MeoA`
- `MeoB`
- `MeoC`
- `MeoD`
未命中响应示例:
```json
{
"customer_id": "KH00308",
"category": "sale",
"status": "not_found",
"message": "未找到该 customer_id 和 category 对应的 I_Sale 记录"
}
```
参数错误:
- `customer_id` 为空时返回 `400`
- `category``sale` / `sale_return` 时返回 `400`
## 7. Query Customer Finance Records
`GET /api/v1/finance/by-customer`
用途:
- 按客户名精确查询该客户名下的财务记录
- 当前销售/销退只认 `dbo.I_Sale`
- 当前收款/退款只认 `dbo.F_Skd`
- 支持按记录类型筛选,并支持控制是否包含真实资金变动、是否包含挂账/欠款调整
- 不读取 cursor也不推进 cursor
参数:
- `customer_name_b64`: 必填,客户名的 Base64URL 编码;精确匹配客户表 `dbo.B_Khzl.KhName`
- `record_types`: 可选,逗号分隔;支持 `sale``sale_return``receipt``refund`;不传默认全部
- `include_cash_movement`: 可选,布尔值;默认 `true`
- `include_adjustments`: 可选,布尔值;默认 `false`
- `filter_sk`: 可选,布尔值;默认 `false`;当前 `receipt` 口径下保留该参数但不生效
当前口径:
- `sale`: `I_Sale.DanType = '成品销售单'`
- `sale_return`: `I_Sale.DanType = '客户退货单'`
- `receipt`: 仅纳入 `F_Skd.BianHaoID LIKE 'SK%'` 的收款流水,不纳入 `XS%` 记录
- `refund`: `F_Skd.sType = 1 AND F_Skd.BianHaoID LIKE 'XT%'`
- `receipt` 的返回金额字段仍保留 `F_Skd.FkJinE``F_Skd.ZkJinE` 等原始值,但当前口径不再使用 `FkJinE` 作为筛选条件
- `refund` 的统计和筛选金额字段为 `F_Skd.YfJinE`
- `include_cash_movement``include_adjustments` 当前仅影响 `refund``receipt` 统一按 `SK%` 全量统计
- `include_cash_movement=true` 时,`refund``YfJinE < 0`
- `include_adjustments=true` 时,`refund` 额外包含 `YfJinE = 0` 的挂账/欠款调整记录
当前已验证的 `sType` 规则:
- `sType = 1`:当前财务 API 使用的业务单据关联流水,样本中覆盖 `XS...``XT...`
- `sType = 0`:当前样本对应 `SK...` 型独立收款流水;当前 `receipt` 查询会纳入它,`refund` 不会
示例:
```http
GET /api/v1/finance/by-customer?customer_name_b64=6bi_54OI5pyN6aWw&record_types=sale,receipt,refund&include_cash_movement=true&include_adjustments=false
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"mode": "customer_finance",
"customer_name": "鸿烨服饰",
"customer_ids": [
"KH00999"
],
"record_types": [
"sale",
"receipt",
"refund"
],
"include_cash_movement": true,
"include_adjustments": false,
"status": "active",
"snapshot_at": "2026-05-10T21:30:00Z",
"total_count": 3,
"sales_count": 1,
"sale_returns_count": 0,
"receipts_count": 1,
"refunds_count": 1,
"sales": [
{
"BianHaoID": "XS20366749",
"DanType": "成品销售单",
"KhID": "KH00999"
}
],
"sale_returns": [],
"receipts": [
{
"BianHaoID": "XS20215718",
"FkJinE": "378.00",
"JieSunFS": "微信"
}
],
"refunds": [
{
"BianHaoID": "XT20200743",
"YfJinE": "-2201.00",
"FkJinE": "0.00",
"JieSunFS": "微信"
}
]
}
```
未命中响应示例:
```json
{
"customer_name": "鸿烨服饰",
"status": "not_found",
"message": "未找到该 customer_name 对应的财务记录"
}
```
参数错误示例:
```json
{
"error": "record_types contains unsupported value"
}
```
## 6. Database Inspect Permission Check
`GET /api/v1/db/permissions`
用途:
- 检查当前数据库账号是否具备数据库分析所需的基础能力
- 尝试验证数据库连接、获取当前库名、列出可见表、读取字段元数据、读取 `sys` 元数据、检查 `VIEW DEFINITION`、以及对所有可见表执行 `SELECT TOP (1)`
- 返回总体是否可用,以及各项检查结果
配置开关:
```yaml
db_inspect:
enabled: true
```
成功响应示例:
```json
{
"can_inspect": true,
"database_name": "RCYH2020",
"visible_table_count": 32,
"checks": [
{
"name": "database_connection",
"ok": true
},
{
"name": "list_base_tables",
"ok": true
},
{
"name": "read_all_visible_table_columns",
"ok": true
},
{
"name": "select_top_1_from_all_visible_tables",
"ok": true
}
]
}
```
字段说明:
- `can_inspect`: 是否满足数据库分析所需的整体权限和可读能力
- `database_name`: 当前连接到的数据库名
- `visible_table_count`: 当前账号可见的基础表数量
- `checks`: 分项检查结果
- `failed_column_tables`: 无法读取字段元数据的表清单,仅检查失败时出现
- `failed_select_tables`: 无法执行 `SELECT TOP (1)` 的表清单,仅检查失败时出现
## 7. List Database Tables
`GET /api/v1/db/tables`
用途:
- 返回当前数据库中当前账号可见的所有基础表
成功响应示例:
```json
{
"count": 2,
"tables": [
{
"schema": "dbo",
"name": "D_KhDhd",
"full_name": "dbo.D_KhDhd"
},
{
"schema": "dbo",
"name": "B_Khzl",
"full_name": "dbo.B_Khzl"
}
]
}
```
## 8. List Table Columns
`GET /api/v1/db/columns`
参数:
- `table`: 必填,表名,格式为 `schema.table``db.schema.table`
用途:
- 返回指定表的字段列表
- 返回字段名、类型、是否可空、长度、精度、顺序等信息
示例:
```http
GET /api/v1/db/columns?table=dbo.D_KhDhd
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"table": "dbo.D_KhDhd",
"count": 2,
"columns": [
{
"name": "ID",
"data_type": "int",
"nullable": false,
"ordinal_position": 1
},
{
"name": "BianHaoID",
"data_type": "nvarchar",
"nullable": true,
"max_length": 50,
"ordinal_position": 2
}
]
}
```
## 9. Generic Table Select
`GET /api/v1/db/select`
参数:
- `table`: 必填,表名,格式为 `schema.table``db.schema.table`
- `columns`: 必填,逗号分隔的字段名列表,例如 `ID,BianHaoID`
- `where`: 可选,受限条件表达式;支持 `=` `!=` `<>` `>` `>=` `<` `<=` `LIKE` `IS NULL` `IS NOT NULL`,多个条件只支持用 `AND` 连接;字符串字面量必须写成单引号,例如 `DanType = '客户退货单'`
- `limit`: 可选,正整数;不传时使用默认值,并受服务端上限限制
用途:
- 对指定表执行通用只读查询
- 仅返回请求中指定的字段集合
- 当前实现固定为 `SELECT TOP (limit)`,支持受限 `WHERE`,不支持自定义 SQL
示例:
```http
GET /api/v1/db/select?table=dbo.D_KhDhd&columns=ID,BianHaoID&limit=10
Authorization: your-fixed-authorization-secret
```
```http
GET /api/v1/db/select?table=dbo.I_Sale&columns=BianHaoID,DanType,ShuLiang&where=DanType%20%3D%20%27%E5%AE%A2%E6%88%B7%E9%80%80%E8%B4%A7%E5%8D%95%27%20AND%20ShuLiang%20%3C%200&limit=10
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"table": "dbo.D_KhDhd",
"columns": [
"ID",
"BianHaoID"
],
"count": 2,
"rows": [
{
"ID": 1001,
"BianHaoID": "KD20432358"
},
{
"ID": 1002,
"BianHaoID": "KD20432359"
}
]
}
```
参数错误示例:
```json
{
"error": "where is invalid"
}
```
当配置关闭时:
```json
{
"error": "db inspect api is disabled"
}
```
## 10. Get Current Cursor
`GET /api/v1/cursor`
用途:
- 查看当前游标值
- 查看最近一次人工修改游标前的 `origin_cursor`
示例:
```http
GET /api/v1/cursor
Authorization: your-fixed-authorization-secret
```
成功响应示例:
```json
{
"cursor": 1500,
"origin_cursor": 1250
}
```
## 11. Set Cursor
`POST /api/v1/cursor/set`
用途:
- 人工把游标改到指定值
- 每次手工修改时,都会把修改前的游标保存到 `origin_cursor`
请求体:
```json
{
"value": 1500
}
```
规则:
- `value` 必须是非负整数
- 调用成功后:
- `cursor` 更新为 `value`
- `origin_cursor` 保存修改前的 `cursor`
请求示例:
```http
POST /api/v1/cursor/set
Authorization: your-fixed-authorization-secret
Content-Type: application/json
{
"value": 1500
}
```
成功响应示例:
```json
{
"cursor_before": 1250,
"cursor_after": 1500,
"origin_cursor": 1250,
"updated": true
}
```
## 12. Get Image
`GET /api/v1/image`
用途:
- 根据给定文件名,从配置的图片目录读取对应文件
- 找到后返回图片内容的 Base64 字符串
- 找不到时返回 `404`
配置文件:
```yaml
image:
directory: "./images"
```
参数:
- `name`: 可选,原始文件名,必须是纯文件名,不能包含路径
- `name_b64`: 可选,文件名的 Base64URL 编码;当文件名包含 `#` 等 URL 特殊字符时推荐使用
- 如果 `name` 不带后缀,服务端会按 `.jpg``.png` 的顺序自动尝试
说明:
- `name``name_b64` 二选一即可
- 如果文件名里包含 `#`,很多客户端会在真正发请求前把它后面的内容当作 URL fragment 截掉,因此推荐使用 `name_b64`
示例:
```http
GET /api/v1/image?name=test
Authorization: your-fixed-authorization-secret
```
```http
GET /api/v1/image?name_b64=YWJjIzEyMw
Authorization: your-fixed-authorization-secret
```
上面的 `name_b64=YWJjIzEyMw` 对应原始文件名:
```text
abc#123
```
成功响应示例:
```json
{
"name": "test.jpg",
"content_type": "image/jpeg",
"data": "/9j/4AAQSkZJRgABAQ..."
}
```
错误响应示例:
```json
{
"error": "image not found"
}
```
说明:
- `data` 是图片二进制内容的 Base64 编码
- `content_type` 会优先根据文件扩展名推断,推断不出来时会回退到内容检测
- 如果 `name` 没有后缀,会优先查找 `name.jpg`,找不到再查 `name.png`
- 如果文件名中含有 `#`、空格等特殊字符,优先使用 `name_b64`
- 为了安全,`name` 不能带目录分隔符,也不能包含 `..`
## 13. Cursor State File
默认文件:
```text
./data/cursor-state.json
```
文件内容示例:
```json
{
"cursor": 1500,
"origin_cursor": 1250
}
```
说明:
- `cursor`: 当前增量同步游标
- `origin_cursor`: 最近一次人工修改游标前的值