hl-api-changelog/changelogs-v2/2026-06/25_4337_4349_发票列表ALL改订单视角+封面图-修改接口-管理后台.md

15 KiB

发票管理列表 - ALL 改订单视角 + 列表行新增封面图(管理后台)

  • 接口GET /v3/admin/order/invoice/page
  • 变更类型:修改接口 破坏性变更tab=ALL 列表语义 + tabCounts.ALL 计数口径均变)
  • 端类型:管理后台
  • 日期2026-06-25
  • Issue#4337
  • PR#4338ALL 改订单视角)+ #4349(行新增 productCoverImg

1 接口背景

财务发票管理列表原先以发票记录为视角。ALL tab 只返回已有发票记录的订单行,tabCounts.ALL 计数只统计发票记录总数,导致:

  • ALL 数量 < NONE未申请数量,前端展示出现矛盾
  • ALL 列表无法让财务在一个页面纵览所有已完成订单的发票状态

本次将 ALL tab 切换为订单视角:以全部 COMPLETED已完成订单为数据源,有发票的行展示发票字段,无发票的行 status=NONE,对齐前端原型设计。


2 变更清单

# 变更项 变更前 变更后
1 tabCounts.ALL 计数口径 仅统计发票记录数REQUESTED+ISSUED+PUSHED,不含未申请 统计全部 COMPLETED 订单数(含未申请),永远 >= 任何单个 tab
2 tab=ALL 列表数据源 只返回有发票记录的订单行 返回全部 COMPLETED 订单,无发票行 status=NONE
3 titleName/requestedBy 在 ALL/NONE tab 的行为 未定义(可能干扰结果) 静默忽略(两字段仅在 REQUESTED/ISSUED/PUSHED 三个发票视角 tab 生效)
4 列表行出参 productCoverImg 无此字段 新增,返回产品封面图 URL,无封面时为 null

3 接口详情

属性
方法 GET
路径 /v3/admin/order/invoice/page
描述 财务发票管理列表(分页),含 tab 计数与汇总统计
认证 Bearer JWT管理员
幂等性 只读,天然幂等
限流 无特殊限制

4 接口入参

4.1 Query 参数

参数名 类型 必填 说明
tab string 当前 tab,枚举值见第 6 节;默认 ALL
pageNo integer 页码,默认 1
pageSize integer 每页条数,默认 20
keyword string 关键词搜索(订单号 / 产品名 / 联系人),所有 tab 均生效
titleName string 发票抬头名称,仅 REQUESTED/ISSUED/PUSHED tab 生效,ALL/NONE tab 静默忽略
requestedBy string 申请人(定制师),仅 REQUESTED/ISSUED/PUSHED tab 生效,ALL/NONE tab 静默忽略
departureStartDate string 出发日期起,格式 YYYY-MM-DD
departureEndDate string 出发日期止,格式 YYYY-MM-DD

4.2 请求体

GET 接口)


5 出参字段

响应外层结构:

{
  "code": 200,
  "data": {
    "tabCounts": [...],
    "stats": [...],
    "records": [...],
    "total": 0,
    "pageNo": 1,
    "pageSize": 20
  }
}

5.1 tabCounts5 项固定顺序)

字段 类型 说明
code string tab 枚举值(见第 6 节)
name string tab 中文标签
count integer 该 tab 对应的记录数

固定顺序REQUESTED → ISSUED → PUSHED → NONE → ALL

ALL.count 语义已变:现为全部 COMPLETED 订单数(含未申请);之前仅含发票记录数。

5.2 stats4 项固定顺序)

字段 类型 说明
code string 枚举值(见第 6 节)
name string 统计项中文标签
count integer 数量
amount number 金额元,JSON number

固定顺序REQUESTED → ISSUED → PUSHED → CURRENT_MONTH_ISSUED

5.3 records 列表行InvoicePageItemRespVO

字段 类型 说明
id string 发票记录 ID雪花无发票行为 null
orderId string 订单 ID雪花
orderNo string 订单号
productName string 产品名称
productCoverImg string 产品封面图 URL新增字段);无封面时为 null
tierName string 档期名称
contactName string 联系人姓名
customizerName string 定制师姓名
departureDate string 出发日期,格式 YYYY-MM-DD
adultCount integer 成人数
childCount integer 儿童数
youngChildCount integer 婴幼儿数
invoiceType string 发票类型枚举(见第 6 节);无发票行为 null
invoiceTypeText string 发票类型中文;无发票行为 null
titleType string 抬头类型枚举(见第 6 节);无发票行为 null
titleName string 抬头名称;无发票行为 null
taxNo string 税号;无发票行为 null
amount number 发票金额(元);无发票行为 null
email string 接收邮箱;无发票行为 null
status string 发票状态枚举(见第 6 节);无发票行固定为 NONE
statusText string 发票状态中文;无发票行固定为 未申请
requestedBy string 申请人(定制师);无发票行为 null
requestedAt string 申请时间 ISO 8601;无发票行为 null
issuedAt string 开票时间 ISO 8601;无发票行为 null
issuedBy string 开票人;无发票行为 null
invoiceNo string 发票号;无发票行为 null
fileUrl string 发票文件 URL;无发票行为 null
pdfName string PDF 文件名;无发票行为 null
pdfSize string PDF 文件大小(字符串,如 128KB;无发票行为 null

6 枚举 / 数据字典

6.1 tab 枚举(查询参数 & tabCounts.code

code name 说明
REQUESTED 待开票 已申请、待财务开票
ISSUED 待推送 已开票、待推送给客户
PUSHED 已推送 已推送给客户
NONE 未申请 已完成订单但尚未申请发票
ALL 全部 订单视角:全部 COMPLETED 订单(含无发票行)

6.2 stats.code 枚举

code name
REQUESTED 待开票
ISSUED 已开票(待推送)
PUSHED 已推送
CURRENT_MONTH_ISSUED 本月已开票

6.3 发票状态枚举records.status

code statusText 说明
REQUESTED 待开票 已申请
ISSUED 待推送 已开票
PUSHED 已推送 已推送
NONE 未申请 tab=ALL/NONE 时无发票行专用

6.4 发票类型枚举invoiceType

code 说明
VAT_NORMAL 增值税普通发票
VAT_SPECIAL 增值税专用发票

6.5 抬头类型枚举titleType

code 说明
PERSONAL 个人
COMPANY 企业

7 错误码

错误码 含义 前端处理建议
200 成功 正常渲染
401 未认证 跳登录
403 无权限 提示无访问权限
500 服务端异常 通用错误提示

8 示例

8.1 典型成功——tab=ALL,混合行有发票 + 无发票)

请求

GET /v3/admin/order/invoice/page?tab=ALL&pageNo=1&pageSize=20

响应

{
  "code": 200,
  "data": {
    "tabCounts": [
      {"code": "REQUESTED", "name": "待开票", "count": 3,},
      {"code": "ISSUED",    "name": "待推送", "count": 1,},
      {"code": "PUSHED",    "name": "已推送", "count": 5,},
      {"code": "NONE",      "name": "未申请", "count": 12,},
      {"code": "ALL",       "name": "全部",   "count": 21}
    ],
    "stats": [
      {"code": "REQUESTED",            "name": "待开票",     "count": 3,  "amount": 8800.00},
      {"code": "ISSUED",               "name": "已开票",     "count": 1,  "amount": 3200.00},
      {"code": "PUSHED",               "name": "已推送",     "count": 5,  "amount": 15600.00},
      {"code": "CURRENT_MONTH_ISSUED", "name": "本月已开票", "count": 4,  "amount": 12000.00}
    ],
    "records": [
      {
        "id": "1923456789012345678",
        "orderId": "1823456789012345678",
        "orderNo": "HL20260620001",
        "productName": "云南深度游7日",
        "tierName": "2026-07-01班期",
        "contactName": "张三",
        "customizerName": "李定制",
        "departureDate": "2026-07-01",
        "adultCount": 2,
        "childCount": 1,
        "youngChildCount": 0,
        "invoiceType": "VAT_NORMAL",
        "invoiceTypeText": "增值税普通发票",
        "titleType": "COMPANY",
        "titleName": "北京科技有限公司",
        "taxNo": "91110000123456789X",
        "amount": 6800.00,
        "email": "finance@example.com",
        "status": "REQUESTED",
        "statusText": "待开票",
        "requestedBy": "李定制",
        "requestedAt": "2026-06-20T10:30:00+08:00",
        "issuedAt": null,
        "issuedBy": null,
        "invoiceNo": null,
        "fileUrl": null,
        "pdfName": null,
        "pdfSize": null
      },
      {
        "id": null,
        "orderId": "1823456789012345679",
        "orderNo": "HL20260619002",
        "productName": "西藏圣地朝圣8日",
        "tierName": "2026-06-25班期",
        "contactName": "王五",
        "customizerName": "赵定制",
        "departureDate": "2026-06-25",
        "adultCount": 4,
        "childCount": 0,
        "youngChildCount": 0,
        "invoiceType": null,
        "invoiceTypeText": null,
        "titleType": null,
        "titleName": null,
        "taxNo": null,
        "amount": null,
        "email": null,
        "status": "NONE",
        "statusText": "未申请",
        "requestedBy": null,
        "requestedAt": null,
        "issuedAt": null,
        "issuedBy": null,
        "invoiceNo": null,
        "fileUrl": null,
        "pdfName": null,
        "pdfSize": null
      }
    ],
    "total": 21,
    "pageNo": 1,
    "pageSize": 20
  }
}

8.2 边界情况——tab=ALL 传了 titleName被静默忽略

请求

GET /v3/admin/order/invoice/page?tab=ALL&titleName=北京科技&pageNo=1&pageSize=20

说明titleName 参数不参与过滤,接口正常返回全量 COMPLETED 订单分页。records 中仍会出现 status=NONE 的无发票行,响应结构与 8.1 相同,此处不重复。

8.3 业务失败——无已完成订单时 tab=ALL 返回空列表

请求

GET /v3/admin/order/invoice/page?tab=ALL&pageNo=1&pageSize=20

响应(无 COMPLETED 订单时)

{
  "code": 200,
  "data": {
    "tabCounts": [
      {"code": "REQUESTED", "name": "待开票", "count": 0},
      {"code": "ISSUED",    "name": "待推送", "count": 0},
      {"code": "PUSHED",    "name": "已推送", "count": 0},
      {"code": "NONE",      "name": "未申请", "count": 0},
      {"code": "ALL",       "name": "全部",   "count": 0}
    ],
    "stats": [
      {"code": "REQUESTED",            "name": "待开票",     "count": 0, "amount": 0},
      {"code": "ISSUED",               "name": "已开票",     "count": 0, "amount": 0},
      {"code": "PUSHED",               "name": "已推送",     "count": 0, "amount": 0},
      {"code": "CURRENT_MONTH_ISSUED", "name": "本月已开票", "count": 0, "amount": 0}
    ],
    "records": [],
    "total": 0,
    "pageNo": 1,
    "pageSize": 20
  }
}

9 业务边界

适用

  • 订单状态为 COMPLETED已完成的订单才出现在 ALL/NONE tab
  • REQUESTED/ISSUED/PUSHED 三个 tab 仍以发票记录为视角,只返回有对应状态发票的订单行

不适用

  • 进行中(未完成)订单不出现在任何 tab
  • 已取消订单不出现

特殊边界

  • ALL tab 下tabCounts.ALL.count = REQUESTED + ISSUED + PUSHED + NONE,四者无重叠
  • 同一订单只有一张有效发票记录,不会重复出现
  • titleName/requestedBy 在 ALL/NONE tab 传入后静默忽略,不报错、不影响结果
  • productCoverImg 无封面时为 null,前端需做防空处理

10 修改前后对比

字段级对比

字段 变更前 变更后
tabCounts.ALL.count 仅 REQUESTED+ISSUED+PUSHED 发票记录数之和 全部 COMPLETED 订单数(含无发票订单)
recordstab=ALL 时) 仅返回有发票记录的订单行,无 status=NONE 行 返回全部 COMPLETED 订单,无发票行 status=NONE
records[].idtab=ALL 时) 所有行均有值 无发票行为 null
records[].amounttab=ALL 时) 所有行均有值 无发票行为 null
records[].productCoverImg 无此字段 新增,产品封面图 URL,无封面为 null

tab=ALL 计数对比(假设 2 张发票 + 12 个未申请)

变更前:

ALL.count = 2   仅发票记录,ALL < NONE,矛盾
NONE.count = 12

变更后:

ALL.count = 14  = 2 + 12,ALL >= NONE,正确
NONE.count = 12

11 影响评估 / 回滚

破坏兼容性:是

  • 前端若假设 tab=ALL 列表行的 id 一定不为 null,需修改无发票行 id 为 null
  • 前端若用 id !== null 判断是否显示开票按钮,需改为判断 status 是否为 NONE
  • tabCounts.ALL.count 现在总是 >= 之前的值,若前端有基于此的断言需同步更新
  • productCoverImg 为新增字段,前端需在合适位置渲染,null 时不显示
  • stats 块不受影响,无需改动

前端同步上线:建议与本次后端部署同期上线,避免显示数据矛盾窗口期。

回滚方案:回滚后端至上一个版本 jar 即可恢复旧行为;若前端已适配新结构则需同步回滚前端。


12 注意事项

  1. 无发票行的 id 字段为 null,前端不可用 id 做有无发票判断,应改用 status 字段值是否为 NONE。
  2. amount 字段类型为 JSON number,不是字符串,渲染时直接用数值格式化。
  3. titleName/requestedBy 在 ALL/NONE tab 下静默忽略,搜索框可保留,后端不过滤,行为符合预期。
  4. stats 块不受 tab 切换影响,始终返回全局四项汇总统计,与当前 tab 无关。
  5. tabCounts 固定 5 项、顺序不变,前端可按 code 匹配或按索引渲染。
  6. productCoverImg 为 null 时,前端不显示图片占位,不报错,直接跳过渲染。

13 关联 / 联系人