---
schema: "hl-changelog/v2"
ticket: "5429"
title: "核单门票/游玩统一资源日期价格下拉"
consumer: "admin"
author: "yst"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@0a8a72ed6a978a9f14187679188f4c8308e354cd"
target_release: ""
verified_at: ""
status_note: "hl-resource-service；PR #5528 与补丁 PR #5534 已合并并部署测试服，Gateway 真实验收通过；等待管理后台接入。"
updated_at: "2026-08-05"
base: "dev-v3"
---

# 【✨ 新增接口·管理后台】核单门票/游玩统一资源日期价格下拉（#5429）

> **PR**: [#5528](https://git.1814.love:8443/wx/HL/pulls/5528)、[#5534](https://git.1814.love:8443/wx/HL/pulls/5534)
> **服务**: hl-resource-service
> **更新时间**: 2026-08-05

## 1. 接口背景

管理后台核单 Step 2 新增门票/游玩项目时，需要在同一个分页结果中搜索景区和游玩项目，并按实际游玩日期取得协议价、结算价和建议核算单价。该接口统一返回两类资源；即使当天未配置价格，也仍可返回资源供人工核单。

## 变更接口

| # | 接口名 | 方法 | 路径 | 变更类型 | 说明 |
|---|--------|------|------|----------|------|
| 1 | 分页查询门票/游玩资源选项 | GET | `/admin/resource-options/ticket-items` | 新增接口 | 按游玩日期统一查询景区和游玩项目，并返回资源级日期价格 |

## 3. 接口详情

- **使用场景**：核单 Step 2 新增或搜索实际发生的门票/游玩项目。
- **认证**：需要有效的管理后台 JWT，使用 `Authorization: Bearer <token>`。
- **幂等性**：幂等，只读查询。
- **限流**：无接口专属限流约定。
- **响应类型**：`Result<PageResult<TicketResourceOptionRespVO>>`。
- **请求体**：无。

## 4. 接口入参

### 4.1 Query 参数

| 字段 | 类型 | 必填 | 默认值 | 校验规则 | 说明 |
|------|------|------|--------|----------|------|
| `dayDate` | String | 是 | 无 | ISO 日期 `yyyy-MM-dd` | 实际游玩日期；价格字段只匹配这一天的资源价格 |
| `keyword` | String | 否 | `null` | 最长 100 个字符 | 资源名称模糊搜索；自动去除首尾空格；去除后为空等同未传 |
| `resourceType` | String | 否 | `null` | `SCENIC` 或 `ACTIVITY` | 不传时同时查询景区和游玩项目 |
| `status` | Integer | 否 | `null` | `0` 或 `1` | 不传时同时包含已启用和已下架资源 |
| `page` | Integer | 否 | `1` | 最小值 1 | 当前页码 |
| `pageSize` | Integer | 否 | `20` | 1～100 | 每页条数 |

### 4.2 请求体字段

无请求体。

## 5. 出参字段

### 5.1 统一响应与分页字段

| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `code` | Integer | 否 | 业务状态码；成功为 `200` |
| `message` | String | 否 | 响应消息；成功为 `成功` |
| `success` | Boolean | 否 | `code == 200` 时为 `true` |
| `traceId` | String | 是 | 链路追踪 ID |
| `data` | Object | 否 | 分页结果 |
| `data.records` | Array | 否 | 本页资源列表；无匹配资源时为 `[]` |
| `data.total` | Integer | 否 | 符合条件的资源总数 |
| `data.page` | Integer | 否 | 当前页码 |
| `data.pageSize` | Integer | 否 | 每页条数 |

### 5.2 `data.records[]` 资源字段（完整 13 项）

| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `resourceType` | String | 否 | 资源类型：`SCENIC` 景区、`ACTIVITY` 游玩项目 |
| `resourceId` | String | 否 | 资源 ID；固定按 JSON String 返回，不要转换为 JavaScript `Number` |
| `resourceName` | String | 否 | 资源名称；名称为 `null`、空字符串或纯空白的资源不会返回 |
| `status` | Integer | 否 | `0` 已下架、`1` 已启用 |
| `statusName` | String | 否 | 与 `status` 对应：`已下架` 或 `已启用` |
| `city` | String | 是 | 城市；景区优先返回城市名称；允许 `null` 或空字符串 |
| `settleType` | String | 是 | 结算方式：`cash`、`sign`、`company`；资源未配置时可为 `null` |
| `dayDate` | String | 否 | 本次查询的实际游玩日期，格式 `yyyy-MM-dd` |
| `protocolPrice` | Decimal | 是 | 该日期的协议价；未配置时为 `null` |
| `settlementPrice` | Decimal | 是 | 该日期的结算价；未配置时为 `null` |
| `ticketUnitPrice` | Decimal | 是 | 建议核算单价：优先取结算价，结算价为空时回退协议价；两者都为空时为 `null` |
| `priceConfigured` | Boolean | 否 | `ticketUnitPrice` 非空时为 `true`，否则为 `false` |
| `specName` | String | 否 | 固定返回 `成人票` |

## 6. 枚举 / 数据字典

### 6.1 `resourceType`

**所属字段**：Query `resourceType`、响应 `data.records[].resourceType`
**类型**：String

| 值 | 中文 | 说明 |
|----|------|------|
| `SCENIC` | 景区 | 来源为景区资源 |
| `ACTIVITY` | 游玩项目 | 来源为活动/游玩项目资源 |

### 6.2 `status` / `statusName`

**所属字段**：Query `status`、响应 `data.records[].status/statusName`

| `status` | `statusName` | 说明 |
|----------|--------------|------|
| `1` | `已启用` | 排序时优先返回；可用于当前资源选择 |
| `0` | `已下架` | 默认查询仍会返回，满足事后核单；传 `status=1` 可排除 |

### 6.3 `settleType`（字典 `resource_settle_type`）

**所属字段**：响应 `data.records[].settleType`
**类型**：String / null

| 值 | 中文 | 说明 |
|----|------|------|
| `cash` | 现付 | 资源结算方式为现付 |
| `sign` | 签单 | 资源结算方式为签单 |
| `company` | 公司付款 | 资源结算方式为公司付款 |

### 6.4 价格字段关系

| 条件 | `ticketUnitPrice` | `priceConfigured` |
|------|-------------------|-------------------|
| `settlementPrice` 非空 | 取 `settlementPrice` | `true` |
| `settlementPrice` 为空、`protocolPrice` 非空 | 取 `protocolPrice` | `true` |
| 两个价格都为空 | `null` | `false` |

## 7. 错误码

| code | 含义 | 触发场景 |
|------|------|----------|
| `200` | 成功 | 查询完成；没有匹配资源时仍为成功，`records=[]` |
| `400` | 参数校验失败 | 缺少/无法解析 `dayDate`，`keyword` 超过 100 字符，`resourceType` 非法，`status` 非 0/1，或分页参数越界 |
| `401` | 未认证或认证失效 | 未携带有效的管理后台 JWT |
| `500` | 系统异常 | 查询过程发生未预期异常 |

## 8. 示例

### 8.1 典型成功：同时返回景区和游玩项目

**请求**：

```http
GET /admin/resource-options/ticket-items?dayDate=2026-08-03&keyword=体验&page=1&pageSize=20
Authorization: Bearer <admin-token>
```

无请求体。

**响应**：

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "records": [
      {
        "resourceType": "SCENIC",
        "resourceId": "2079454953641836546",
        "resourceName": "草原景区体验区",
        "status": 1,
        "statusName": "已启用",
        "city": "呼伦贝尔市",
        "settleType": "sign",
        "dayDate": "2026-08-03",
        "protocolPrice": 100.00,
        "settlementPrice": 88.00,
        "ticketUnitPrice": 88.00,
        "priceConfigured": true,
        "specName": "成人票"
      },
      {
        "resourceType": "ACTIVITY",
        "resourceId": "2079454953641836550",
        "resourceName": "骑马体验",
        "status": 0,
        "statusName": "已下架",
        "city": null,
        "settleType": "cash",
        "dayDate": "2026-08-03",
        "protocolPrice": 66.00,
        "settlementPrice": null,
        "ticketUnitPrice": 66.00,
        "priceConfigured": true,
        "specName": "成人票"
      }
    ],
    "total": 2,
    "page": 1,
    "pageSize": 20
  },
  "traceId": "a1b2c3d4-e5f6-7890",
  "success": true
}
```

### 8.2 边界情况：当天无价格

**请求**：

```http
GET /admin/resource-options/ticket-items?dayDate=2026-12-31&resourceType=SCENIC&status=1&page=1&pageSize=20
Authorization: Bearer <admin-token>
```

无请求体。

**响应**：

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "records": [
      {
        "resourceType": "SCENIC",
        "resourceId": "2079454953641836548",
        "resourceName": "免费公园",
        "status": 1,
        "statusName": "已启用",
        "city": "拉萨市",
        "settleType": null,
        "dayDate": "2026-12-31",
        "protocolPrice": null,
        "settlementPrice": null,
        "ticketUnitPrice": null,
        "priceConfigured": false,
        "specName": "成人票"
      }
    ],
    "total": 1,
    "page": 1,
    "pageSize": 20
  },
  "traceId": "b2c3d4e5-f6a7-8901",
  "success": true
}
```

### 8.3 业务失败：缺少游玩日期

**请求**：

```http
GET /admin/resource-options/ticket-items?page=1&pageSize=20
Authorization: Bearer <admin-token>
```

无请求体。

**响应**：

```json
{
  "code": 400,
  "message": "游玩日期不能为空",
  "data": null,
  "traceId": "c3d4e5f6-a7b8-9012",
  "success": false
}
```

## 9. 业务边界

- 默认统一查询 `SCENIC` 与 `ACTIVITY`，`total` 是两类资源合并后的总数，不是分别分页后相加。
- 默认同时包含已启用和已下架资源；结果按“已启用优先 → 名称升序 → 资源类型升序 → 资源 ID 升序”稳定排序。
- 软删除资源不返回；资源名称为 `null`、空字符串或纯空白时也不返回，且不会计入 `total`。
- `keyword` 只匹配资源名称；不会匹配城市或资源 ID。
- 当天没有价格不会排除资源；此时允许人工核单，价格字段按第 6.4 节返回。
- 页码超过最后一页时，返回 `code=200`、`records=[]`，`total` 仍为符合条件的总数。
- `city` 和 `settleType` 是可空字段，不能作为能否选择资源的判断条件。

## 验证证据

- PR #5528 与补丁 PR #5534 已合并到 `dev-v3`。
- `hl-resource-service` 已部署测试服，经 Gateway 真实 HTTP 验收；补丁后全页扫描 121 条资源，空名称记录为 0，`resourceId` 按 String 返回。

## 10. 影响评估

- **是否破坏向后兼容**：否；这是新增只读接口，不改变已有接口。
- **前端是否必须同步上线**：否；后端上线后前端可按需接入。
- **ID 类型要求**：`resourceId` 必须始终按 String 保存和传递。

## 11. 注意事项

- 选择行的核算单价使用 `ticketUnitPrice`，不要在前端重新实现结算价/协议价优先级。
- `priceConfigured=false` 不代表资源不可选，只表示该游玩日期没有可自动带出的价格。
- 不要根据 `city` 是否为空过滤资源。
- 不要在前端把两个资源类型拆成两次请求再自行合并分页；本接口已经提供统一分页和 `total`。

## 12. 关联 / 联系人

### 12.1 链接

- **Issue**: [#5429](https://git.1814.love:8443/wx/HL/issues/5429)
- **功能 PR**: [#5528](https://git.1814.love:8443/wx/HL/pulls/5528)
- **功能 Merge commit**: [5ab2fb780](https://git.1814.love:8443/wx/HL/commit/5ab2fb7802772f99af9ee2715bb921e502a6f07b)
- **补丁 PR**: [#5534](https://git.1814.love:8443/wx/HL/pulls/5534)
- **补丁 Merge commit**: [87e8a96ba](https://git.1814.love:8443/wx/HL/commit/87e8a96ba16cbc505092562c7fae0f9e88984a5a)

### 12.2 联系人

- **后端负责人**: @yst

## 关联/联系人

### 链接

- [后端工单 #5429](https://git.1814.love:8443/wx/HL/issues/5429)

### 联系人

- **后端负责人**: @yst
