Skip to content

feat(subscription): 支持订阅套餐模型限制功能#4564

Open
wans10 wants to merge 7 commits intoQuantumNous:mainfrom
wans10:main
Open

feat(subscription): 支持订阅套餐模型限制功能#4564
wans10 wants to merge 7 commits intoQuantumNous:mainfrom
wans10:main

Conversation

@wans10
Copy link
Copy Markdown
Contributor

@wans10 wans10 commented Apr 30, 2026

⚠️ 提交说明 / PR Notice

  • 在 SubscriptionPlan 模型中增加 model_limits 字段及相关校验逻辑
  • 实现订阅预扣费时的模型权限检查,确保请求模型在套餐允许范围内
  • 优化错误提示:区分“模型不受支持”与“订阅额度不足”两种异常情况
  • 在管理后台(Classic UI)增加模型限制配置界面,支持带图标的模型选择
  • 在订阅列表和选购卡片中展示可用模型限制信息
  • 同步更新数据库迁移 DDL 及 8 种语言的 i18n 翻译

📝 变更描述 / Description

本次变更实现了订阅套餐的“模型限制”功能。通过在 SubscriptionPlan 模型中引入 model_limits 字段,管理员可以精确控制每个订阅套餐可调用的模型范围。

核心逻辑说明:

  1. 权限校验:在 PreConsumeUserSubscription 的事务流中新增了模型权限前置检查。系统会遍历用户的所有活跃订阅,只有同时满足“模型授权”和“余额充足”的订阅才会被选中进行扣费。
  2. UX 优化:引入了错误回溯机制。如果用户拥有可用订阅但均因模型不匹配而被跳过,系统将返回明确的 no subscription allows model X 错误,而非含糊的额度不足提示。
  3. UI/UX 集成:在 Classic 前端实现了带图标的多选下拉框,方便管理员从现有模型库中快速配置限制列表,并在用户端卡片中清晰展示限制状态(如“可用模型:5 个”及悬浮列表)。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix)
  • ✨ 新功能 (New feature)
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

image

Summary by CodeRabbit

  • New Features

    • Subscription plans can restrict which AI models are allowed per plan (leave empty = no restriction).
    • Admin changes to model restrictions are now persisted.
    • Plan details, popovers and benefits show available-model count and tooltip with model list.
    • Subscription edit modal adds a multi-select model picker; i18n updated across locales.
  • Bug Fixes

    • Returns a distinct error when no active plan permits a requested model.

- 在 SubscriptionPlan 模型中增加 model_limits 字段及相关校验逻辑
- 实现订阅预扣费时的模型权限检查,确保请求模型在套餐允许范围内
- 优化错误提示:区分“模型不受支持”与“订阅额度不足”两种异常情况
- 在管理后台(Classic UI)增加模型限制配置界面,支持带图标的模型选择
- 在订阅列表和选购卡片中展示可用模型限制信息
- 同步更新数据库迁移 DDL 及 8 种语言的 i18n 翻译
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds per-plan model restrictions: DB schema adds two columns, backend persists them and enforces allowed models during pre-consume checks, and frontend + i18n provide configuration UI and display of plan model limits.

Changes

Cohort / File(s) Summary
Database Schema
model/main.go
Adds model_limits_enabled (numeric, default 0) and model_limits (text) to subscription_plans; updates initial creation and runs ALTER TABLE ... ADD COLUMN if missing.
Subscription Model & Logic
model/subscription.go
Adds ModelLimitsEnabled and ModelLimits fields plus helpers (GetModelLimits, GetModelLimitsMap, IsModelAllowed); updates PreConsumeUserSubscription to ignore plans that disallow the requested model and return a distinct error when no active plan permits the model.
Backend API
controller/subscription.go
AdminUpdateSubscriptionPlan now includes model_limits_enabled and model_limits in the GORM Updates(...) payload so plan model limit settings are persisted.
Frontend — Table / Popover
web/classic/src/components/table/subscriptions/SubscriptionsColumnDefs.jsx
Extends plan popover to show a “模型限制” label and a value: parsed model count when enabled, otherwise a localized “不限” fallback.
Frontend — Modal
web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx
Adds model_limits form state and multi-select UI; fetches enabled models from /api/channel/models_enabled, maps them to options with category icons, converts between array and comma-separated string on load/submit, and submits plan.model_limits_enabled + plan.model_limits.
Frontend — Plans Card
web/classic/src/components/topup/SubscriptionPlansCard.jsx
Parses model_limits when enabled, shows a localized “可用模型: N 个模型” benefit line, and attaches a tooltip with the full model list.
Internationalization
web/classic/src/i18n/locales/...
en.json, fr.json, ja.json, ru.json, vi.json, zh-CN.json, zh-TW.json, zh.json
Adds translation keys and strings for model restriction labels, descriptions, and guidance (including “leave empty = no restriction”) across multiple locales.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller as Controller
    participant Model as SubscriptionLogic
    participant DB as Database

    Client->>Controller: PreConsumeUserSubscription(modelName, user)
    Controller->>Model: Find active subscriptions for user
    Model->>DB: SELECT subscriptions/plans for user
    DB-->>Model: subscriptions list

    rect rgba(100, 150, 200, 0.5)
        Model->>Model: For each plan:
        alt ModelLimitsEnabled
            Model->>Model: Parse ModelLimits -> set
            Model->>Model: IsModelAllowed(modelName)?
            alt allowed
                Model->>Model: Check quota & other constraints
            else not allowed
                Model-->>Model: skip plan
            end
        else NotEnabled
            Model->>Model: Check quota & other constraints
        end
    end

    alt a plan matched and quota ok
        Model-->>Controller: selected plan
        Controller-->>Client: 200 OK (plan)
    else no plan allows model
        Model-->>Controller: Error: no subscription allows model
        Controller-->>Client: 4xx Error (model not allowed)
    else matched but quota insufficient
        Model-->>Controller: Error: quota insufficient
        Controller-->>Client: 402 / appropriate error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • seefs001
  • Calcium-Ion

Poem

🐰 I hop through plans with lists in paw,
I count the models every plan can draw,
If one says no, I nudge it aside,
If allowed, I nibble quota with pride,
Hooray — neat limits keep every model in sight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(subscription): 支持订阅套餐模型限制功能' accurately describes the main change: adding model restriction functionality to subscription plans.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
model/subscription.go (1)

1058-1115: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Model-limit error is misclassified when allowed plans exist but quota is insufficient

Current modelNotAllowed flag is set if any plan disallows the model. That makes the function return no subscription allows model ... even when another plan does allow the model but has insufficient remaining quota.

Patch
-    modelNotAllowed := false
+    anyPlanAllowsModel := false
     for _, candidate := range subs {
       sub := candidate
       plan, err := getSubscriptionPlanByIdTx(tx, sub.PlanId)
       if err != nil {
         return err
       }
       // Check model limits: skip subscriptions whose plan doesn't allow the requested model
       if modelName != "" && !plan.IsModelAllowed(modelName) {
-        modelNotAllowed = true
         continue
       }
+      if modelName != "" {
+        anyPlanAllowsModel = true
+      }
       if err := maybeResetUserSubscriptionWithPlanTx(tx, &sub, plan, now); err != nil {
         return err
       }
       usedBefore := sub.AmountUsed
       if sub.AmountTotal > 0 {
         remain := sub.AmountTotal - usedBefore
         if remain < amount {
           continue
         }
       }
       ...
     }
-    if modelNotAllowed {
+    if modelName != "" && !anyPlanAllowsModel {
       return fmt.Errorf("no subscription allows model %s", modelName)
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@model/subscription.go` around lines 1058 - 1115, The code currently sets
modelNotAllowed true if any candidate plan disallows the model, causing a "no
subscription allows model" error even when another plan does allow it but lacks
quota; change this to track whether any plan actually allows the model (e.g.,
introduce foundAllowed bool) and only return fmt.Errorf("no subscription allows
model %s", modelName) when no plans in subs allow the model. Specifically,
update the loop around subs and the check that uses plan.IsModelAllowed to set
foundAllowed = true when a plan permits the model (or treat empty modelName as
allowed), continue to skip disallowed plans for quota checks, and replace the
final if modelNotAllowed check with if !foundAllowed to decide the error.
web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx (1)

200-219: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Model limits sent by UI won’t persist on plan update unless backend map includes these fields

This payload is correct, but the admin update path currently omits model_limits_enabled and model_limits in controller/subscription.go (Line 223-248), so edits can silently fail to persist these values.

Suggested backend fix (controller/subscription.go)
 updateMap := map[string]interface{}{
   "title":                      req.Plan.Title,
   "subtitle":                   req.Plan.Subtitle,
   "price_amount":               req.Plan.PriceAmount,
   "currency":                   req.Plan.Currency,
   "duration_unit":              req.Plan.DurationUnit,
   "duration_value":             req.Plan.DurationValue,
   "custom_seconds":             req.Plan.CustomSeconds,
   "enabled":                    req.Plan.Enabled,
   "sort_order":                 req.Plan.SortOrder,
   "stripe_price_id":            req.Plan.StripePriceId,
   "creem_product_id":           req.Plan.CreemProductId,
   "max_purchase_per_user":      req.Plan.MaxPurchasePerUser,
   "total_amount":               req.Plan.TotalAmount,
   "upgrade_group":              req.Plan.UpgradeGroup,
   "quota_reset_period":         req.Plan.QuotaResetPeriod,
   "quota_reset_custom_seconds": req.Plan.QuotaResetCustomSeconds,
+  "model_limits_enabled":       req.Plan.ModelLimitsEnabled,
+  "model_limits":               req.Plan.ModelLimits,
   "updated_at":                 common.GetTimestamp(),
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx`
around lines 200 - 219, In the subscription update handler in the controller
(the admin subscription update path), read and apply the incoming payload fields
model_limits_enabled and model_limits to the plan object before saving so UI
edits persist: parse model_limits (string/CSV) and model_limits_enabled from the
request body, assign them to the plan's corresponding fields (e.g.,
plan.ModelLimitsEnabled and plan.ModelLimits or whatever struct fields you use),
and include those fields in the update/save operation so they are written to the
DB; ensure types match the model (convert CSV to the stored format or
vice‑versa) and that the save/update method persists these new fields.
🧹 Nitpick comments (1)
web/classic/src/components/topup/SubscriptionPlansCard.jsx (1)

513-538: ⚡ Quick win

Normalize the model-limit list before counting and rendering.

split(',') is repeated here, and the entries are not trimmed. A single parsed list would keep the label and tooltip consistent if the stored string contains spaces or stray separators.

♻️ Proposed fix
-                const modelLimitsLabel =
-                  plan?.model_limits_enabled && plan?.model_limits
-                    ? `${t('可用模型')}: ${plan.model_limits.split(',').filter(Boolean).length} ${t('个模型')}`
-                    : null;
+                const modelLimitNames = (plan?.model_limits || '')
+                  .split(',')
+                  .map((model) => model.trim())
+                  .filter(Boolean);
+                const modelLimitsLabel =
+                  plan?.model_limits_enabled && modelLimitNames.length > 0
+                    ? `${t('可用模型')}: ${modelLimitNames.length} ${t('个模型')}`
+                    : null;
@@
-                        tooltip: plan.model_limits
-                          .split(',')
-                          .filter(Boolean)
-                          .join(', '),
+                        tooltip: modelLimitNames.join(', '),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/classic/src/components/topup/SubscriptionPlansCard.jsx` around lines 513
- 538, In SubscriptionPlansCard.jsx, normalize plan.model_limits into a single
parsed array (trim each entry and filter out empty strings) once (e.g., const
parsedModelLimits = plan?.model_limits?.split(',').map(s =>
s.trim()).filter(Boolean) || []) and then use parsedModelLimits for computing
modelLimitsLabel (parsedModelLimits.length) and for the tooltip
(parsedModelLimits.join(', ')) instead of calling plan.model_limits.split(',')
in multiple places; update references to modelLimitsLabel and the tooltip
construction to use this parsedModelLimits to keep counting and rendering
consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx`:
- Around line 116-118: During the edit initialization in
AddEditSubscriptionModal (where p.model_limits is parsed into modelLimits), the
CSV split keeps whitespace and breaks multi-select matching; after splitting
p.model_limits with p.model_limits.split(',') you should map over the results
and trim each entry and filter out empty strings (e.g., .split(',').map(s =>
s.trim()).filter(Boolean)) so modelLimits contains clean tokens for the
multi-select.

In `@web/classic/src/components/table/subscriptions/SubscriptionsColumnDefs.jsx`:
- Around line 104-108: The model count calculation using
plan.model_limits.split(',').filter(Boolean) can over-count malformed entries;
in the component (SubscriptionsColumnDefs.jsx) normalize plan.model_limits by
splitting on ',', mapping each item to item.trim(), filtering out empty strings,
and deduplicating (e.g., with a Set) before taking .length; replace the existing
expression that computes `${plan.model_limits.split(',').filter(Boolean).length}
${t('个模型')}` with this normalized-and-unique count so whitespace-padded or
duplicate models are not double-counted.

In `@web/classic/src/i18n/locales/fr.json`:
- Line 3373: The French translation value for the key
"选择后,通过该订阅套餐计费的请求只能使用选中的模型;留空则不限制" is awkward; update the string value to a
clearer phrasing such as "Une fois sélectionnés, les modèles facturés via ce
forfait d’abonnement ne peuvent être que ceux sélectionnés ; laissez vide pour
ne pas imposer de restriction" by replacing the current value in fr.json for
that exact key so the UI reads naturally.

In `@web/classic/src/i18n/locales/vi.json`:
- Line 3830: Replace the ambiguous leading phrase "Khi được đặt" with the
clearer temporal phrase "Sau khi chọn" in the Vietnamese translation for the
JSON key "选择后,通过该订阅套餐计费的请求只能使用选中的模型;留空则不限制" so the value begins "Sau khi chọn,
các yêu cầu..." ensuring the rest of the translated sentence remains unchanged.

---

Outside diff comments:
In `@model/subscription.go`:
- Around line 1058-1115: The code currently sets modelNotAllowed true if any
candidate plan disallows the model, causing a "no subscription allows model"
error even when another plan does allow it but lacks quota; change this to track
whether any plan actually allows the model (e.g., introduce foundAllowed bool)
and only return fmt.Errorf("no subscription allows model %s", modelName) when no
plans in subs allow the model. Specifically, update the loop around subs and the
check that uses plan.IsModelAllowed to set foundAllowed = true when a plan
permits the model (or treat empty modelName as allowed), continue to skip
disallowed plans for quota checks, and replace the final if modelNotAllowed
check with if !foundAllowed to decide the error.

In
`@web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx`:
- Around line 200-219: In the subscription update handler in the controller (the
admin subscription update path), read and apply the incoming payload fields
model_limits_enabled and model_limits to the plan object before saving so UI
edits persist: parse model_limits (string/CSV) and model_limits_enabled from the
request body, assign them to the plan's corresponding fields (e.g.,
plan.ModelLimitsEnabled and plan.ModelLimits or whatever struct fields you use),
and include those fields in the update/save operation so they are written to the
DB; ensure types match the model (convert CSV to the stored format or
vice‑versa) and that the save/update method persists these new fields.

---

Nitpick comments:
In `@web/classic/src/components/topup/SubscriptionPlansCard.jsx`:
- Around line 513-538: In SubscriptionPlansCard.jsx, normalize plan.model_limits
into a single parsed array (trim each entry and filter out empty strings) once
(e.g., const parsedModelLimits = plan?.model_limits?.split(',').map(s =>
s.trim()).filter(Boolean) || []) and then use parsedModelLimits for computing
modelLimitsLabel (parsedModelLimits.length) and for the tooltip
(parsedModelLimits.join(', ')) instead of calling plan.model_limits.split(',')
in multiple places; update references to modelLimitsLabel and the tooltip
construction to use this parsedModelLimits to keep counting and rendering
consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 46f8d73d-9fd2-4e70-bea4-d410e13e72f8

📥 Commits

Reviewing files that changed from the base of the PR and between dac55f0 and fbb3076.

📒 Files selected for processing (14)
  • controller/subscription.go
  • model/main.go
  • model/subscription.go
  • web/classic/src/components/table/subscriptions/SubscriptionsColumnDefs.jsx
  • web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx
  • web/classic/src/components/topup/SubscriptionPlansCard.jsx
  • web/classic/src/i18n/locales/en.json
  • web/classic/src/i18n/locales/fr.json
  • web/classic/src/i18n/locales/ja.json
  • web/classic/src/i18n/locales/ru.json
  • web/classic/src/i18n/locales/vi.json
  • web/classic/src/i18n/locales/zh-CN.json
  • web/classic/src/i18n/locales/zh-TW.json
  • web/classic/src/i18n/locales/zh.json

Comment thread web/classic/src/i18n/locales/fr.json Outdated
Comment thread web/classic/src/i18n/locales/vi.json Outdated
- 在编辑订阅套餐初始化时增加 trim() 处理,防止 CSV 中的空格导致多选框匹配失效
- 在套餐列表显示时对模型列表进行去重和格式化,确保模型总数统计准确
- 改进法语 (fr) 和越南语 (vi) 关于模型限制描述的词句,提升语意清晰度
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx (1)

180-194: 💤 Low value

Consider adding loadModels or t to the dependency array.

The loadModels function uses t from props, but neither is listed in the useEffect dependencies. This could trigger ESLint exhaustive-deps warnings. Since t is typically stable from the i18n context, the functional impact is minimal, but adding it would ensure correctness if the language changes while the modal is open.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx`
around lines 180 - 194, The useEffect that runs when the modal becomes visible
references loadModels and the translation function t but only lists visible in
its dependency array; to satisfy exhaustive-deps and ensure correctness, include
loadModels and t in the dependency array of the useEffect where visible is used
(i.e., the effect that calls API.get and loadModels), or if loadModels is stable
via useCallback/memoization ensure it is declared as such before useEffect;
update the dependency list to [visible, loadModels, t] (or memoize loadModels)
so ESLint warnings are resolved and the effect responds to changes in those
values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx`:
- Around line 180-194: The useEffect that runs when the modal becomes visible
references loadModels and the translation function t but only lists visible in
its dependency array; to satisfy exhaustive-deps and ensure correctness, include
loadModels and t in the dependency array of the useEffect where visible is used
(i.e., the effect that calls API.get and loadModels), or if loadModels is stable
via useCallback/memoization ensure it is declared as such before useEffect;
update the dependency list to [visible, loadModels, t] (or memoize loadModels)
so ESLint warnings are resolved and the effect responds to changes in those
values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1a55af13-72bf-4f40-88d0-665328e99c1d

📥 Commits

Reviewing files that changed from the base of the PR and between fbb3076 and 67dd89b.

📒 Files selected for processing (4)
  • web/classic/src/components/table/subscriptions/SubscriptionsColumnDefs.jsx
  • web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx
  • web/classic/src/i18n/locales/fr.json
  • web/classic/src/i18n/locales/vi.json
✅ Files skipped from review due to trivial changes (2)
  • web/classic/src/i18n/locales/vi.json
  • web/classic/src/i18n/locales/fr.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/classic/src/components/table/subscriptions/SubscriptionsColumnDefs.jsx

wans10 added 2 commits May 1, 2026 00:51
- 使用 useCallback 缓存 loadModels 函数,确保其在组件渲染间的稳定性
- 补全 useEffect 的依赖项(loadModels, t),修复 exhaustive-deps 警告并确保逻辑正确性
- 修复 model/subscription.go 中模型限制错误分类逻辑:只有当没有任何订阅允许该模型时才返回模型限制错误,防止在多订阅场景下因单个订阅不匹配导致误报。
- 优化 SubscriptionPlansCard.jsx 中的模型列表处理:对 model_limits 进行归一化处理(修剪空格并过滤空项),确保数量统计和悬浮提示信息的一致性。
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx`:
- Around line 116-121: 当前初始化会在存在残留字符串时无条件解析 p.model_limits 导致在
model_limits_enabled 为 false 时编辑保存会误启用限制;在 AddEditSubscriptionModal.jsx 中将对
modelLimits 的赋值改为在 p.model_limits_enabled 为真时才解析并赋值(即依赖 p.model_limits_enabled 来
gate 初始化 modelLimits),并在文件中另一个相同处理位置(先前提到的第 142 行处)做相同修改以保持一致性;请查找使用
p.model_limits 和 p.model_limits_enabled 的初始化逻辑并仅在 p.model_limits_enabled ===
true 时执行 .split().map(...).filter(Boolean) 赋值。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9d0b725e-2955-4b56-b8b8-a385a704f85e

📥 Commits

Reviewing files that changed from the base of the PR and between 67dd89b and 837c878.

📒 Files selected for processing (3)
  • model/subscription.go
  • web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx
  • web/classic/src/components/topup/SubscriptionPlansCard.jsx
✅ Files skipped from review due to trivial changes (1)
  • model/subscription.go

- 后端逻辑:修复 model/subscription.go 中的模型选择错误分类,确保在多订阅场景下正确区分模型限制与额度不足。
- 数据初始化:在 AddEditSubscriptionModal 中对模型限制初始化增加“启用状态”门控,并进行 trim 处理,防止残留空格干扰匹配。
- 界面展示:归一化 SubscriptionsColumnDefs 和 SubscriptionPlansCard 中的模型解析逻辑,确保模型计数和悬浮提示的一致性。
- React 优化:补全 useEffect 依赖项并使用 useCallback 缓存数据加载函数,消除 Lint 警告并提升组件稳定性。
- 国际化:改进法语 (fr) 和越南语 (vi) 的翻译措辞,使其更加自然且语意明确。
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx`:
- Around line 146-153: loadModels 中调用的 API.get('/api/user/models')
仅按当前登录用户可见模型返回,会在多分组/管理员场景导致漏模型并意外收窄套餐;请将该调用改为使用后台的全量/管理员模型接口(例如改为
API.get('/api/admin/models') 或其他后端提供的全量模型端点),或者在请求中支持传入目标分组(如
groupId)以按目标分组拉取模型;同时在 loadModels 中保留错误和空结果的兜底处理以避免 UI 崩溃。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 91467559-262a-4ff9-b043-5ffb0a9541bd

📥 Commits

Reviewing files that changed from the base of the PR and between 837c878 and 823492f.

📒 Files selected for processing (2)
  • web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx
  • web/classic/src/components/topup/SubscriptionPlansCard.jsx

- 将订阅编辑弹窗中的模型加载接口从 /api/user/models 切换为 /api/channel/models_enabled,确保管理员在配置套餐时可见系统中所有已启用的模型。
- 在 loadModels 函数中增加对返回数据的 Array.isArray 校验,并完善 catch 块的兜底处理,提升弹窗在异常情况下的稳定性。
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx`:
- Around line 171-176: The code currently swallows model-load errors by calling
setModels([]), which makes an accidental API failure serialize as
model_limits_enabled: false; instead, add explicit load-state and error-state
(e.g., modelsLoading and modelsLoadFailed) in the AddEditSubscriptionModal logic
and update the load routine (the block using setModels in the try/catch) to call
setModelsLoadFailed(true) on catch rather than setModels([]). Update the UI to
show an error message and disable the model selector and submission path (the
submit handler that serializes model_limits_enabled) when modelsLoadFailed is
true so a transient fetch failure cannot be saved as “no model limits.” Ensure
existing code paths that read models differentiate between an actual empty
models array and a load failure by checking modelsLoadFailed before treating
models as empty.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4814d546-ecc3-4bf7-9ebd-f19d516a6ed8

📥 Commits

Reviewing files that changed from the base of the PR and between 823492f and 79d5e43.

📒 Files selected for processing (1)
  • web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx

- 引入显式的模型加载中 (loading) 与加载失败 (error) 状态管理,防止因接口偶发故障导致模型限制被误清空。
- 增加模型加载失败时的重试机制,并优化错误提示图标为 AlertCircle,提升语意清晰度。
- 当模型加载失败时自动禁用提交按钮与模型选择器,确保套餐配置的数据完整性。
- 清理 AddEditSubscriptionModal.jsx 中的冗余语法及括号,优化代码结构。
@zailushang2008
Copy link
Copy Markdown

这么多提交这个的,没有一个合并呀

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.

2 participants