Skip to content

feat(admin): product contract fields in plan drawer, price catalog page, template read API - #11

Merged
YunfanGoForIt merged 1 commit into
mainfrom
feat/admin-product-ui-20261021
Oct 20, 2026
Merged

YunfanGoForIt merged 1 commit into
mainfrom
feat/admin-product-ui-20261021

Conversation

@YunfanGoForIt

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

Important

本 PR 为 AI 辅助生成(提交者非仓库历史核心开发者),描述已人工整理。

📝 变更描述 / Description

让管理员后台真正能管理商品契约,分三部分:

  1. 后端模板管理 API(controller/product_template.go + router/api-router.go):在现有 /api/subscription/admin 组下新增 GET /templates、GET /templates/:id、PUT /templates/:id。PUT 仅允许修改非 locked 模板的运营字段(display_name、display_metadata、min_margin_percent);locked 模板或任何契约关键字段(product_type、price_rules、billing_multiplier、duration_days、model_scope、allowed_channels、max_upstream_cost 等)的变更返回 403 并提示走代码迁移流程。locked 拒绝复用 model.UpdateProductTemplate 的既有守卫;缓存失效由 saveProductTemplate → InvalidateProductTemplateCache 完成(控制器侧亦显式调用一次)。

  2. 套餐抽屉补全(web/src/features/subscriptions/):新增「商品契约」section——product_type(创建时从模板列表选择,编辑时只读)、product_code(创建可写、编辑只读)、model_scope(MultiSelect 多选,getEnabledModels() 数据源,逗号分隔序列化)、billing_multiplier、price_version、product_family、product_tier,以及 listed/redemption_enabled/course_eligible/fallback_allowed 开关。选定 product_type 后展示模板只读约束提示(允许价格列表、固定时长、计费倍率、允许模型集合、限购数),并按模板 model_scope 过滤多选选项。redemption_enabled 因 PUT 明确保留旧值(PATCH 为权威路径),编辑保存后通过 PATCH /plans/:id 单独同步。模板校验失败的服务端错误由 axios 拦截器 toast 展示。

  3. 价格目录页(web/src/features/product-prices/ + 路由 /product-prices):版本化价格列表(product_type / model / price_version / 售价分量 / 生效时间 / 启用状态)、「新增版本」抽屉(四组价格分量 + 计费表达式 + 允许渠道)、启停确认对话框。价格行不可变(后端 BeforeUpdate 强制),UI 不提供编辑入口。侧边栏 admin 组登记 Product Prices 项及模块开关映射。

模板管理页本阶段不做,抽屉内模板信息均走只读 API。

🚀 变更类型 / Type of change

  • ✨ 新功能 (New feature)

🔗 关联任务 / Related Issue

  • 无(IF.Link Phase 3 商品化子任务)

✅ 提交前检查项 / Checklist

  • 人工确认: 描述已整理撰写,非原始 AI 输出直接粘贴。
  • 非重复提交: 已确认无重复 PR。
  • 变更理解: 已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试(见下方证明)。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

  • 后端:GOWORK=off go build ./...、go vet ./controller ./model、go test ./controller -count=1 全部通过(含新增 product_template_test.go 5 个用例:locked 403、关键字段 403、回声字段放行、display 字段更新、min_margin 越界拒绝)。
  • 前端:bun run build、bun run typecheck、bun run test(51 个隔离测试文件全过,含新增 plan-form / template-hints / price-form 共 23 个用例)。
  • Lint:本次涉及文件 oxlint 0 error(仓库存量文件在 main 上已有 lint error,与本次无关)。

…ge, template read API

- add AdminListProductTemplates/AdminGetProductTemplate/AdminUpdateProductTemplate
  under /api/subscription/admin/templates; PUT only accepts display_name,
  display_metadata, min_margin_percent on unlocked templates, answers 403 for
  locked templates or contract-key field changes (migration path)
- subscriptions plan drawer gains a Product Contract section: product_type
  (create-only select), product_code, model_scope multi-select filtered by the
  template scope, billing_multiplier, price_version, product_family, tier and
  the listed/redemption/course/fallback switches, with read-only template
  constraint hints (allowed prices, duration, multiplier, model scope)
- new /product-prices admin page for the immutable versioned price catalog:
  list, add-version drawer, enable/disable toggle
- sidebar admin group gains a Product Prices entry; i18n keys synced
@YunfanGoForIt

Copy link
Copy Markdown
Author

维护者评审通过(2026-10-21):

  • 套餐抽屉补齐商品契约字段(product_type/model_scope 多选/倍率/价格版本等),模型多选按模板范围过滤,直接解决运营反馈的编辑套餐不能改模型;
  • 价格目录页只增不改、符合不可变版本化设计;模板 API 只读 + 受控更新(locked 拒绝复用模型层);
  • 403 偏离 200+success:false 惯例已知悉,前端拦截器兼容,接受;
  • i18n sync 的 base 切换与存量 zh-only key 回填已修正,未跟踪诊断文件未提交,处理得当;
  • CI 6/6 绿。

AI 辅助实现,维护者已核对。

@YunfanGoForIt
YunfanGoForIt marked this pull request as ready for review October 20, 2026 18:31
@YunfanGoForIt
YunfanGoForIt merged commit 1c415d2 into main Oct 20, 2026
6 checks passed
@YunfanGoForIt
YunfanGoForIt deleted the feat/admin-product-ui-20261021 branch October 20, 2026 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant