openapi: 3.0.3 # 契约 #8 API | 模块:biz(B/G 端轻量定制 lead form 信息流:询单→报价→进度→demo 验收)| owner:WS5,全员 review # 设计依据:docs/agent-specs/2026-06-11-Wave4-community-biz-execution.md §4.2/§4.5(D-A 轻量 lead form 先行,覆盖 6 P0)。 # 端:/app-api(客户侧 game-studio:提单 / 我的订单 / 进度看板 / 选模板 / 试玩反馈确认,用户 Token + Mapper 强制 getLoginUserId() 归属谓词,WS3) # /admin-api(运营侧 game-admin:处理队列 / 代客发起 / 指派 / 报价 / 推进状态机 / 线下签署兜底,RBAC @PreAuthorize,WS4) # 前缀由 huijing 框架按 controller.app/admin 包名自动添加(@RequestMapping 只写 /biz);本文件 path 直接写含前缀的完整对外路径。 # 错误码段(落 game 业务段 1-110-***-***,模块归属决定,contracts/README.md §四 已在册): # 1-110-001-*** = 询单(询单不存在/非本人订单/状态机非法流转…) # 1-110-002-*** = 报价(报价不存在/询单状态不允许报价…) # 1-110-003-*** = 进度(非法状态推进/demo 未就绪不允许进入待验收…) # 1-110-004-*** = 验收(验收记录不存在/未到待验收态/重复确认…) # 响应统一 Huijing CommonResult 信封:{ code, data, msg };code=0 成功。 # 状态机:game_biz_lead.status 单线性五态 0待跟进→1已报价→2制作中→3待验收→4已交付; # 非法流转由 BizLeadService 写前校验拒绝(复用 project ProjectServiceImpl 流转校验内联范式,无独立 StateService,不引 Flowable)。 # 归属隔离(R-medium PII 红线):客户侧 /app-api/biz/* 必须在 Mapper 查询里强制以登录态 user_id(customer_user_id)作谓词 enforce # (可信边界,非 @DataPermission),前端不够;客户只见自己询单/进度/报价。 # 资金流边界(D-A):本波只到状态机走通 + 线下签署后台标记兜底(signed_offline);收款(T-BIZ-08)/在线电子签章(T-BIZ-03)/分账留 M4。 # demo 试玩取包复用 runtime 真实双路由(见文末 paths 注释),不在 biz 自建取包端点。 # 权限点登记(§7.4 必做):biz:lead:query/create/assign/advance、biz:quote:create/query、biz:acceptance:sign # 需在 huijing system_menu 登记后 RBAC 才放行(范本=project:review:query 登记方式)。 # 边界 OUT:不接 ip seam(D-C 维持 D5 推迟,直接复用 aigc 4 模板 + runtime 沙箱);P-BIZ-11 学生防沉迷已划归 compliance(不计入 biz)。 info: title: 绘境AI biz 模块 API version: 1.0.0 description: >- B/G 端轻量定制 lead form 信息流闭环:客户在线提单(询单落库即开状态机)→ 运营报价(参数化估价,报价≠可支付订单)→ 进度看板(状态机各节点流转时间线)→ demo 试玩验收(复用 aigc 4 模板生成 + runtime 沙箱取包,客户反馈→确认)。 资金流(收款/分账/在线签章)留 M4,本波仅线下签署后台标记兜底。 覆盖产品功能 P-BIZ-01(在线提单)/02(选模板)/03(进度看板)/04(试玩验收)/08(报价编排)/12(运营代客发起)。 前端据此 vite-plugin-mock 自动生成 mock。 servers: - url: http://localhost:48080 description: 本地(Swagger/Knife4j http://localhost:48080/doc.html) paths: # =========================================================================== # 客户侧(产品端 game-studio,WS3):提单 / 我的订单 / 详情 / 进度看板 / 选模板 / 试玩反馈确认 # 全部用户 Token,Mapper 强制 customer_user_id = getLoginUserId() 归属谓词,客户只见自己订单。 # =========================================================================== /app-api/biz/leads: post: tags: [app-biz] summary: 提交定制需求询单(P-BIZ-01) description: >- 客户在线提交定制需求,落库即开状态机=待跟进0 + 落 game_biz_progress 首条 to_status=0。 customer_user_id = getLoginUserId()。 requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/BizLeadCreateReqVO' } responses: '200': description: 新建询单 ID(CommonResult) content: application/json: schema: type: object properties: code: { type: integer, example: 0 } data: { type: integer, format: int64, description: '新建询单 ID' } msg: { type: string, example: '' } /app-api/biz/leads/my: get: tags: [app-biz] summary: 我的定制订单列表(P-BIZ-03) description: >- 我的定制订单列表,customer_user_id 过滤(客户只见自己)。 归属隔离:Mapper 强制 customer_user_id = getLoginUserId() 谓词(可信边界)。 parameters: - { name: status, in: query, required: false, schema: { type: integer, enum: [0, 1, 2, 3, 4] }, description: '状态筛选(可选)' } - { name: cursor, in: query, required: false, schema: { type: integer, format: int64 }, description: '游标分页(可选)' } - { name: size, in: query, required: false, schema: { type: integer, default: 20 }, description: '每页条数' } responses: '200': description: 我的订单分页(CommonResult) content: application/json: schema: type: object properties: code: { type: integer, example: 0 } data: type: object properties: list: { type: array, items: { $ref: '#/components/schemas/BizLeadRespVO' } } nextCursor: { type: integer, format: int64, nullable: true } msg: { type: string, example: '' } /app-api/biz/leads/{id}: get: tags: [app-biz] summary: 询单详情 description: >- 询单详情:含当前状态 / 最新报价 / 进度时间线 / demo 可预览判定。 归属隔离:service 校验 customer_user_id == getLoginUserId(),非本人订单拒绝(1-110-001-***)。 parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '询单 ID' } responses: '200': description: 询单详情(CommonResult) content: application/json: schema: type: object properties: code: { type: integer, example: 0 } data: { $ref: '#/components/schemas/BizLeadDetailRespVO' } msg: { type: string, example: '' } /app-api/biz/leads/{id}/progress: get: tags: [app-biz] summary: 进度看板时间线(P-BIZ-03) description: 进度看板时间线(game_biz_progress 按 create_time)。归属隔离同上。 parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '询单 ID' } responses: '200': description: 进度时间线(CommonResult) content: application/json: schema: type: object properties: code: { type: integer, example: 0 } data: { type: array, items: { $ref: '#/components/schemas/BizProgressRespVO' } } msg: { type: string, example: '' } /app-api/biz/templates: get: tags: [app-biz] summary: 按场景检索可选模板(P-BIZ-02) description: 按场景检索可选玩法模板(复用 aigc 4 模板 clicker/merge/idle/tycoon)。 parameters: - { name: bizType, in: query, required: false, schema: { type: integer, enum: [1, 2, 3] }, description: '定制场景:1品牌营销 2文旅 3通用定制(可选)' } responses: '200': description: 可选模板列表(CommonResult) content: application/json: schema: type: object properties: code: { type: integer, example: 0 } data: { type: array, items: { $ref: '#/components/schemas/BizTemplateRespVO' } } msg: { type: string, example: '' } /app-api/biz/acceptances/{leadId}/feedback: post: tags: [app-biz] summary: 客户试玩后提交反馈(P-BIZ-04) description: 客户试玩 demo 后提交反馈(落 game_biz_acceptance.feedback)。归属隔离:询单须属当前客户。 parameters: - { name: leadId, in: path, required: true, schema: { type: integer, format: int64 }, description: '询单 ID' } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/BizFeedbackReqVO' } responses: '200': description: CommonResult content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } } /app-api/biz/acceptances/{leadId}/confirm: post: tags: [app-biz] summary: 客户确认验收(P-BIZ-04) description: >- 客户确认验收,落 confirm_status=1 + confirmed_time,状态机 3待验收→4已交付。 归属隔离:询单须属当前客户;service 校验当前为待验收态(1-110-004-***)。 parameters: - { name: leadId, in: path, required: true, schema: { type: integer, format: int64 }, description: '询单 ID' } requestBody: required: false content: application/json: schema: type: object properties: demoVersionId: { type: integer, format: int64, description: '确认的 demo 版本 ID' } responses: '200': description: CommonResult content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } } # --------------------------------------------------------------------------- # demo 试玩取包:复用 runtime 真实双路由,不在 biz 自建端点(评审版 R2-3,两条须写全) # GET /app-api/runtime/package/{versionId} —— 清单 meta(CommonResult), # biz 看板「是否可预览」判定走此条; # GET /app-api/runtime/package/{versionId}/manifest —— 原始 JSON,宿主 sha256 比对后注入。 # (仅文档声明复用,端点定义见 contracts/api-schemas/runtime.yaml,biz 不重复定义。) # --------------------------------------------------------------------------- # =========================================================================== # 运营侧(管理端 game-admin,WS4):处理队列 / 代客发起 / 指派 / 报价 / 推进状态机 / 线下签署兜底 # 全部 RBAC @PreAuthorize,权限点需在 system_menu 登记(§7.4)。 # =========================================================================== /admin-api/biz/leads/page: get: tags: [admin-biz] summary: 处理队列(按 owner/status/bizType 筛选) description: '运营处理队列分页。权限点:biz:lead:query。' parameters: - { name: ownerUserId, in: query, required: false, schema: { type: integer, format: int64 }, description: '按负责人筛选(可选)' } - { name: status, in: query, required: false, schema: { type: integer, enum: [0, 1, 2, 3, 4] }, description: '按状态筛选(可选)' } - { name: bizType, in: query, required: false, schema: { type: integer, enum: [1, 2, 3] }, description: '按场景筛选(可选)' } - { name: pageNo, in: query, required: false, schema: { type: integer, default: 1 }, description: '页码' } - { name: pageSize, in: query, required: false, schema: { type: integer, default: 10 }, description: '每页条数' } responses: '200': description: 处理队列分页(CommonResult) content: application/json: schema: type: object properties: code: { type: integer, example: 0 } data: type: object properties: list: { type: array, items: { $ref: '#/components/schemas/BizLeadRespVO' } } total: { type: integer, format: int64 } msg: { type: string, example: '' } /admin-api/biz/leads: post: tags: [admin-biz] summary: 运营代客发起定制单(P-BIZ-08/12) description: '运营代客发起定制单(customer_user_id 可空)。权限点:biz:lead:create。' requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/BizLeadCreateReqVO' } responses: '200': description: 新建询单 ID(CommonResult) content: application/json: schema: type: object properties: code: { type: integer, example: 0 } data: { type: integer, format: int64 } msg: { type: string, example: '' } /admin-api/biz/leads/{id}/assign: put: tags: [admin-biz] summary: 认领/指派负责人 description: '认领/指派负责人(owner_user_id)。权限点:biz:lead:assign。' parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '询单 ID' } requestBody: required: true content: application/json: schema: type: object properties: ownerUserId: { type: integer, format: int64, description: '负责人用户 ID' } responses: '200': description: CommonResult content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } } /admin-api/biz/leads/{id}/quotes: post: tags: [admin-biz] summary: 报价输出(P-BIZ-08) description: >- 报价输出(参数化估价,报价≠可支付订单);状态机 0待跟进→1已报价。quote_no 由 service 串行 max+1 生成。 权限点:biz:quote:create。 parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '询单 ID' } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/BizQuoteCreateReqVO' } responses: '200': description: 报价 ID(CommonResult) content: application/json: schema: type: object properties: code: { type: integer, example: 0 } data: { type: integer, format: int64 } msg: { type: string, example: '' } get: tags: [admin-biz] summary: 报价历史 description: '报价历史(按询单查)。权限点:biz:quote:query。' parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '询单 ID' } responses: '200': description: 报价历史列表(CommonResult) content: application/json: schema: type: object properties: code: { type: integer, example: 0 } data: { type: array, items: { $ref: '#/components/schemas/BizQuoteRespVO' } } msg: { type: string, example: '' } /admin-api/biz/leads/{id}/advance: post: tags: [admin-biz] summary: 推进状态机(P-BIZ-03) description: >- 推进状态机(→2制作中 / →3待验收,→3 守 demo 可预览即 demoVersionId 必填且 runtime 包就绪); 落 game_biz_progress 流转记录。权限点:biz:lead:advance。 parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '询单 ID' } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/BizAdvanceReqVO' } responses: '200': description: CommonResult content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } } /admin-api/biz/acceptances/{id}/sign-offline: put: tags: [admin-biz] summary: 线下签署后台标记兜底(P-BIZ-04) description: >- 线下签署后台标记兜底(signed_offline=1),M4 接在线签章前的过渡手段。权限点:biz:acceptance:sign。 parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '验收记录 ID' } responses: '200': description: CommonResult content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } } components: schemas: CommonResultBoolean: type: object description: Huijing 统一响应信封(Boolean 数据) properties: code: { type: integer, example: 0 } data: { type: boolean, example: true } msg: { type: string, example: '' } BizLeadCreateReqVO: type: object description: 定制询单创建请求(客户自助 / 运营代客共用) required: [bizType, title] properties: bizType: { type: integer, enum: [1, 2, 3], description: '定制场景:1品牌营销 2文旅 3通用定制' } title: { type: string, maxLength: 120, description: '需求标题' } sceneDesc: { type: string, maxLength: 2000, description: '场景需求描述' } contactName: { type: string, maxLength: 64, description: '联系人' } contactPhone: { type: string, maxLength: 32, description: '联系电话' } company: { type: string, maxLength: 128, description: '企业/机构名称' } templateId: { type: string, maxLength: 64, description: '选定的玩法模板 ID(可选)' } customerUserId: { type: integer, format: int64, nullable: true, description: '客户用户 ID(运营代客发起可填,自助提单取登录态)' } BizLeadRespVO: type: object description: 询单列表项 properties: id: { type: integer, format: int64, description: '询单 ID' } bizType: { type: integer, description: '定制场景:1品牌营销 2文旅 3通用定制' } title: { type: string, description: '需求标题' } status: { type: integer, description: '状态机:0待跟进 1已报价 2制作中 3待验收 4已交付' } ownerUserId: { type: integer, format: int64, nullable: true, description: '跟进负责人用户 ID' } demoVersionId: { type: integer, format: int64, nullable: true, description: 'demo 预览版本 ID' } createTime: { type: string, format: date-time, description: '创建时间' } updateTime: { type: string, format: date-time, description: '更新时间' } BizLeadDetailRespVO: type: object description: 询单详情(含最新报价 / 进度时间线 / demo 可预览判定) properties: lead: { $ref: '#/components/schemas/BizLeadRespVO' } latestQuote: { $ref: '#/components/schemas/BizQuoteRespVO' } progressList: { type: array, items: { $ref: '#/components/schemas/BizProgressRespVO' } } demoPreviewable: { type: boolean, description: 'demo 是否可预览(demoVersionId 非空且 runtime 包就绪)' } BizQuoteCreateReqVO: type: object description: 报价创建请求(参数化估价表单) required: [amountFen] properties: amountFen: { type: integer, format: int64, description: '报价金额(分,与 trade 同口径;本波仅展示不收款)' } serviceItems: { type: string, maxLength: 1000, description: '服务项明细(编排内容)' } validDays: { type: integer, default: 30, description: '报价有效天数' } remark: { type: string, maxLength: 500, description: '备注' } BizQuoteRespVO: type: object description: 报价记录 properties: id: { type: integer, format: int64, description: '报价 ID' } leadId: { type: integer, format: int64, description: '所属询单 ID' } quoteNo: { type: integer, description: '报价版本号' } amountFen: { type: integer, format: int64, description: '报价金额(分)' } serviceItems: { type: string, description: '服务项明细' } validDays: { type: integer, description: '报价有效天数' } remark: { type: string, description: '备注' } createTime: { type: string, format: date-time, description: '创建时间' } BizProgressRespVO: type: object description: 进度工单(看板时间线项) properties: id: { type: integer, format: int64, description: '进度工单 ID' } fromStatus: { type: integer, nullable: true, description: '流转前状态(首条 null)' } toStatus: { type: integer, description: '流转后状态(0-4)' } operatorUserId: { type: integer, format: int64, nullable: true, description: '操作人用户 ID' } note: { type: string, description: '进度说明' } createTime: { type: string, format: date-time, description: '流转时间' } BizTemplateRespVO: type: object description: 可选玩法模板(复用 aigc 4 模板) properties: templateId: { type: string, description: '模板 ID(clicker/merge/idle/tycoon)' } name: { type: string, description: '模板名称' } bizType: { type: integer, description: '适配场景:1品牌营销 2文旅 3通用定制' } description: { type: string, description: '模板说明' } BizFeedbackReqVO: type: object description: 客户试玩反馈请求 required: [demoVersionId] properties: demoVersionId: { type: integer, format: int64, description: 'demo 版本 ID(runtime game_version.id)' } feedback: { type: string, maxLength: 1000, description: '客户试玩反馈' } BizAdvanceReqVO: type: object description: 状态机推进请求(运营) required: [toStatus] properties: toStatus: { type: integer, enum: [2, 3], description: '推进目标状态:2制作中 3待验收' } note: { type: string, maxLength: 500, description: '进度说明' } demoVersionId: { type: integer, format: int64, nullable: true, description: 'demo 版本 ID(→3待验收时必填,runtime 包须就绪)' }