# 格物开放 API · 企业采购
# 由生成脚本输出，接口事实逐条取自 apps/api-hub/app/open 下各 route.ts 与 packages/commerce。
# 文档页：https://open.gowu.net/ （或 www.gowu.net/open）
openapi: 3.0.3
info:
  title: 格物开放 API · 企业采购
  version: 1.0.0
  description: >-
    **场景：企业采购**（交易模式：企业额度，或员工付现金）。给自己公司搭采购应用：企业把采购额度发给采购人员、按部门做预算，员工用企业额度下单（企业也可以配置为员工自己付现金），企业统一结算开票。与员工福利购物是同一套企业额度与接口：界面上请叫「企业额度」，接口字段仍是
    `points`；不含福豆任务、签到与生日福利。终端用户自带账号体系。只含该场景开通的接口，与审批默认给的权限一致。


    **接入流程**：在开发者控制台申请正式接入并录入企业信息 → 平台审核：开通接口权限、建好企业并开通交易（开通前下单返回 `ORG_EGP_NOT_READY`）→
    企业预充值或授信，平台按约定配置付款方式（全额由企业额度支付，或员工在企业购收银台付现金：支付宝 / 微信 / 对公）→ 你的服务端 `GET /v1/partner/orgs` 查到企业、`PUT
    /v1/partner/orgs/{orgId}/members/{userId}` 把你的用户绑成员工（userId 即 x-open-user）→ 管理员 `POST /v1/enterprise/org/points`
    发放额度 → 员工下单：`payWith: "auto"` 按企业配置付款（要付现金时先让员工从结算预览的 `cash.payTypes` 选 `payType`，下单返回 `launchUrl`，员工付完后平台结清，以订单详情的
    `mixedPay.status` 为准）。


    `x-open-user` 放员工在你系统里的用户 ID（即绑定时的 userId）。金额单位：额度 100 = 1 元，商品与订单金额为元。


    标了「可选」的接口（站内信、专区、搜索联想、部门与预算、消费记录、购物车）按需接入。


    ## 鉴权与签名（v2）


    所有请求带 `x-app-key`。为 appKey 配置 `app_secret` 后，该 appKey 的**所有**请求都要签名：

    带 `x-timestamp`（Unix 秒，±300 秒内有效）、`x-nonce`（每次请求一个随机串）、`x-sign-version: 2` 与 `x-signature`。


    签名串为下面八段用 `\n` 连接：


    1. `OCP-SIGN-V2`（固定字符串）

    2. 时间戳（同 x-timestamp）

    3. nonce（同 x-nonce）

    4. 请求方法，大写

    5. 纯路径，不含域名与 query

    6. 规范化 query：解码后按 key、再按 value 升序，各自 encodeURIComponent，用 `&` 连接；没有 query 为空串

    7. 请求体原文的 sha256（十六进制）；无请求体时为空串的 sha256：`e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`

    8. `x-open-user` 的值；不带则为空串


    `x-signature = HMAC-SHA256(app_secret, 签名串)` 的十六进制。不带 `x-sign-version` 的请求暂按旧版（v1）校验，过渡期后只接受 v2。


    ⚠️ `app_secret` 只放你自己的服务端，不要打进小程序 / App / 网页。`x-open-user` 必须取自你服务端的登录态，不能透传前端传来的值。


    ## 错误


    错误统一返回 `{ "code": "...", "message": "..." }`（部分接口另带 `ok: false`），HTTP 状态码同时表意：

    `400 BAD_REQUEST` 参数不合法 · `401 UNAUTHORIZED` appKey 无效 / 签名错误 / 时间戳超窗 · `403 FORBIDDEN` 路径不在 appKey 权限白名单 ·

    `404 NOT_FOUND` 资源不存在或不归属你的 appKey · `429 RATE_LIMITED` 超出限流（按 Retry-After 重试）。


    ## 限流


    只读接口每个 appKey 每分钟 300 次；用户态（交易类）接口每分钟 60 次。


    ## 对外 ID


    订单号、售后单号、商品 ID、SKU ID 都是不透明字符串：原样保存、原样回传，不要解析格式。

    商品接口正在重构为统一商品层，届时商品 ID 会切换为平台 ID，会提前通知并提供对照。
servers:
  - url: https://api.gowu.net
    description: 生产
tags:
  - name: 企业开户与员工绑定
    description: 服务端签名调用，不带 x-open-user。企业由平台在审批你的接入申请时建好，你只需查到它并绑定员工
  - name: 企业管理
    description: x-open-user 放企业管理员（owner / admin）
  - name: 企业管理（可选）
    description: 部门、预算、消费记录、员工生日，按需接入
  - name: 员工额度
    description: x-open-user 放员工；签到为可选
  - name: 站内信（可选）
    description: x-open-user 放当前用户
  - name: 商品
    description: 商品接口正在重构为统一商品层，上线前后会给出对照
  - name: 购物车（可选）
    description: x-open-user 放员工；服务端购物车
  - name: 结算与下单
    description: x-open-user 放员工；payWith 固定传 "auto"，付款方式由平台按企业配置
  - name: 售后与开票
    description: 售后按子订单发起；订单提交后自动开票
  - name: 接入与账户
    description: 沙箱 key 与账户信息
security:
  - AppKey: []
paths:
  /v1/buyer/me:
    get:
      tags:
        - 员工额度
      summary: 用户资料
      description: >-
        首次访问自动建档。`org` 是当前用户所属的企业：id、名称、在本产品里的开通状态（active 才能交易）、本人角色（owner / admin / member）、额度余额；没有归属企业为
        null。登录后调一次即可拿全身份，按 role 决定显不显示企业管理入口。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  account:
                    type: object
                    properties:
                      id:
                        type: string
                      platform:
                        type: string
                        enum:
                          - wx
                          - alipay
                          - pc
                          - h5
                          - other
                      externalId:
                        type: string
                        description: '= x-open-user'
                      nickname:
                        type: string
                      avatar:
                        type: string
                      realName:
                        type: string
                        description: 未填为空串
                      birthday:
                        type: string
                        description: 未填为空串
                      gender:
                        type: string
                        description: 未填为空串
                      createdAt:
                        type: string
                      lastSeenAt:
                        type: string
                  org:
                    type: object
                    nullable: true
                    description: 所属企业；没有为 null
                    properties:
                      id:
                        type: string
                        description: 企业 id（orgId）
                      name:
                        type: string
                      status:
                        type: string
                        description: 企业在本产品里的状态：active 才能交易；pending 待激活 / 开通审核中，rejected、disabled、none
                      role:
                        type: string
                        enum:
                          - owner
                          - admin
                          - member
                      balance:
                        type: integer
                        description: 本人额度余额（100 = 1 元）
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getBuyerMe
    put:
      tags:
        - 员工额度
      summary: 修改用户资料
      description: 不接受 phone。传空串清空对应字段。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                nickname:
                  type: string
                avatar:
                  type: string
                realName:
                  type: string
                birthday:
                  type: string
                  description: YYYY-MM-DD 或 MM-DD，须为过去的日期
                gender:
                  type: string
                  enum:
                    - male
                    - female
                    - ''
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  account:
                    type: object
        '400':
          description: '`BAD_BIRTHDAY` / `BAD_GENDER`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: putBuyerMe
  /v1/partner/orgs:
    get:
      tags:
        - 企业开户与员工绑定
      summary: 你的企业
      description: 你的企业——审批通过后由平台建好，归属当前 appKey，这里查到 `orgId` 后再绑定员工。按创建时间倒序，最多 200 条，不分页。
      security:
        - AppKey: []
          Signature: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/PartnerOrg'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getPartnerOrgs
  /v1/partner/orgs/{orgId}:
    get:
      tags:
        - 企业开户与员工绑定
      summary: 企业详情
      description: 轮询它看审核状态（status 从 pending 变为 active）。
      security:
        - AppKey: []
          Signature: []
      parameters:
        - name: orgId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  org:
                    $ref: '#/components/schemas/PartnerOrg'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: '`ORG_NOT_FOUND`：不存在或不归属当前 appKey'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getPartnerOrgsByorgId
  /v1/partner/orgs/{orgId}/members:
    get:
      tags:
        - 企业开户与员工绑定
      summary: 已绑定员工
      description: 只列经本接入方绑定的员工，含已离职的，不分页。
      security:
        - AppKey: []
          Signature: []
      parameters:
        - name: orgId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/PartnerMember'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: '`ORG_NOT_FOUND`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getPartnerOrgsByorgIdMembers
  /v1/partner/orgs/{orgId}/members/{userId}:
    put:
      tags:
        - 企业开户与员工绑定
      summary: 绑定员工 / 修改角色
      description: 把你的用户绑成员工，同时开通采购权限。`userId` 用你自己的用户 ID，之后该员工请求时放进 x-open-user。已是本企业在职员工时只更新角色（HTTP 200）；一个用户同时只能属于一家企业。
      security:
        - AppKey: []
          Signature: []
      parameters:
        - name: orgId
          in: path
          required: true
          schema:
            type: string
        - name: userId
          in: path
          required: true
          schema:
            type: string
          description: 你的用户 ID，匹配 ^[\w.:@-]{1,128}$
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 40
                phone:
                  type: string
                  maxLength: 20
                  description: 仅存档，平台不验证、不用于识别身份
                role:
                  type: string
                  enum:
                    - owner
                    - admin
                    - member
                  default: member
                platform:
                  type: string
                  enum:
                    - wx
                    - alipay
                    - pc
                    - h5
                    - other
                  default: other
      responses:
        '200':
          description: 已是员工，角色已更新
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  created:
                    type: boolean
                    example: false
                  member:
                    $ref: '#/components/schemas/PartnerMember'
        '201':
          description: 已绑定
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  created:
                    type: boolean
                    example: true
                  member:
                    $ref: '#/components/schemas/PartnerMember'
        '400':
          description: '`BAD_USER` / `BAD_ROLE`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: '`ORG_NOT_FOUND`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: '`ALREADY_BOUND`：该用户已是其他企业的在职员工'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: putPartnerOrgsByorgIdMembersByuserId
    delete:
      tags:
        - 企业开户与员工绑定
      summary: 员工离职
      description: 未用额度全部退回企业额度池，收回采购权限。超级管理员（owner）不能直接离职，需先把 owner 交接给别人。
      security:
        - AppKey: []
          Signature: []
      parameters:
        - name: orgId
          in: path
          required: true
          schema:
            type: string
        - name: userId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                  maxLength: 60
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  reclaimed:
                    type: number
                    description: 退回企业的额度
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: '`ORG_NOT_FOUND` / `NOT_MEMBER`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: '`OFFBOARD_FAILED`：成员不在职，或 owner 需先交接'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: deletePartnerOrgsByorgIdMembersByuserId
  /v1/enterprise/org:
    get:
      tags:
        - 企业管理
      summary: 企业概览、额度池余额与流水
      description: x-open-user 放企业管理员（owner / admin）。企业由该用户所属企业决定，请求里不接受 orgId。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  org:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      status:
                        type: string
                      joinPolicy:
                        type: string
                        enum:
                          - auto
                          - review
                      poolBalance:
                        type: number
                      memberCount:
                        type: integer
                      invoice:
                        $ref: '#/components/schemas/InvoiceInfo'
                      invoiceReady:
                        type: boolean
                      createdAt:
                        type: string
                  ledger:
                    type: array
                    description: 额度池流水，最多 100 条，新的在前
                    items:
                      type: object
                      properties:
                        kind:
                          type: string
                          description: recharge / grant / revoke / expire / refund / offboard / adjust 等
                        kindLabel:
                          type: string
                        amount:
                          type: number
                          description: 带正负号
                        balanceAfter:
                          type: number
                        remark:
                          type: string
                        createdAt:
                          type: string
                  defaultExpiryDays:
                    type: number
                    description: 发放额度的默认有效期（天）
                  me:
                    type: object
                    properties:
                      role:
                        type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrg
  /v1/enterprise/org/profile:
    put:
      tags:
        - 企业管理
      summary: 修改企业资料
      description: 企业名称与统一社会信用代码开户后不可改（传了不同的值返回 `IDENTITY_LOCKED`）。税号固定等于信用代码。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                shortName:
                  type: string
                region:
                  type: string
                contactName:
                  type: string
                adminTitle:
                  type: string
                adminEmail:
                  type: string
                licenseUrl:
                  type: string
                joinPolicy:
                  type: string
                  enum:
                    - auto
                    - review
                invoice:
                  $ref: '#/components/schemas/InvoiceInfo'
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ok'
        '400':
          description: '`IDENTITY_LOCKED` / `SAVE_FAILED` / `BAD_CREDIT_CODE`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: putEnterpriseOrgProfile
  /v1/enterprise/org/bills:
    get:
      tags:
        - 企业管理
      summary: 企业账单
      description: 不带 id 返回最近 36 期（按期间倒序）；带 id 返回单张。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: id
          in: query
          required: false
          schema:
            type: string
          description: 账单 id
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/OrgBill'
                  bill:
                    $ref: '#/components/schemas/OrgBill'
                description: 不带 id 时返回 items，带 id 时返回 bill
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: 账单不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrgBills
  /v1/enterprise/org/points:
    post:
      tags:
        - 企业管理
      summary: 发放 / 回收额度
      description: >-
        以管理员身份调用。`action`：`grant` 发放（缺省）、`revoke` 回收、`grant-all` 全员发放。grant / revoke 用 `userId`（你的用户 ID）或 `accountId`
        指定员工，两者都传以 accountId 为准。


        `theme` 是福利类型，可选值用 `GET /v1/enterprise/points/themes` 查，传了不认识的值返回 400。每批有效期夹到 1–90 天，到期未用完退回企业。金额单位：100 = 1 元。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amount
              properties:
                action:
                  type: string
                  enum:
                    - grant
                    - revoke
                    - grant-all
                  default: grant
                userId:
                  type: string
                  description: 你的用户 ID（grant / revoke 时与 accountId 二选一）
                accountId:
                  type: string
                  description: 平台内部员工账号 id
                amount:
                  type: integer
                  minimum: 1
                  description: 额度（100 = 1 元）；grant-all 时为每人金额
                theme:
                  type: string
                  default: special
                  description: 福利类型 key
                name:
                  type: string
                  description: 这批额度的名称，如「中秋福利」
                expiresInDays:
                  type: number
                  description: 有效期（天），不传用企业默认，最终夹到 1–90
                budgetCategory:
                  type: string
                  description: 计入哪个预算类目，缺省 = theme
                lotId:
                  type: string
                  description: 仅 revoke：指定从哪一批回收，不传按到期先后
                remark:
                  type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  replay:
                    type: boolean
                    description: grant / revoke：是否为重复请求的回放
                  result:
                    type: object
                    description: grant-all 时返回
                    properties:
                      granted:
                        type: integer
                      amount:
                        type: number
                      failed:
                        type: array
                        items:
                          type: object
                          properties:
                            accountId:
                              type: string
                            message:
                              type: string
        '400':
          description: >-
            `BAD_REQUEST`（金额或福利类型不合法、缺少员工）/ `BUDGET_EXCEEDED` / `INSUFFICIENT_POINTS`（额度池或员工余额不足，附 balance、shortfall）/
            `NO_ACCOUNT` / `LOT_UNAVAILABLE` / `EMPTY`
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: '`NOT_MEMBER`：该用户不是本企业员工；或管理员校验失败（见企业概览接口）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseOrgPoints
  /v1/enterprise/points/themes:
    get:
      tags:
        - 企业管理
      summary: 福利类型列表
      description: 发放额度时 `theme` 的可选值，由运营在后台维护，不要写死。只返回启用中的类型。
      security:
        - AppKey: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        key:
                          type: string
                          example: festival
                        label:
                          type: string
                          example: 节日福利
                        sort:
                          type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterprisePointsThemes
  /v1/enterprise/org/members/{accountId}:
    parameters:
      - name: accountId
        in: path
        required: true
        schema:
          type: string
        description: 员工的平台账号 id；带 `?by=userId` 时为你的用户 ID
      - name: by
        in: query
        required: false
        schema:
          type: string
          enum:
            - userId
        description: 传 userId 时，路径里放你自己的用户 ID
    get:
      tags:
        - 企业管理
      summary: 员工额度明细
      description: 员工手上还有余量的额度批次，以及离职时的回收记录。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  lots:
                    type: array
                    items:
                      $ref: '#/components/schemas/Lot'
                  offboardRecord:
                    type: array
                    items:
                      type: object
                      properties:
                        lotId:
                          type: string
                        name:
                          type: string
                        amount:
                          type: number
                        at:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrgMembersByaccountId
    put:
      tags:
        - 企业管理
      summary: 修改员工资料
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                realName:
                  type: string
                departmentId:
                  type: string
                  nullable: true
                  description: null 或空串 = 清空部门
                birthday:
                  type: string
                  description: YYYY-MM-DD 或 MM-DD
                gender:
                  type: string
                  enum:
                    - male
                    - female
                    - ''
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ok'
        '400':
          description: 操作失败，`message` 说明原因（部分情况不带 code）
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: putEnterpriseOrgMembersByaccountId
    post:
      tags:
        - 企业管理
      summary: 停用 / 恢复 / 离职 / 改角色
      description: >-
        `suspend` 停用（额度保留，可恢复）· `reactivate` 恢复 · `offboard` 离职（未用额度退回企业）· `set-role` 改角色（`role` 为 admin 或
        member）。不能对自己操作；owner 不能直接停用或离职，需先交接。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - action
              properties:
                action:
                  type: string
                  enum:
                    - suspend
                    - reactivate
                    - offboard
                    - set-role
                reason:
                  type: string
                  description: offboard 时可填
                role:
                  type: string
                  enum:
                    - admin
                    - member
                  description: set-role 时必填
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  role:
                    type: string
                    description: set-role 时返回
                  result:
                    type: object
                    description: offboard 时返回
                    properties:
                      lots:
                        type: integer
                      amount:
                        type: number
                      legacy:
                        type: number
        '400':
          description: '`SELF` 不能对自己操作 / `OWNER_LOCKED` / `LAST_MANAGER` / `NOT_FOUND`，或 message 说明的状态不允许'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseOrgMembersByaccountId
  /v1/enterprise/org/points-settings:
    get:
      tags:
        - 企业管理
      summary: 企业额度设置
      description: '`effective` 生效值；`overrides` 企业自己设过的项（null = 跟随平台）；`platform` 平台默认。'
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  effective:
                    $ref: '#/components/schemas/PointsSettings'
                  overrides:
                    $ref: '#/components/schemas/PointsSettings'
                  platform:
                    $ref: '#/components/schemas/PointsSettings'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrgPointsSettings
    patch:
      tags:
        - 企业管理
      summary: 修改企业额度设置
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: 只传要改的项；显式传 null = 退回跟随平台默认
              properties:
                checkinEnabled:
                  type: boolean
                  nullable: true
                checkinDailyAmount:
                  type: number
                  nullable: true
                  minimum: 1
                  maximum: 10000
                checkinStreakDays:
                  type: number
                  nullable: true
                  minimum: 2
                  maximum: 60
                checkinStreakBonus:
                  type: number
                  nullable: true
                  minimum: 0
                  maximum: 100000
                pointsExpiryDays:
                  type: number
                  nullable: true
                  minimum: 1
                  maximum: 90
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  effective:
                    $ref: '#/components/schemas/PointsSettings'
                  overrides:
                    $ref: '#/components/schemas/PointsSettings'
                  platform:
                    $ref: '#/components/schemas/PointsSettings'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: patchEnterpriseOrgPointsSettings
  /v1/enterprise/org/dashboard:
    get:
      tags:
        - 企业管理
      summary: 额度看板
      description: 管理首页的汇总数：某个期间内的发放、使用、回池、退回与使用率。全部从额度流水按期间汇总，金额单位 100 = 1 元。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: period
          in: query
          required: false
          schema:
            type: string
            example: 2026-Q3
          description: 期间：2026 / 2026-Q3 / 2026-09；不传 = 当前年份
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  period:
                    type: string
                  members:
                    type: integer
                    description: 在职员工数
                  poolBalance:
                    type: number
                    description: 企业额度池当前余额
                  granted:
                    type: number
                    description: 期间内发放（含任务奖励）
                  used:
                    type: number
                    description: 期间内下单使用
                  returned:
                    type: number
                    description: 回池：回收 + 过期 + 离职 + 兑换扣回
                  refunded:
                    type: number
                    description: 取消 / 退款退回员工
                  usageRate:
                    type: number
                    description: 使用率（%），一位小数：(used − refunded) / granted
                  perCapita:
                    type: number
                    description: 人均发放
                  covered:
                    type: integer
                    description: 期间内被发放过额度的人数
                  redemptions:
                    type: integer
                    description: 期间内下单笔数
        '400':
          description: 操作失败，`message` 说明原因（部分情况不带 code）
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrgDashboard
  /v1/enterprise/org/members:
    get:
      tags:
        - 企业管理
      summary: 员工列表
      description: 本企业员工及各自余额，含已停用、已离职的（看 status），不分页。只列在你这个接入方所属产品下的员工。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          description: 成员记录 id
                        orgId:
                          type: string
                        accountId:
                          type: string
                          description: 员工的平台账号 id；单个员工接口的路径参数
                        role:
                          type: string
                          enum:
                            - owner
                            - admin
                            - member
                        status:
                          type: string
                          enum:
                            - active
                            - suspended
                            - offboarded
                        realName:
                          type: string
                        nickname:
                          type: string
                        phone:
                          type: string
                        birthday:
                          type: string
                        departmentId:
                          type: string
                        balance:
                          type: number
                          description: 员工额度余额（100 = 1 元）
                        createdAt:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrgMembers
  /v1/enterprise/org/consumption:
    get:
      tags:
        - 企业管理（可选）
      summary: 员工额度消费记录
      description: 可选。全体员工的消耗侧流水：下单扣减，以及取消、退款、建单失败的退回（用 `direction` 区分）。`summary` 跟随当前筛选条件，不是全量。新的在前。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: accountId
          in: query
          required: false
          schema:
            type: string
          description: 只看某个员工（平台账号 id）
        - name: from
          in: query
          required: false
          schema:
            type: string
            format: date
          description: 起始日期 YYYY-MM-DD（含）
        - name: to
          in: query
          required: false
          schema:
            type: string
            format: date
          description: 截止日期 YYYY-MM-DD（含）
        - name: kind
          in: query
          required: false
          schema:
            type: string
            enum:
              - order
              - order_cancel
              - refund
              - order_rollback
          description: 只看某一类；不传 = 四类都要
        - $ref: '#/components/parameters/Page'
        - name: pageSize
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 1000
            default: 20
          description: 上限 1000，供导出分批拉取
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  total:
                    type: integer
                  page:
                    type: integer
                  pageSize:
                    type: integer
                  summary:
                    type: object
                    properties:
                      spent:
                        type: number
                        description: 下单扣减合计
                      refunded:
                        type: number
                        description: 各种退回合计
                      net:
                        type: number
                        description: 净消耗 = spent − refunded，不小于 0
                      people:
                        type: integer
                        description: 有消耗的人数
                      orders:
                        type: integer
                        description: 下单笔数
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        accountId:
                          type: string
                        name:
                          type: string
                          description: 姓名，没有则昵称或手机号
                        phone:
                          type: string
                        departmentName:
                          type: string
                        kind:
                          type: string
                          enum:
                            - order
                            - order_cancel
                            - refund
                            - order_rollback
                        kindLabel:
                          type: string
                        amount:
                          type: number
                          description: 恒为正数，方向看 direction
                        direction:
                          type: string
                          enum:
                            - out
                            - in
                        outOrderId:
                          type: string
                        bizOrderId:
                          type: string
                          description: 订单还没建成时为空
                        orderStatus:
                          type: integer
                        remark:
                          type: string
                        createdAt:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrgConsumption
  /v1/enterprise/org/departments:
    get:
      tags:
        - 企业管理（可选）
      summary: 部门列表
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        sort:
                          type: number
                        memberCount:
                          type: integer
                        createdAt:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrgDepartments
    post:
      tags:
        - 企业管理（可选）
      summary: 新建部门
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                sort:
                  type: number
                  default: 0
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  id:
                    type: string
        '400':
          description: 操作失败，`message` 说明原因（部分情况不带 code）
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseOrgDepartments
    put:
      tags:
        - 企业管理（可选）
      summary: 修改部门
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - id
              properties:
                id:
                  type: string
                name:
                  type: string
                sort:
                  type: number
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ok'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: putEnterpriseOrgDepartments
    delete:
      tags:
        - 企业管理（可选）
      summary: 删除部门
      description: 部门下还有员工时不能删。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: string
          description: 部门 id
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ok'
        '400':
          description: 操作失败，`message` 说明原因（部分情况不带 code）
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: deleteEnterpriseOrgDepartments
  /v1/enterprise/org/budgets:
    get:
      tags:
        - 企业管理（可选）
      summary: 预算列表 / 预算看板
      description: 带 `dashboard=<期间>` 返回该期间的预算执行看板（lines + totals）；否则返回预算列表，可用 `period` 筛选。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: period
          in: query
          required: false
          schema:
            type: string
          description: 如 2026 / 2026-Q3 / 2026-09
        - name: dashboard
          in: query
          required: false
          schema:
            type: string
          description: 看板期间，格式同 period
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Budget'
                  period:
                    type: string
                  lines:
                    type: array
                    items:
                      $ref: '#/components/schemas/BudgetLine'
                  totals:
                    type: object
                    properties:
                      amount:
                        type: number
                      granted:
                        type: number
                      used:
                        type: number
        '400':
          description: 操作失败，`message` 说明原因（部分情况不带 code）
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrgBudgets
    post:
      tags:
        - 企业管理（可选）
      summary: 设置预算
      description: 按 期间 + 类目 + 部门 新建或覆盖。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - period
                - amount
              properties:
                period:
                  type: string
                  description: 2026 / 2026-Q3 / 2026-09
                category:
                  type: string
                  description: 福利类型 key；空 = 不分类目
                departmentId:
                  type: string
                  description: 空 = 不分部门
                amount:
                  type: integer
                  minimum: 0
                alertPct:
                  type: integer
                  minimum: 1
                  maximum: 100
                  default: 80
                overspendPolicy:
                  type: string
                  enum:
                    - allow
                    - block
                  default: allow
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  id:
                    type: string
        '400':
          description: 操作失败，`message` 说明原因（部分情况不带 code）
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseOrgBudgets
    delete:
      tags:
        - 企业管理（可选）
      summary: 删除预算
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: string
          description: 预算 id
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ok'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 当前用户不能做管理操作：`NOT_ORG_MEMBER` 未绑定到企业 / `NOT_ORG_ADMIN` 不是 owner 或 admin / `ORG_NOT_ACTIVE` 企业待审核或已停用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: deleteEnterpriseOrgBudgets
  /v1/enterprise/points:
    get:
      tags:
        - 员工额度
      summary: 能否用企业额度支付
      description: '结算页用：这个员工能不能用企业额度、余额多少。未绑定企业时 `bound: false`。'
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  bound:
                    type: boolean
                  canUsePoints:
                    type: boolean
                    description: 企业为 active 时为 true
                  balance:
                    type: number
                  org:
                    type: object
                    properties:
                      name:
                        type: string
                      status:
                        type: string
                  role:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterprisePoints
  /v1/enterprise/points/summary:
    get:
      tags:
        - 员工额度
      summary: 额度总览
      description: 余额、30 天内即将到期的额度、所属企业与角色。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  bound:
                    type: boolean
                  balance:
                    type: number
                  expiringSoon:
                    type: object
                    properties:
                      amount:
                        type: number
                      nearestDate:
                        type: string
                  org:
                    type: object
                    properties:
                      name:
                        type: string
                      status:
                        type: string
                      role:
                        type: string
                  canUsePoints:
                    type: boolean
                  ratio:
                    type: integer
                    example: 100
                    description: 100 = 1 元
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterprisePointsSummary
  /v1/enterprise/points/ledger:
    get:
      tags:
        - 员工额度
      summary: 额度流水
      description: 最多取最近 200 条再分页，因此 total 最大 200。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: type
          in: query
          required: false
          schema:
            type: string
            enum:
              - grant
              - order
              - refund
              - expire
          description: 不传 = 全部；refund 包含各种退回
        - $ref: '#/components/parameters/Page'
        - name: pageSize
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  bound:
                    type: boolean
                  total:
                    type: integer
                  page:
                    type: integer
                  pageSize:
                    type: integer
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        kind:
                          type: string
                        label:
                          type: string
                          description: 展示用文案，由服务端下发
                        amount:
                          type: number
                          description: 带正负号
                        balanceAfter:
                          type: number
                        remark:
                          type: string
                          nullable: true
                        lots:
                          type: array
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                              name:
                                type: string
                              theme:
                                type: string
                        createdAt:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterprisePointsLedger
  /v1/enterprise/points/welfares:
    get:
      tags:
        - 员工额度
      summary: 按批次查看剩余额度与到期日
      description: 只含还有余量的批次，按到期日升序。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: theme
          in: query
          required: false
          schema:
            type: string
          description: 福利类型 key
        - name: expiringWithin
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
          description: 只看 N 天内到期的
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  bound:
                    type: boolean
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Lot'
                  total:
                    type: number
                    description: 所有批次剩余之和
                  expiringAmount:
                    type: number
                    description: 有到期日的批次剩余之和
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterprisePointsWelfares
  /v1/enterprise/points/rules:
    get:
      tags:
        - 员工额度
      summary: 额度使用规则文案
      description: 登录前也能看；带 x-open-user 时有效期按该员工所属企业的设置显示。
      security:
        - AppKey: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ratio:
                    type: integer
                    example: 100
                  expiryPolicy:
                    type: object
                    properties:
                      defaultDays:
                        type: number
                      onExpire:
                        type: string
                        example: return_to_org
                  sections:
                    type: array
                    items:
                      type: object
                      properties:
                        title:
                          type: string
                        body:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterprisePointsRules
  /v1/enterprise/notifications:
    get:
      tags:
        - 站内信（可选）
      summary: 站内信列表
      description: 可选。发给当前用户的站内信（如预算预警、任务变更），新的在前，最多 50 条。只存表，不推送。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: unread
          in: query
          required: false
          schema:
            type: string
            enum:
              - '1'
          description: 传 1 只看未读
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  unread:
                    type: integer
                    description: 未读总数
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        kind:
                          type: string
                        title:
                          type: string
                        body:
                          type: string
                        refId:
                          type: string
                          description: 关联对象 id（如任务 id）
                        readAt:
                          type: string
                          description: 未读时不返回
                        createdAt:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseNotifications
    post:
      tags:
        - 站内信（可选）
      summary: 标记已读
      description: 可选。不传 ids = 全部标为已读。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  items:
                    type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  marked:
                    type: integer
                    description: 本次标记的条数
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseNotifications
  /v1/enterprise/products/search:
    post:
      tags:
        - 商品
      summary: 搜索商品
      description: >-
        请求体带 version: 2（响应同样带 version: 2）；不带 version 为旧版接口，返回格式不同，保留一个版本周期。按关键词 / 编码找商品，或按条件浏览。每条结果是「商品 +
        推荐规格」，可附上符合程度与每个条件的判定（include: ["match"]）。mode 控制多严：缺省 balanced（完全符合的在前、一件都没有才放宽）；AI 助手推荐、清单解析建议
        strict（只要完全符合的）。翻页用 nextCursor。匹配与排序规则、各商品池可用的筛选字段见开发者文档 §11。未带 x-open-user 时带 query、筛选或排序都返回 401
        NEED_LOGIN，纯浏览只给第一页。
      security:
        - AppKey: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              required:
                - version
              description: >-
                必须带 version: 2，其余全部可选；不传 query = 按条件浏览。不认识的参数一律 400 并在 field 里指明（带了旧参数会提示新写法）。不带 version
                的请求按旧版接口处理（keyword / category / brand / priceMin / priceMax / inStockOnly / sortBy / page /
                pageSize，返回旧的 { items, page, pageSize, total }），保留一个版本周期
              properties:
                version:
                  type: integer
                  enum:
                    - 2
                  description: 接口版本，固定传 2。不传 = 旧版接口（返回格式不同）
                query:
                  type: object
                  description: 找什么：text 与 code 二选一
                  properties:
                    text:
                      type: string
                      maxLength: 100
                      description: 关键词。多个条件用空格分开，必须条件全部满足才算完全符合
                    optional:
                      type: array
                      items:
                        type: string
                      maxItems: 10
                      description: text 里「有更好、没有也行」的词（如用户说颜色无所谓）：只参与排序，不作为必须条件。必须是 text 里出现过的词，否则 400
                    code:
                      type: string
                      maxLength: 64
                      description: 按 SKU 编码 / 型号 / 条码 / 上游商品 ID 精确查，不容错、不改写
                filter:
                  type: object
                  description: 硬条件：不满足就不返回
                  properties:
                    category:
                      oneOf:
                        - type: string
                        - type: array
                          items:
                            type: string
                          maxItems: 20
                      description: 叶子类目名，精确匹配；数组 = 任一
                    categoryId:
                      oneOf:
                        - type: string
                        - type: array
                          items:
                            type: string
                          maxItems: 20
                      description: 类目 id（一级 / 二级 / 叶子），含子类目；数组 = 任一。类目导航接口给的就是它
                    brand:
                      oneOf:
                        - type: string
                        - type: array
                          items:
                            type: string
                          maxItems: 20
                      description: 品牌名，精确匹配；数组 = 任一
                    price:
                      type: object
                      description: 价格区间（元，含边界），按规格价：任一可售规格落在区间内即命中，此时推荐的就是区间内的规格。传反了自动对调
                      properties:
                        gte:
                          type: number
                          minimum: 0
                        lte:
                          type: number
                          minimum: 0
                    inStock:
                      type: boolean
                      description: 只要有货的
                unknown:
                  type: string
                  enum:
                    - include
                    - exclude
                  default: include
                  description: 筛选字段没有值的商品怎么处理（当前可用字段都有值，预留）
                mode:
                  type: string
                  enum:
                    - balanced
                    - strict
                    - broad
                  default: balanced
                  description: >-
                    多严。balanced：完全符合的在前、部分符合的随后，一件都没有时才放宽（返回 relaxation）；strict：只要完全符合的，宁缺毋滥（AI
                    助手推荐、清单解析用）；broad：全部给，含放宽得到的
                sort:
                  type: string
                  enum:
                    - relevance
                    - price_asc
                    - price_desc
                    - sales_desc
                  default: relevance
                  description: 顺序。价格按推荐规格的价格；任何排序下不符合的（related）都排在最后
                profile:
                  type: string
                  enum:
                    - agent
                    - mall
                  default: agent
                  description: 排序预设：agent 推荐给人看的少量结果（符合程度优先，其次有货）；mall 搜索结果页
                prefer:
                  type: array
                  maxItems: 5
                  description: >-
                    软偏好：只影响同一符合程度内的先后，不影响返回哪些；多条按先后递减。sort 不是 relevance 时忽略。每条是以下三种写法之一：`{ "field": "price",
                    "direction": "low" | "high" }` 便宜 / 贵的优先；`{ "field": "brand", "value": "膳魔师" }` 这个品牌优先；`{ "text":
                    "大容量" }` 这个词命中的优先
                  items:
                    oneOf:
                      - type: object
                        required:
                          - field
                          - direction
                        properties:
                          field:
                            type: string
                            enum:
                              - price
                          direction:
                            type: string
                            enum:
                              - low
                              - high
                      - type: object
                        required:
                          - field
                          - value
                        properties:
                          field:
                            type: string
                            enum:
                              - brand
                          value:
                            type: string
                      - type: object
                        required:
                          - text
                        properties:
                          text:
                            type: string
                            maxLength: 50
                            description: 这个词命中的优先（可以不在 query.text 里）
                excludeFields:
                  type: array
                  items:
                    type: string
                    enum:
                      - title
                      - titleGrams
                      - aliases
                      - subtitle
                      - brand
                      - category
                      - categoryPath
                      - tags
                      - skuSpecValues
                      - skuTitles
                      - specsText
                      - qualityPerformance
                      - useCases
                      - descriptionSellingPoints
                      - audience
                      - exactCodes
                      - supplierName
                  description: >-
                    这次查询不用这些字段（只对 query.text 起作用）：既不在里面找商品，也不拿它判断符合与否。用来对比某个字段的作用，如去掉卖点
                    sellingPoints。不能全部去掉。可选字段：title（标题）、titleGrams（标题按每两个字切开（中文分词切错时的兜底））、aliases（买家叫法（别名））、subtitle（副标题）、brand（品牌）、category（叶子类目名）、categoryPath（类目整条路径）、tags（平台类目路径）、skuSpecValues（各规格的规格值（颜色、尺码、容量、型号…）与材质）、skuTitles（各规格的规格名）、specsText（商品参数（前
                    600 字））、qualityPerformance（品质性能（前 300 字））、useCases（适用场景）、descriptionSellingPoints（商品描述与卖点（前 300
                    字））、audience（适用人群）、exactCodes（编码：上游商品 ID、SKU 编码、型号、条码）、supplierName（供应商名）
                limit:
                  type: integer
                  minimum: 1
                  maximum: 50
                  default: 20
                cursor:
                  type: string
                  description: 翻页：上次返回的 nextCursor。与本次请求的条件绑定（换了条件 400），1 小时有效
                include:
                  type: array
                  items:
                    type: string
                    enum:
                      - match
                  description: match：每条结果附上条件判定（符合程度、每个条件满足与否及凭据）
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchV2Page'
        '400':
          description: '`BAD_REQUEST`：参数不合法（field 指明哪个参数；带了旧参数会提示新写法），version 不是 2，或 cursor 无效 / 过期 / 与本次条件不符'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: '`NEED_LOGIN`：未带 x-open-user 时只能取第一页和精选位。响应带 `blocked`：`search`（带了搜索条件）/ `category`（按类目浏览）/ `paging`（翻页）'
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                    example: NEED_LOGIN
                  message:
                    type: string
                  blocked:
                    type: string
                    enum:
                      - search
                      - category
                      - paging
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseProductsSearch
  /v1/enterprise/products/batch:
    get:
      tags:
        - 商品
      summary: 商品批量详情
      description: >-
        一次查多件商品的详情（购物车 / 收藏 / 订单回显用），每件与「商品详情」同一结构、同一可见范围。按请求顺序返回 `items`；查不到或已下架的放进 `notFound`，不报错。一次最多 20 件，超过回
        `TOO_MANY_IDS`。
      security:
        - AppKey: []
      parameters:
        - name: ids
          in: query
          required: true
          schema:
            type: string
          description: 商品 id，英文逗号分隔，最多 20 个，如 `ep_self_1,ep_self_2`
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/ProductDetail'
                  notFound:
                    type: array
                    items:
                      type: string
                    description: 查不到或当前不可见的商品 id
        '400':
          description: '`BAD_REQUEST`：ids 为空；`TOO_MANY_IDS`：超过 20 件'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseProductsBatch
  /v1/enterprise/products/by-tag:
    get:
      tags:
        - 商品
      summary: 按标签取商品
      description: >-
        取运营打了指定标签的商品，标签 key 向平台运营索取。商品结构与商品列表一致，可见范围为已上架 + 本渠道可见 + 有货。实际生效的标签回在 `tags`（已剔除停用 / 不存在的）：`match=any`
        时忽略无效标签、全部无效返回空列表；`match=all` 时有一个无效即返回空列表。未带 x-open-user 时只能取第一页（翻页返回 401 NEED_LOGIN），排序不受限。
      security:
        - AppKey: []
      parameters:
        - name: tags
          in: query
          required: true
          schema:
            type: string
          description: 标签 key，英文逗号分隔（也可重复传 tags=a&tags=b），最多 20 个，超出的忽略
        - name: match
          in: query
          required: false
          schema:
            type: string
            enum:
              - any
              - all
            default: any
          description: any：带任一标签即可；all：须同时带齐所有标签
        - name: sortBy
          in: query
          required: false
          schema:
            type: string
            enum:
              - sales_desc
              - price_asc
              - price_desc
              - newest
              - tagged
              - random
            default: sales_desc
          description: >-
            sales_desc 销量从高到低（销量为分档值，同档按更新时间）；price_asc / price_desc 按售价；newest 按上架时间，新品在前；tagged
            按打标时间，运营最近打上该标签的在前；random 随机打散，同一用户一小时内顺序固定、翻页不重不漏，每小时换一次（未带 x-open-user 时同一 appKey 下所有访客同一顺序；命中超过 2000 件时按
            sales_desc 返回）
        - $ref: '#/components/parameters/Page'
        - name: pageSize
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Product'
                  page:
                    type: integer
                  pageSize:
                    type: integer
                  total:
                    type: integer
                    description: 命中总数（精确值）
                  hasMore:
                    type: boolean
                  tags:
                    type: array
                    items:
                      type: string
                    description: 实际生效的标签 key（已剔除停用 / 不存在的）
        '400':
          description: '`BAD_REQUEST`：tags 为空，或 sortBy 不在可选值内'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: '`NEED_LOGIN`：未带 x-open-user 时只能取第一页和精选位。响应带 `blocked`：`search`（带了搜索条件）/ `category`（按类目浏览）/ `paging`（翻页）'
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                    example: NEED_LOGIN
                  message:
                    type: string
                  blocked:
                    type: string
                    enum:
                      - search
                      - category
                      - paging
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseProductsByTag
  /v1/enterprise/products/{id}:
    get:
      tags:
        - 商品
      summary: 商品详情
      security:
        - AppKey: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductDetail'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: '`NOT_FOUND`：商品不存在或已下架'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseProductsByid
  /v1/enterprise/products/{id}/desc:
    get:
      tags:
        - 商品
      summary: 图文详情
      description: 已消毒的 HTML 片段，可直接渲染。拿不到时返回空串（仍为 200）。
      security:
        - AppKey: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  html:
                    type: string
                  imageCount:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseProductsByidDesc
  /v1/enterprise/nav:
    get:
      tags:
        - 商品
      summary: 类目导航 · 一级
      security:
        - AppKey: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        groupId:
                          type: string
                        title:
                          type: string
                        icon:
                          type: string
                          nullable: true
                        entries:
                          type: array
                          items:
                            type: object
                            properties:
                              label:
                                type: string
                              categoryId:
                                type: string
                              categoryName:
                                type: string
                              count:
                                type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseNav
  /v1/enterprise/nav/branch:
    get:
      tags:
        - 商品
      summary: 类目导航 · 二级（带图）
      security:
        - AppKey: []
      parameters:
        - name: ids
          in: query
          required: true
          schema:
            type: string
          description: 一级类目 id，逗号分隔，最多 20 个
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        categoryId:
                          type: string
                        name:
                          type: string
                        children:
                          type: array
                          description: 每个一级最多 12 个
                          items:
                            type: object
                            properties:
                              categoryId:
                                type: string
                              name:
                                type: string
                              count:
                                type: integer
                              imageUrl:
                                type: string
                                nullable: true
                              imageKind:
                                type: string
                                enum:
                                  - url
                                  - svg
                                nullable: true
                              monogram:
                                type: object
                                description: 无图时的文字占位
                                properties:
                                  text:
                                    type: string
                                  hue:
                                    type: number
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseNavBranch
  /v1/divisions:
    get:
      tags:
        - 结算与下单
      summary: 行政区划级联
      description: >-
        从 parent=1（全国）开始逐级下钻：省 → 市 → 区县（divisionCode）→ 乡镇街道（townDivisionCode）。与福利GO 小程序、网页商城的地址选择同一份数据。老路径
        `/v1/lm/divisions` 仍可用，返回相同。企业购下单的 `receiver.province / city / area` 用这里选出的名称，乡镇街道名称放进
        `receiver.street`；也可以把带区划码的地址存进地址簿，下单传 `addressId`。
      security:
        - AppKey: []
      parameters:
        - name: parent
          in: query
          required: false
          description: 上一级区划码
          schema:
            type: string
            default: '1'
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        code:
                          type: string
                        name:
                          type: string
                        parentCode:
                          type: string
                        hasChildren:
                          type: boolean
                        level:
                          type: integer
                          description: 2 省 / 3 市 / 4 区县 / 5 乡镇街道
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getDivisions
  /v1/enterprise/checkout/render:
    post:
      tags:
        - 结算与下单
      summary: 结算预览
      description: 权威价、库存与可售状态；员工已绑定企业时返回 `points`（额度是否足够）。不需要收货地址。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - items
              properties:
                items:
                  type: array
                  minItems: 1
                  items:
                    type: object
                    required:
                      - productId
                    properties:
                      productId:
                        type: string
                        description: 商品接口返回的 id
                      skuId:
                        type: string
                        description: 商品详情 skus[].skuId；skuId 为 null 的商品不要传
                      qty:
                        type: integer
                        minimum: 1
                        default: 1
                device:
                  type: string
                  enum:
                    - pc
                    - mobile
                  description: （员工付现金 · 网页 / H5）场景，决定 `cash.payTypes` 里有没有微信；缺省按 appKey 登记的端
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  render:
                    type: object
                    properties:
                      totalFee:
                        type: number
                      postFee:
                        type: number
                      payable:
                        type: number
                      lines:
                        type: array
                        items:
                          type: object
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/OrderItem'
                  availabilityOk:
                    type: boolean
                  issues:
                    type: array
                    items:
                      type: object
                      properties:
                        productId:
                          type: string
                        title:
                          type: string
                        reason:
                          type: string
                          enum:
                            - OFF_SHELF
                            - OUT_OF_STOCK
                            - PRICE_CHANGED
                        detail:
                          type: string
                  points:
                    type: object
                    description: 员工已绑定企业时返回
                    properties:
                      required:
                        type: number
                        description: 这单需要的额度（100 = 1 元）
                      balance:
                        type: number
                      sufficient:
                        type: boolean
                      canUsePoints:
                        type: boolean
                  cash:
                    type: object
                    description: 这单要员工付现金时返回（企业配置为全额现金或混合，且当前端已开通）。全额现金时 `cent` 就是应付总额；混合时 `points.required` 是企业承担的那部分
                    properties:
                      cent:
                        type: integer
                        description: 员工自付的现金（分）
                      ratioBp:
                        type: integer
                        description: 企业承担比例（万分比）；0 = 全额由员工付。混合支付暂未开放，目前恒为 0
                      payTypes:
                        type: array
                        items:
                          type: string
                          enum:
                            - ALIPAY
                            - WECHAT_H5
                            - DGZF
                        description: 这个 appKey 在当前场景下可用的现金支付方式（支付宝 / 微信 / 对公），按它在你的下单页展示，员工选中的作为下单的 `payType` 传回
        '400':
          description: '`EMPTY` / `PRODUCT_NOT_FOUND` / `RENDER_FAILED` / `ORG_EGP_NOT_READY`（企业的交易尚未开通）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseCheckoutRender
  /v1/enterprise/orders:
    post:
      tags:
        - 结算与下单
      summary: 下单
      description: >-
        **`payWith` 固定传 `"auto"`**：付款方式完全由平台按企业配置决定——全额扣员工额度、全额由员工付现金，还是按比例混合（**混合暂未开放**，开放后无需改接入）；该 appKey
        没开通员工付现金时一律扣额度。扣额度与建单在同一事务里。


        要员工付现金时响应带 `launchUrl`（24 小时有效）——支付方式（`payType`）由你在下单页让员工选（可选项见结算预览的 `cash.payTypes`），会产生现金时必填；把员工带到 `launchUrl`
        即进入付款（对公为转账信息）。发起后默认沿用这种方式，可在继续支付时更换。付完平台核实到账、扣额度、结清订单（付款页由企业购提供，不一定跳回你的页面；以订单详情的 `mixedPay.status` 与
        `order.status` 推送为准）。员工付现金需要该 appKey 已开通（找平台在访问管理里开）。过期或中途关闭了用 `POST /v1/enterprise/orders/{bizOrderId}`
        `action=resume-pay` 重新取链接；结果以订单详情的 `mixedPay.status` 与 `order.status` 推送为准。


        收货地址 `receiver` 与 `addressId`（地址簿）二选一，同时传以 addressId 为准。


        **幂等**：强烈建议传 `idempotencyKey`，响应丢失时用同一个 key 重试，返回同一张单；不传时服务端按内容生成，只在 2 分钟内去重。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - items
              properties:
                items:
                  type: array
                  minItems: 1
                  items:
                    type: object
                    required:
                      - productId
                    properties:
                      productId:
                        type: string
                        description: 商品接口返回的 id
                      skuId:
                        type: string
                        description: 商品详情 skus[].skuId；skuId 为 null 的商品不要传
                      qty:
                        type: integer
                        minimum: 1
                        default: 1
                receiver:
                  $ref: '#/components/schemas/Receiver'
                addressId:
                  type: string
                payWith:
                  type: string
                  enum:
                    - auto
                  description: 固定传 `auto`：付款方式由平台按企业配置——全额扣员工额度、全额由员工在企业购收银台付现金，或两者按比例混合（混合暂未开放）；appKey 没开通员工付现金时扣额度
                payType:
                  type: string
                  enum:
                    - ALIPAY
                    - WECHAT_H5
                    - DGZF
                  description: >-
                    （员工付现金时）现金的支付方式：支付宝 / 微信 / 对公。**这单会产生现金时必填**（不传 400 `PAY_TYPE_REQUIRED`，响应带可选的
                    `payTypes`）。请在你的下单页按结算预览返回的 `cash.payTypes` 让员工选。必须在该 appKey 允许的范围内（平台在访问管理配置；没配时按登记的端：支付宝小程序为支付宝 +
                    对公，微信小程序为微信 + 对公，网页为全部、电脑上不含微信），否则 400 `PAY_TYPE_NOT_ALLOWED`
                returnUrl:
                  type: string
                  description: >-
                    （员工付现金 · 网页 / H5）收银台与结果页的「返回」地址：须 https，且是该 appKey 登记的回调地址的域名或其子域。会追加 `bizOrderId` 与
                    `result`（success / pending / failed / cancel，只是提示）。现金在企业购收银台付，付完不一定跳回这里——以订单查询或 order.status 推送为准
                device:
                  type: string
                  enum:
                    - pc
                    - mobile
                  description: （员工付现金 · 网页 / H5）收银台形态；缺省按 appKey 登记的端
                idempotencyKey:
                  type: string
                  description: 建议用你系统的订单号
                remark:
                  type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  bizOrderId:
                    type: string
                  order:
                    $ref: '#/components/schemas/Order'
                  pointsCharged:
                    type: number
                    description: 扣除的额度（100 = 1 元）。要员工付现金的单付完才扣，下单时不返回
                  hybrid:
                    type: boolean
                    description: 这单要员工付现金（字段名沿用旧称）
                  cashCent:
                    type: integer
                    description: 员工要付的现金（分）
                  launchUrl:
                    type: string
                    description: 付款链接（企业购收银台入口），24 小时有效
        '400':
          description: >-
            `EMPTY` / `BAD_RECEIVER` / `ADDRESS_NOT_FOUND` / `PRODUCT_NOT_FOUND` / `UNAVAILABLE` / `INSUFFICIENT_POINTS`
            / `POINTS_NOT_BOUND` / `ORG_NOT_ACTIVE` / `MEMBER_NOT_ACTIVE` / `ORG_EGP_NOT_READY` / `IN_PROGRESS`（同 key
            正在处理）/ `CREATE_FAILED` / `CREATE_PENDING`；员工付现金：`BAD_RETURN_URL` / `PAY_TYPE_REQUIRED`（会产生现金但没传 payType，响应带
            `payTypes`）/ `PAY_TYPE_NOT_ALLOWED`（payType 不在该 appKey 的范围内）等
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: '`ORDER_NOT_ALLOWED`：员工没有采购权限'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseOrders
    get:
      tags:
        - 结算与下单
      summary: 订单列表
      description: 当前员工的订单，新的在前。要员工付现金的订单带 `mixedPay` 摘要（不含收银台链接，继续支付请进详情或调 resume-pay）。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Order'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrders
  /v1/enterprise/orders/{bizOrderId}:
    parameters:
      - name: bizOrderId
        in: path
        required: true
        schema:
          type: string
    get:
      tags:
        - 结算与下单
      summary: 订单详情
      description: 要员工付现金的订单带 `mixedPay`；还没付完时给出 `mixedPay.launchUrl`。可用 `returnUrl` / `device` 覆盖下单时的设置。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: returnUrl
          in: query
          required: false
          schema:
            type: string
            description: >-
              （员工付现金 · 网页 / H5）收银台与结果页的「返回」地址：须 https，且是该 appKey 登记的回调地址的域名或其子域。会追加 `bizOrderId` 与 `result`（success /
              pending / failed / cancel，只是提示）。现金在企业购收银台付，付完不一定跳回这里——以订单查询或 order.status 推送为准
        - name: device
          in: query
          required: false
          schema:
            type: string
            enum:
              - pc
              - mobile
            description: （员工付现金 · 网页 / H5）收银台形态；缺省按 appKey 登记的端
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Order'
                  - type: object
                    properties:
                      mixedPay:
                        type: object
                        description: >-
                          员工付现金的状态（只有要员工付现金的订单才有，字段名沿用旧称）。pending = 现金还没付；paid = 现金已到账、正在结清；confirmed = 已付清；failed =
                          订单已关（已付的现金原路退回）
                        properties:
                          status:
                            type: string
                            enum:
                              - pending
                              - paid
                              - confirmed
                              - failed
                          cashCent:
                            type: integer
                            description: 员工自付的现金（分）
                          pointsCent:
                            type: integer
                            description: 企业承担的额度（100 = 1 元）
                          launchUrl:
                            type: string
                            description: （仅详情）收银台链接，24 小时有效；还没付完时给出
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrdersBybizOrderId
    post:
      tags:
        - 结算与下单
      summary: 取消 / 确认收货 / 继续支付
      description: >-
        `action` 放在 query 或 body：`cancel` 取消（已发货不能取消）、`receive` 确认收货、`resume-pay` 继续付现金（重新取付款链接）。失败返回 400 `{ ok: false,
        message }`。


        `resume-pay`：现金已付完的直接结清，返回 `state: "done"`；还没付的返回 `state: "need_pay"` 与新的 `launchUrl`（同一张单，不会重复收钱）。可带
        `returnUrl` / `device` / `payType`（已发起过的单沿用原支付方式，传别的不生效）。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: action
          in: query
          required: false
          schema:
            type: string
            enum:
              - cancel
              - receive
              - resume-pay
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                action:
                  type: string
                  enum:
                    - cancel
                    - receive
                    - resume-pay
                payType:
                  type: string
                  enum:
                    - ALIPAY
                    - WECHAT_H5
                    - DGZF
                  description: resume-pay：现金支付方式，须在 appKey 允许的范围内（同下单接口）。还没发起过付款的单必填（不传 400 `PAY_TYPE_REQUIRED`）；已发起过的不传就沿用原方式
                returnUrl:
                  type: string
                  description: >-
                    （员工付现金 · 网页 / H5）收银台与结果页的「返回」地址：须 https，且是该 appKey 登记的回调地址的域名或其子域。会追加 `bizOrderId` 与
                    `result`（success / pending / failed / cancel，只是提示）。现金在企业购收银台付，付完不一定跳回这里——以订单查询或 order.status 推送为准
                device:
                  type: string
                  enum:
                    - pc
                    - mobile
                  description: （员工付现金 · 网页 / H5）收银台形态；缺省按 appKey 登记的端
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  message:
                    type: string
                  state:
                    type: string
                    enum:
                      - done
                      - need_pay
                    description: resume-pay 才有
                  launchUrl:
                    type: string
                    description: resume-pay 且 need_pay 时给出，24 小时有效
                  cashCent:
                    type: integer
        '400':
          description: 操作不允许，见 message；resume-pay 还可能是 `BAD_RETURN_URL` / `PAY_TYPE_NOT_ALLOWED`
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseOrdersBybizOrderId
  /v1/enterprise/orders/{bizOrderId}/logistics:
    get:
      tags:
        - 结算与下单
      summary: 物流轨迹
      description: '一单可能分多个包裹。未发货时 `shipped: false`、packages 为空。'
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: bizOrderId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  bizOrderId:
                    type: string
                  shipped:
                    type: boolean
                  packages:
                    type: array
                    items:
                      type: object
                      properties:
                        packageId:
                          type: string
                        logisticsCompany:
                          type: string
                        invoiceNo:
                          type: string
                          description: 运单号
                        statusDesc:
                          type: string
                        consignTime:
                          type: string
                        deliveredTime:
                          type: string
                        items:
                          type: array
                          items:
                            type: object
                            properties:
                              itemName:
                                type: string
                              skuName:
                                type: string
                              quantity:
                                type: integer
                        tracks:
                          type: array
                          items:
                            type: object
                            properties:
                              time:
                                type: string
                              desc:
                                type: string
                              city:
                                type: string
        '400':
          description: '`UPSTREAM`：上游查询失败'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrdersBybizOrderIdLogistics
  /v1/enterprise/refunds:
    post:
      tags:
        - 售后与开票
      summary: 发起售后
      description: 按子订单发起；一单多件时 `subOrderId` 必填（取自订单详情 subOrders）。退款金额退回员工额度。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - bizOrderId
              properties:
                bizOrderId:
                  type: string
                subOrderId:
                  type: string
                reasonId:
                  type: string
                reasonText:
                  type: string
                amount:
                  type: number
                  description: 退款金额（元），不传按可退全额
                needReturn:
                  type: boolean
                  description: 是否需要寄回商品
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  refund:
                    $ref: '#/components/schemas/Refund'
                  subOrderId:
                    type: string
        '400':
          description: >-
            `NOT_PAID` / `ORDER_CLOSED` / `SUB_ORDER_REQUIRED` / `SUB_ORDER_INVALID` / `REASON_INVALID` /
            `PROOF_REQUIRED` / `NO_REFUNDABLE_AMOUNT` / `SUBMIT_FAILED` / `NOT_FOUND` 等
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseRefunds
    get:
      tags:
        - 售后与开票
      summary: 售后列表
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Refund'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseRefunds
  /v1/enterprise/refunds/{refundId}:
    parameters:
      - name: refundId
        in: path
        required: true
        schema:
          type: string
    get:
      tags:
        - 售后与开票
      summary: 售后详情
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Refund'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseRefundsByrefundId
    post:
      tags:
        - 售后与开票
      summary: 撤销售后 / 回传退货运单
      description: '`?action=cancel`（缺省）撤销；`?action=return` 寄回商品后回传运单。失败返回 400 `{ ok: false, message }`。'
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: action
          in: query
          required: false
          schema:
            type: string
            enum:
              - cancel
              - return
            default: cancel
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              description: 仅 action=return 时需要
              properties:
                logisticsCompany:
                  type: string
                  description: 快递公司编码或中文名
                invoiceNo:
                  type: string
                  description: 退货运单号
                mobile:
                  type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  message:
                    type: string
        '400':
          description: 操作不允许，见 message
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseRefundsByrefundId
  /v1/buyer/invoices:
    get:
      tags:
        - 售后与开票
      summary: 开票记录
      description: 订单提交后自动开票，抬头取企业开户时的信息。最多返回最近 100 条。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Invoice'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getBuyerInvoices
  /v1/enterprise/zones:
    get:
      tags:
        - 商品
      summary: 首页专区
      description: 可选。运营配置的专区（一张 banner + 一组商品），按 `sort` 顺序渲染 banner，点击后用 `id` 调专区商品接口。停用的专区不出现。未登录访客浏览（平台为该应用配了访客货盘时）返回空列表。
      security:
        - AppKey: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        bannerUrl:
                          type: string
                        sort:
                          type: number
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseZones
  /v1/enterprise/zones/{id}/products:
    get:
      tags:
        - 商品
      summary: 专区商品
      description: 可选。商品结构与商品列表一致，按销量倒序。专区不存在、已停用或访客浏览时返回空列表（`zone` 为 null 或 items 为空），不返回 404。
      security:
        - AppKey: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: 专区 id
        - $ref: '#/components/parameters/Page'
        - name: pageSize
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ProductPage'
                  - type: object
                    properties:
                      zone:
                        type: object
                        nullable: true
                        properties:
                          id:
                            type: string
                          name:
                            type: string
                          bannerUrl:
                            type: string
                      hasMore:
                        type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseZonesByidProducts
  /v1/enterprise/bundles:
    get:
      tags:
        - 商品
      summary: 组货方案列表
      description: >-
        可选。平台运营配置的组货方案（如「新企开办 → 1人团队 / 5人团队」：一组规格 + 建议数量），按场景分组；场景、方案各自按运营设的顺序。只返回调用方所属产品（appKey 的产品归属）里已上线的方案。appKey
        未配置所属产品时须传 `realm`；配置了的传别的产品返回 403。列表不含明细，选中方案后用 `code` 调组货方案详情。
      security:
        - AppKey: []
      parameters:
        - name: scene
          in: query
          required: false
          schema:
            type: string
          description: 只看某个场景（场景编码，如 business_startup）
        - name: realm
          in: query
          required: false
          schema:
            type: string
            enum:
              - welfare
              - procurement
              - consumer
          description: 所属产品。仅 appKey 未配置所属产品时需要
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  realm:
                    type: string
                    description: 实际生效的产品
                  scenes:
                    type: array
                    items:
                      type: object
                      properties:
                        code:
                          type: string
                          description: 场景编码
                        name:
                          type: string
                          description: 场景名，如「新企开办」
                        bundles:
                          type: array
                          items:
                            type: object
                            properties:
                              code:
                                type: string
                                description: 方案编码，稳定不变，用于取详情
                              name:
                                type: string
                                description: 方案名称
                              label:
                                type: string
                                description: 前端选项标签，如「1人团队」
                              description:
                                type: string
                                nullable: true
                              sortOrder:
                                type: integer
                              version:
                                type: integer
                                description: 当前发布的版本号，运营每次发布 +1
                              itemCount:
                                type: integer
                                description: 规格数
                              publishedAt:
                                type: string
                                nullable: true
        '400':
          description: '`BAD_REQUEST`：appKey 未配置所属产品且没传 realm，或 realm 不认识'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: '`REALM_MISMATCH`：传的 realm 不是该 appKey 所属的产品'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseBundles
  /v1/enterprise/bundles/{code}:
    get:
      tags:
        - 商品
      summary: 组货方案详情
      description: >-
        可选。方案当前发布版本的规格与建议数量，价格、库存实时读取，并按调用方渠道判断能否购买。买不到的规格也会返回（`available=false` 并带
        `unavailableReason`），由端上决定置灰还是提示换货；`totalPrice` 只合计能买的规格。加购 / 下单沿用 `{ productId, skuId?, qty }`：`qty` 取
        `quantity`，单规格商品 `skuId` 为 null，不传。
      security:
        - AppKey: []
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
          description: 方案编码（来自组货方案列表）
        - name: realm
          in: query
          required: false
          schema:
            type: string
            enum:
              - welfare
              - procurement
              - consumer
          description: 所属产品。仅 appKey 未配置所属产品时需要
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                  name:
                    type: string
                  label:
                    type: string
                  description:
                    type: string
                    nullable: true
                  sortOrder:
                    type: integer
                  version:
                    type: integer
                  itemCount:
                    type: integer
                  publishedAt:
                    type: string
                    nullable: true
                  scene:
                    type: object
                    properties:
                      code:
                        type: string
                      name:
                        type: string
                  totalPrice:
                    type: number
                    description: 能买的规格按建议数量的合计（元），参考价，以结算为准
                  unavailableCount:
                    type: integer
                    description: 当前买不到的规格数
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        skuRef:
                          type: string
                          description: 规格的稳定标识
                        productId:
                          type: string
                          description: 加购 / 下单用的商品 ID
                        skuId:
                          type: string
                          nullable: true
                          description: 加购 / 下单用的规格 ID；单规格商品为 null
                        quantity:
                          type: integer
                          description: 建议数量
                        title:
                          type: string
                        specs:
                          type: object
                          additionalProperties:
                            type: string
                          description: '规格属性，如 { 颜色: 黑色 }'
                        skuTitle:
                          type: string
                          nullable: true
                        imageUrl:
                          type: string
                        brand:
                          type: string
                          nullable: true
                        price:
                          type: number
                          description: 单价（元），实时
                        marketPrice:
                          type: number
                          nullable: true
                        stock:
                          type: integer
                          nullable: true
                          description: 精确库存；上游只给模糊库存时为 null，看 fuzzyStock
                        fuzzyStock:
                          type: string
                          nullable: true
                        available:
                          type: boolean
                        unavailableReason:
                          type: string
                          enum:
                            - 商品未上架
                            - 上游已下架
                            - 规格已删除
                            - 无货
                            - 规格不存在
                            - 渠道不可售
                          description: available=false 时才有
        '400':
          description: '`BAD_REQUEST`：appKey 未配置所属产品且没传 realm，或 realm 不认识'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: '`REALM_MISMATCH`：传的 realm 不是该 appKey 所属的产品'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: '`NOT_FOUND`：方案不存在、未上线或不在该产品里'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseBundlesBycode
  /v1/enterprise/products/suggest:
    get:
      tags:
        - 商品
      summary: 搜索联想 / 热门搜索
      description: 可选。输入框联想：`q` 为已输入的前缀；`q` 为空时返回热门搜索词。搜索服务不可用时返回空列表（仍为 200），不影响主流程。
      security:
        - AppKey: []
      parameters:
        - name: q
          in: query
          schema:
            type: string
            maxLength: 50
          description: 已输入的前缀；不传 = 热门搜索
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            default: 10
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        text:
                          type: string
                        type:
                          type: string
                          enum:
                            - query
                            - category
                            - brand
                          description: query 热门搜索词 / category 类目 / brand 品牌
                        hits:
                          type: integer
                          description: 该词最近一次搜索的命中数（仅 query）
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseProductsSuggest
  /v1/enterprise/products/events:
    post:
      tags:
        - 商品
      summary: 上报搜索结果上的点击 / 加购 / 下单
      description: 可选。用户在搜索结果上点击、加购或下单时上报，带回搜索接口返回的 `searchId`，用于优化排序。尽力而为：搜索服务不可用时也返回成功。
      security:
        - AppKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - productId
                - event
              properties:
                productId:
                  type: string
                event:
                  type: string
                  enum:
                    - click
                    - cart
                    - order
                searchId:
                  type: string
                  maxLength: 64
                  description: 搜索接口返回的 searchId
                position:
                  type: integer
                  minimum: 1
                  description: 在搜索结果里的位置（从 1 起）
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
        '400':
          description: '`BAD_REQUEST`：productId 缺失或 event 不是 click / cart / order'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseProductsEvents
  /v1/enterprise/cart:
    get:
      tags:
        - 购物车（可选）
      summary: 购物车
      description: 可选。服务端购物车，按员工保存、换设备不丢。合计只统计还能买的行。员工已绑定企业时带 `points`：这车需要多少额度、够不够（企业为 active 且余额足够才为 true）。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Cart'
                  - type: object
                    properties:
                      points:
                        type: object
                        description: 员工已绑定企业时返回
                        properties:
                          required:
                            type: number
                            description: 需要的额度（100 = 1 元）
                          balance:
                            type: number
                          sufficient:
                            type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseCart
    delete:
      tags:
        - 购物车（可选）
      summary: 清空购物车
      description: 可选。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ok'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: deleteEnterpriseCart
  /v1/enterprise/cart/items:
    post:
      tags:
        - 购物车（可选）
      summary: 加入购物车
      description: 可选。同一商品 + SKU 已在车里时数量累加。`qty` 缺省 1。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - productId
              properties:
                productId:
                  type: string
                skuId:
                  type: string
                  description: 商品详情 skus[].skuId；skuId 为 null 的商品不要传
                qty:
                  type: integer
                  minimum: 0
      responses:
        '200':
          description: 成功，返回最新购物车
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  cart:
                    $ref: '#/components/schemas/Cart'
        '400':
          description: 缺少 productId
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: postEnterpriseCartItems
    put:
      tags:
        - 购物车（可选）
      summary: 设置数量
      description: 可选。把该商品 + SKU 的数量**设为** `qty`；`qty` 为 0 即删除。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - productId
              properties:
                productId:
                  type: string
                skuId:
                  type: string
                  description: 商品详情 skus[].skuId；skuId 为 null 的商品不要传
                qty:
                  type: integer
                  minimum: 0
      responses:
        '200':
          description: 成功，返回最新购物车
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  cart:
                    $ref: '#/components/schemas/Cart'
        '400':
          description: 缺少 productId
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: putEnterpriseCartItems
    delete:
      tags:
        - 购物车（可选）
      summary: 移出购物车
      description: 可选。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      parameters:
        - name: productId
          in: query
          required: true
          schema:
            type: string
        - name: skuId
          in: query
          required: false
          schema:
            type: string
      responses:
        '200':
          description: 成功，返回最新购物车
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  cart:
                    $ref: '#/components/schemas/Cart'
        '400':
          description: 缺少 productId
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: deleteEnterpriseCartItems
  /v1/enterprise/orders/in-transit:
    get:
      tags:
        - 结算与下单
      summary: 在途订单
      description: 「我的」页「N 个订单正在路上」：`count` 为在途订单数（在最近 50 单里统计），`items` 只给最近 3 单及各自最新物流节点（节点缓存 60 秒）。
      security:
        - AppKey: []
          Signature: []
          OpenUser: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                  items:
                    type: array
                    maxItems: 3
                    items:
                      type: object
                      properties:
                        bizOrderId:
                          type: string
                        unifiedStatus:
                          type: string
                        unifiedStatusLabel:
                          type: string
                        title:
                          type: string
                          description: 第一件商品的标题
                        imageUrl:
                          type: string
                        latest:
                          type: object
                          nullable: true
                          description: 最新物流节点；查不到为 null
                          properties:
                            desc:
                              type: string
                            time:
                              type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getEnterpriseOrdersInTransit
  /v1/access-clients/me:
    get:
      tags:
        - 接入与账户
      summary: 当前 appKey 信息
      security:
        - AppKey: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  appKey:
                    type: string
                  remark:
                    type: string
                    nullable: true
                  createdAt:
                    type: string
                    nullable: true
                  apiCallCount:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      operationId: getAccessClientsMe
  /v1/health:
    get:
      tags:
        - 接入与账户
      summary: 健康检查
      security: []
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  db:
                    type: string
                    example: ok
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          description: 依赖不可用
      operationId: getHealth
components:
  securitySchemes:
    AppKey:
      type: apiKey
      in: header
      name: x-app-key
    Signature:
      type: apiKey
      in: header
      name: x-signature
      description: 'HMAC-SHA256 签名（v2），另带 x-timestamp / x-nonce / x-sign-version: 2。算法见文档开头。'
    OpenUser:
      type: apiKey
      in: header
      name: x-open-user
      description: 终端用户标识：你系统里的用户 ID，必须取自你服务端的登录态。参与签名第 8 段。
  parameters:
    Page:
      name: page
      in: query
      schema:
        type: integer
        minimum: 1
        default: 1
  responses:
    BadRequest:
      description: 参数不合法
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: appKey 无效或已停用、签名错误、时间戳超出 ±300 秒
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: 路径不在该 appKey 的权限白名单，或业务上不允许（见 code）
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: 资源不存在，或不归属你的 appKey / 当前用户
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: 超出限流，按 Retry-After 头重试
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    Error:
      type: object
      required:
        - code
        - message
      properties:
        ok:
          type: boolean
          example: false
        code:
          type: string
          example: BAD_REQUEST
        message:
          type: string
    Ok:
      type: object
      properties:
        ok:
          type: boolean
          example: true
    Product:
      type: object
      properties:
        id:
          type: string
          description: 商品 ID，下单时原样放进 items[].productId
        externalItemId:
          type: string
        title:
          type: string
        subtitle:
          type: string
        imageUrl:
          type: string
        imageUrls:
          type: array
          items:
            type: string
        category:
          type: string
        brand:
          type: string
        price:
          type: number
          description: 售价（元）；多规格商品为最低规格价
        marketPrice:
          type: number
        shopName:
          type: string
        sales30d:
          type: number
        availability:
          type: string
          enum:
            - in_stock
            - out_of_stock
        featured:
          type: boolean
          description: 是否运营精选
        matchedSku:
          $ref: '#/components/schemas/MatchedSku'
    MatchedSku:
      type: object
      description: >-
        关键词搜索命中的规格：多规格商品、且搜索词能对应到某个规格时才有（「黑色 1000ml 保温杯」→ 黑色 / 1000ml）。带价格区间时给区间内的规格。建议卡片直接展示该规格，点进详情时用 skuId 预先选中。没有 =
        按商品展示
      properties:
        skuId:
          type: string
        specText:
          type: string
          description: 规格值，按「 / 」连接，如「黑色 / 1000ml」
        price:
          type: number
          description: 该规格的对外售价（元），与详情接口的规格价同口径；缺省 = 用商品价
        imageUrl:
          type: string
          description: 该规格的图片；缺省 = 用商品主图
    ProductPage:
      type: object
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Product'
        page:
          type: integer
        pageSize:
          type: integer
        total:
          type: integer
          description: 命中总数（带关键词时为估算值）。结果按渠道可见范围再过滤，一页可能少于 pageSize；翻页以返回为空或 page × pageSize ≥ total 判断结束
        searchId:
          type: string
          description: 带关键词搜索时返回；上报点击 / 加购 / 下单时带回
        correctedQuery:
          type: string
          description: 做了错别字纠正时实际搜的词，可提示「已为您搜索 xx」
        relaxed:
          type: boolean
          description: true = 没有同时满足全部关键词的商品，返回的是放宽后的相关商品；可提示「没有找到同时满足『…』的商品，以下是相关商品」
    SearchBody:
      type: object
      description: 全部可选
      properties:
        keyword:
          type: string
          maxLength: 100
          description: 关键词。多个条件用空格分开，每个词都要命中（标题、买家叫法、品牌、类目、规格值 / 规格名、商品参数、场景、卖点、编码等）；一件都没有时才放宽并返回 relaxed=true。4 个字及以上的词允许错一个字
        category:
          type: string
          maxLength: 100
          description: 叶子类目名，精确匹配
        brand:
          type: string
          maxLength: 100
          description: 品牌名，精确匹配
        priceMin:
          type: number
          minimum: 0
          description: 元，含。多规格商品任一可售规格的价格落在区间内即命中
        priceMax:
          type: number
          minimum: 0
          description: 元，含。与 priceMin 传反会自动对调
        inStockOnly:
          type: boolean
          description: 只要有货的；缺省不过滤
        sortBy:
          type: string
          enum:
            - price_asc
            - price_desc
            - sales_desc
          description: 缺省按相关性（同一规格满足全部条件的排前），无关键词时按更新时间。价格升序取最低规格价、降序取最高规格价
        page:
          type: integer
          minimum: 1
          default: 1
        pageSize:
          type: integer
          minimum: 1
          maximum: 60
          default: 20
    SearchRequirement:
      type: object
      description: 从 query.text 理解出来的一个条件。只是我们的理解，供参考（会随理解能力变化），不是约定
      properties:
        text:
          type: string
        role:
          type: string
          enum:
            - product
            - attribute
            - brand
            - other
          description: product 品类 / attribute 属性 / brand 品牌 / other 其他（编码）
        enforced:
          type: boolean
          description: 是否作为必须条件（决定完全符合与否）。只有有把握的条件才是 true
        why:
          type: string
          enum:
            - optional
            - vague
            - unrecognized
          description: 不作为必须条件的原因：调用方标了可选 / 模糊词（大容量、好用）/ 认不出
    SearchV2Sku:
      type: object
      description: 推荐的规格（卡片直接展示它，进详情时用 id 预选）
      properties:
        id:
          type: string
          description: 规格 ID，即详情接口的 skus[].skuId；单规格商品（详情里没有规格选择）不给
        specText:
          type: string
          description: 规格值，如「曜石黑 / 1000ml」
        specs:
          type: object
          additionalProperties:
            type: string
          description: 规格名 → 规格值
        price:
          type: number
          description: 该规格的对外售价（元），与详情接口的规格价同口径
        marketPrice:
          type: number
        imageUrl:
          type: string
          description: 规格图；没有时用商品主图
        stock:
          type: integer
        available:
          type: boolean
        chosenBy:
          type: string
          enum:
            - match
            - cheapest
            - only
          description: match 按搜索条件选出 / cheapest 条件在规格间没有区分，给价格区间内最便宜的 / only 只有一个规格
    SearchV2Hit:
      type: object
      properties:
        product:
          allOf:
            - $ref: '#/components/schemas/Product'
            - type: object
              properties:
                categoryId:
                  type: string
                  description: 叶子类目 id（仅企业购）
        sku:
          allOf:
            - $ref: '#/components/schemas/SearchV2Sku'
          nullable: true
          description: 推荐的规格；商品没有可售规格时为 null
        skuCount:
          type: integer
          description: 可售规格数
        match:
          type: object
          description: include 含 match 时返回
          properties:
            level:
              type: string
              enum:
                - exact
                - partial
                - related
              description: exact 推荐的这个规格满足全部必须条件 / partial 没有不满足的，但有判断不了或分散在不同规格上的 / related 有不满足的，或是放宽得到的
            requirements:
              type: array
              description: 每个条件在推荐规格上的判定，顺序同 interpretation.requirements
              items:
                type: object
                properties:
                  text:
                    type: string
                  state:
                    type: string
                    enum:
                      - met
                      - unmet
                      - unknown
                    description: met 满足 / unmet 不满足（如类目明确是别的品类）/ unknown 判断不了（字面上没找到不算不满足）
                  by:
                    type: string
                    description: 满足的凭据：命中的规格值原文，如「曜石黑」
    SearchV2Page:
      type: object
      properties:
        version:
          type: integer
          enum:
            - 2
          description: 响应版本，固定 2。解析前可以校验它，防止拿旧格式硬解析
        searchId:
          type: string
          description: 带 query 时返回；上报点击 / 加购 / 下单时带回
        interpretation:
          type: object
          description: 带 query.text 时返回：我们怎么理解这次查询（供参考，不是约定）
          properties:
            searched:
              type: string
              description: 纠错 / 改写后实际搜的词；与输入不同时可提示「已为您搜索 xx」
            requirements:
              type: array
              items:
                $ref: '#/components/schemas/SearchRequirement'
        hits:
          type: array
          items:
            $ref: '#/components/schemas/SearchV2Hit'
        relaxation:
          type: object
          description: 返回了不符合（related）的结果时才有：哪些必须条件没有满足。可提示「没有找到同时满足…的商品，以下是相关商品」
          properties:
            dropped:
              type: array
              items:
                type: string
        relaxHints:
          type: array
          description: 完全符合的不足 limit 时：去掉某个必须条件能有几件完全符合的。AI 助手可据此问用户要不要放宽，再把那个词放进 query.optional 重搜
          items:
            type: object
            properties:
              drop:
                type: string
              exact:
                type: integer
        total:
          type: object
          properties:
            value:
              type: integer
            exact:
              type: boolean
              description: false = 估算值
        nextCursor:
          type: string
          description: 下一页的游标；没有 = 没有下一页。未登录访客不返回
        degraded:
          type: boolean
          description: 搜索服务暂时不可用、退回查库：只按标题拆词匹配，没有 match 与推荐规格的条件判定
    PartnerOrg:
      type: object
      properties:
        orgId:
          type: string
        name:
          type: string
        status:
          type: string
          enum:
            - pending
            - active
            - disabled
          description: pending = 待平台审核；active 后才能充值与下单
        unifiedCreditCode:
          type: string
        shortName:
          type: string
        contactName:
          type: string
        adminEmail:
          type: string
        region:
          type: string
        invoice:
          $ref: '#/components/schemas/InvoiceInfo'
        invoiceReady:
          type: boolean
          description: 抬头与税号都已具备
        poolBalance:
          type: number
          description: 企业额度池余额（100 = 1 元）
        memberCount:
          type: integer
        createdAt:
          type: string
    InvoiceInfo:
      type: object
      properties:
        title:
          type: string
          description: 发票抬头，缺省 = 企业名称
        taxNo:
          type: string
          description: 税号，固定等于统一社会信用代码
        bankName:
          type: string
        bankAccount:
          type: string
        address:
          type: string
        phone:
          type: string
    PartnerMember:
      type: object
      properties:
        userId:
          type: string
          description: 你自己的用户 ID（即该员工请求时的 x-open-user）
        name:
          type: string
        phone:
          type: string
          description: 接入方声明的手机号，平台不验证
        role:
          type: string
          enum:
            - owner
            - admin
            - member
        status:
          type: string
          enum:
            - active
            - suspended
            - offboarded
        balance:
          type: number
          description: 员工额度余额（100 = 1 元）
        boundAt:
          type: string
    Lot:
      type: object
      description: 一批发放的额度
      properties:
        id:
          type: string
        name:
          type: string
        theme:
          type: string
        themeLabel:
          type: string
        amount:
          type: number
          description: 发放额度
        remaining:
          type: number
          description: 剩余额度
        grantedAt:
          type: string
        expiresAt:
          type: string
          nullable: true
    PointsSettings:
      type: object
      properties:
        checkinEnabled:
          type: boolean
        checkinDailyAmount:
          type: number
        checkinStreakDays:
          type: number
        checkinStreakBonus:
          type: number
        pointsExpiryDays:
          type: number
          description: 发放默认有效期（天），1–90
    OrgBill:
      type: object
      properties:
        id:
          type: string
        period:
          type: string
          example: 2026-09
        granted:
          type: number
        used:
          type: number
        refunded:
          type: number
        returned:
          type: number
        serviceFee:
          type: number
        adjust:
          type: number
        adjustReason:
          type: string
        payable:
          type: number
        paid:
          type: number
        status:
          type: string
          description: generated / confirmed / paid / closed 等
        generatedAt:
          type: string
        confirmedAt:
          type: string
        paidAt:
          type: string
    Budget:
      type: object
      properties:
        id:
          type: string
        periodKind:
          type: string
          enum:
            - year
            - quarter
            - month
        period:
          type: string
        category:
          type: string
        departmentId:
          type: string
        amount:
          type: number
        alertPct:
          type: integer
        overspendPolicy:
          type: string
          enum:
            - allow
            - block
    BudgetLine:
      allOf:
        - $ref: '#/components/schemas/Budget'
        - type: object
          properties:
            granted:
              type: number
            used:
              type: number
            remaining:
              type: number
            ratePct:
              type: number
            alert:
              type: string
              enum:
                - none
                - warn
                - over
    TaskSubmitField:
      type: object
      required:
        - key
        - type
        - label
      properties:
        key:
          type: string
          pattern: ^[A-Za-z][A-Za-z0-9_]{0,31}$
        type:
          type: string
          enum:
            - text
            - image
            - file
            - link
        label:
          type: string
          maxLength: 20
        required:
          type: boolean
        max:
          type: integer
          description: text 字数 / link 长度 / image、file 个数（≤9）上限
    TaskPickupInfo:
      type: object
      description: 消耗型任务的领取信息
      properties:
        location:
          type: string
        timeText:
          type: string
        startAt:
          type: string
        endAt:
          type: string
        rules:
          type: string
    TaskEntry:
      type: object
      description: 员工在某个任务上的参与记录
      properties:
        id:
          type: string
        status:
          type: string
          enum:
            - signed_up
            - in_progress
            - submitted
            - rejected
            - completed
            - pending_writeoff
            - refunded
            - expired
        redeemCode:
          type: string
          nullable: true
          description: 需核销的兑换才有领取码
        rewardAmount:
          type: number
          nullable: true
        spentAmount:
          type: number
          nullable: true
        updatedAt:
          type: string
    TaskSubmission:
      type: object
      properties:
        id:
          type: string
        version:
          type: integer
        status:
          type: string
          enum:
            - pending
            - approved
            - rejected
            - superseded
        payload:
          type: object
          additionalProperties: true
          description: text / link 为字符串；image / file 为 [{ key, url, name }]，url 为短时签名链接
        rejectReason:
          type: string
          nullable: true
        createdAt:
          type: string
        reviewedAt:
          type: string
          nullable: true
    TaskMember:
      type: object
      properties:
        accountId:
          type: string
        name:
          type: string
        avatarUrl:
          type: string
          nullable: true
        departmentName:
          type: string
          nullable: true
    Task:
      type: object
      description: 员工视角的任务
      properties:
        id:
          type: string
        title:
          type: string
        category:
          type: string
        categoryLabel:
          type: string
        description:
          type: string
        coverUrl:
          type: string
          nullable: true
        settleMode:
          type: string
          enum:
            - reward
            - consume
        points:
          type: number
          description: 每人奖励或消耗的额度（100 = 1 元）
        quota:
          type: integer
          nullable: true
          description: null = 不限
        remaining:
          type: integer
          nullable: true
        startAt:
          type: string
        endAt:
          type: string
        phase:
          type: string
          enum:
            - not_started
            - ongoing
            - ended
        needSignup:
          type: boolean
        signupFull:
          type: boolean
        completeMode:
          type: string
          enum:
            - direct
            - submit
        reviewMode:
          type: string
          enum:
            - auto
            - manual
        needWriteoff:
          type: boolean
        scopeText:
          type: string
          description: 如「全体员工」「财务部、仓储部」
        submitSchema:
          type: array
          items:
            $ref: '#/components/schemas/TaskSubmitField'
        pickupInfo:
          $ref: '#/components/schemas/TaskPickupInfo'
        myEntry:
          allOf:
            - $ref: '#/components/schemas/TaskEntry'
          nullable: true
        lastSubmission:
          allOf:
            - $ref: '#/components/schemas/TaskSubmission'
          nullable: true
          description: 仅详情接口返回
    OrgTask:
      type: object
      description: 管理视角的任务
      properties:
        id:
          type: string
        title:
          type: string
        category:
          type: string
        categoryLabel:
          type: string
        description:
          type: string
        coverUrl:
          type: string
          nullable: true
        settleMode:
          type: string
          enum:
            - reward
            - consume
        points:
          type: number
          description: 每人奖励或消耗的额度（100 = 1 元）
        quota:
          type: integer
          nullable: true
          description: null = 不限
        remaining:
          type: integer
          nullable: true
        startAt:
          type: string
        endAt:
          type: string
        phase:
          type: string
          enum:
            - not_started
            - ongoing
            - ended
        needSignup:
          type: boolean
        signupFull:
          type: boolean
        completeMode:
          type: string
          enum:
            - direct
            - submit
        reviewMode:
          type: string
          enum:
            - auto
            - manual
        needWriteoff:
          type: boolean
        scopeText:
          type: string
          description: 如「全体员工」「财务部、仓储部」
        submitSchema:
          type: array
          items:
            $ref: '#/components/schemas/TaskSubmitField'
        pickupInfo:
          $ref: '#/components/schemas/TaskPickupInfo'
        status:
          type: string
          enum:
            - active
            - ended
            - cancelled
        scopeKind:
          type: string
          enum:
            - all
            - departments
            - members
        scopeIds:
          type: array
          items:
            type: string
        signupQuota:
          type: integer
          nullable: true
        budgetFrozen:
          type: number
          description: 已冻结的预算
        stats:
          type: object
          properties:
            signedUp:
              type: integer
            joined:
              type: integer
            completed:
              type: integer
            redeemed:
              type: integer
            pendingReview:
              type: integer
            pendingWriteoff:
              type: integer
        version:
          type: integer
          description: 编辑时作为 expectedVersion 带回
        editRules:
          type: object
          description: 前端据此置灰，服务端照样校验
          properties:
            locked:
              type: array
              items:
                type: string
              description: 当前不可改的字段名
            minQuota:
              type: integer
            pointsEditable:
              type: boolean
            startAtEditable:
              type: boolean
            minSignupQuota:
              type: integer
    ProductDetail:
      allOf:
        - $ref: '#/components/schemas/Product'
        - type: object
          properties:
            subtitle:
              type: string
            description:
              type: string
            detailImages:
              type: array
              items:
                type: string
            specs:
              type: object
              additionalProperties:
                type: string
            skus:
              type: array
              description: 只有一个规格且无 skuId 时不返回
              items:
                type: object
                properties:
                  skuId:
                    type: string
                    nullable: true
                    description: null = 下单时不传 skuId；"0" 是真实 id，要原样传
                  specs:
                    type: object
                    additionalProperties:
                      type: string
                  price:
                    type: number
                  stock:
                    type: number
                  image:
                    type: string
    Receiver:
      type: object
      description: 收货人。省、市、区用名称（不是区划码），全部必填；名称请用 `GET /v1/divisions` 逐级选（乡镇街道放 `street`），叫法不一致上游会以 `321000 地址没有找到` 拒单
      required:
        - name
        - mobile
        - province
        - city
        - area
        - addressDetail
      properties:
        name:
          type: string
        mobile:
          type: string
        province:
          type: string
          example: 浙江省
          description: 省名称，取自 /v1/divisions
        city:
          type: string
          example: 杭州市
          description: 市名称，取自 /v1/divisions
        area:
          type: string
          example: 西湖区
          description: 区 / 县名称，取自 /v1/divisions
        street:
          type: string
          description: 乡镇街道名称（/v1/divisions 第四级），建议传：会拼在详细地址前面，地址更容易被上游认出
        addressDetail:
          type: string
    OrderItem:
      type: object
      properties:
        productId:
          type: string
        title:
          type: string
        imageUrl:
          type: string
        skuId:
          type: string
        skuText:
          type: string
        price:
          type: number
        qty:
          type: integer
        lineTotal:
          type: number
    Order:
      type: object
      properties:
        bizOrderId:
          type: string
          description: 订单号
        outOrderId:
          type: string
        unifiedStatus:
          type: string
          enum:
            - CREATED
            - PAID
            - SHIPPED
            - DELIVERED
            - COMPLETED
            - CANCELED
            - REFUNDING
            - REFUNDED
            - REFUND_REJECTED
          description: 归一化订单状态，按它做业务判断
        unifiedStatusLabel:
          type: string
        displayStatus:
          type: string
        totalFee:
          type: number
        postFee:
          type: number
        payable:
          type: number
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'
        subOrders:
          type: array
          description: 子订单；售后按子订单发起
          items:
            type: object
            properties:
              bizOrderId:
                type: string
                description: 子订单号
              itemId:
                type: string
              skuId:
                type: string
              itemName:
                type: string
              itemPrice:
                type: number
              buyAmount:
                type: number
        receiver:
          type: object
        remark:
          type: string
        createdAt:
          type: string
        updatedAt:
          type: string
    Refund:
      type: object
      properties:
        refundId:
          type: string
        bizOrderId:
          type: string
        subOrderId:
          type: string
        status:
          type: integer
          description: 0 已撤销 / 1–8 处理中到完成，展示用 statusLabel
        statusLabel:
          type: string
        amount:
          type: number
        reason:
          type: string
        createdAt:
          type: string
    Invoice:
      type: object
      properties:
        id:
          type: string
        purchaseOrderId:
          type: string
        title:
          type: string
        taxNo:
          type: string
        amount:
          type: string
        status:
          type: string
          enum:
            - pending
            - applied
            - issued
            - failed
            - rejected
          description: applied = 上游已受理；issued = 已开出
        upstreamInvoiceNos:
          type: array
          items:
            type: string
        fileUrl:
          type: string
          description: 发票下载地址（issued 后）
        upstreamError:
          type: string
          description: failed 时上游给的原因
        createdAt:
          type: string
    Cart:
      type: object
      properties:
        items:
          type: array
          items:
            type: object
            properties:
              productId:
                type: string
              externalItemId:
                type: string
              title:
                type: string
              imageUrl:
                type: string
              skuId:
                type: string
              skuText:
                type: string
                description: 规格文案，如「黑色 / L」
              price:
                type: number
              qty:
                type: integer
              lineTotal:
                type: number
              available:
                type: boolean
                description: 缺省 = 能买；加购后下架、不可售、售罄时为 false
              unavailableReason:
                type: string
                description: 不能买的原因，可直接展示
        totalQty:
          type: integer
          description: 只统计还能买的行
        totalAmount:
          type: number
          description: 元；只统计还能买的行
