Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds shared auto-route chain utilities, updates pricing UI rendering and prop wiring, preserves missing ChangesAuto Route Chain Utility and UI Wiring
Normalized Email MySQL Locking
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant Pricing
participant PricingSidebar
participant AutoRouteView
participant GroupBadge
Pricing->>PricingSidebar: pass autoGroups and autoRoutes
PricingSidebar->>AutoRouteView: getConfiguredAutoRouteChains(...)
AutoRouteView-->>PricingSidebar: configured route chains
PricingSidebar->>GroupBadge: render route and group badges
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (1 warning, 2 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/features/pricing/components/pricing-sidebar.tsx`:
- Around line 168-224: AutoRouteGroupIntro is rendering auto route chains
without applying the same group filter used elsewhere, so excluded/internal
groups can still show up in the pricing sidebar. Update the route-chain
derivation in AutoRouteGroupIntro to pass the same groupFilter logic used in
model-details.tsx (or equivalent shared filter) before mapping and rendering
GroupBadge entries, so the alert matches the visible group list.
In `@web/default/src/features/pricing/lib/auto-route-view.ts`:
- Around line 26-29: `normalizeDisplayGroups` and the exported
`getAutoRouteLabelOverride` are relying on inferred return types, which violates
the explicit typing guideline. Add explicit return type annotations to both
function signatures in the auto-route view utility, using the existing function
names to locate them, and keep the implementations unchanged while making the
returned value types clear in the declaration.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: 3c7766eb-c9c1-40f6-877c-9ff5aceb8aab
📒 Files selected for processing (11)
web/default/src/features/pricing/components/model-details.tsxweb/default/src/features/pricing/components/pricing-sidebar.tsxweb/default/src/features/pricing/components/pricing-toolbar.tsxweb/default/src/features/pricing/index.tsxweb/default/src/features/pricing/lib/auto-route-view.tsweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.json
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Backend checks
- GitHub Check: pr-quality
🧰 Additional context used
📓 Path-based instructions (3)
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/features/pricing/index.tsxweb/default/src/features/pricing/lib/auto-route-view.tsweb/default/src/features/pricing/components/pricing-toolbar.tsxweb/default/src/features/pricing/components/pricing-sidebar.tsxweb/default/src/features/pricing/components/model-details.tsx
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/pricing/index.tsxweb/default/src/features/pricing/lib/auto-route-view.tsweb/default/src/features/pricing/components/pricing-toolbar.tsxweb/default/src/features/pricing/components/pricing-sidebar.tsxweb/default/src/features/pricing/components/model-details.tsx
web/default/src/features/**/lib/**/*.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
表单应使用 React Hook Form + Zod:在功能模块的
lib/下定义 schema,并用z.infer导出表单类型;useForm应配合@hookform/resolvers/zod进行校验。
Files:
web/default/src/features/pricing/lib/auto-route-view.ts
🔇 Additional comments (14)
web/default/src/i18n/locales/fr.json (1)
560-560: LGTM!Also applies to: 670-670, 1024-1024
web/default/src/i18n/locales/ja.json (1)
560-560: LGTM!Also applies to: 670-670, 1024-1024
web/default/src/i18n/locales/ru.json (1)
560-560: LGTM!Also applies to: 670-670, 1024-1024
web/default/src/i18n/locales/vi.json (1)
560-560: LGTM!Also applies to: 670-670, 1024-1024
web/default/src/i18n/locales/zh.json (1)
560-560: LGTM!Also applies to: 670-670, 1024-1024
web/default/src/i18n/locales/en.json (1)
560-560: LGTM!Also applies to: 670-670, 1024-1024
web/default/src/features/pricing/lib/auto-route-view.ts (1)
67-90: LGTM!web/default/src/features/pricing/components/model-details.tsx (1)
24-24: LGTM!Also applies to: 57-60, 755-780
web/default/src/features/pricing/components/pricing-sidebar.tsx (4)
20-44: LGTM!
78-79: LGTM!
348-353: LGTM!
61-61: 📐 Maintainability & Code Quality
ReactNodeis already imported withimport type.> Likely an incorrect or invalid review comment.web/default/src/features/pricing/components/pricing-toolbar.tsx (1)
22-22: LGTM!Also applies to: 89-90, 303-304
web/default/src/features/pricing/index.tsx (1)
221-222: LGTM!Also applies to: 255-256
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/default/src/features/pricing/lib/auto-route-view.ts (1)
74-80: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winNested ternary violates coding guideline.
The
routesassignment nests a second ternary inside theelsebranch of the first, which is disallowed by the project's style rule against two-or-more-level nested ternaries. Convert toif-elseor early return for clarity.♻️ Proposed fix
- const routes = - options.autoRoutes !== undefined - ? options.autoRoutes - : fallbackRoute - ? [fallbackRoute] - : [] + let routes: AutoGroupRoute[] + if (options.autoRoutes !== undefined) { + routes = options.autoRoutes + } else if (fallbackRoute) { + routes = [fallbackRoute] + } else { + routes = [] + }As per coding guidelines: "禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用
if-else、提前返回或抽取函数。"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/default/src/features/pricing/lib/auto-route-view.ts` around lines 74 - 80, The routes selection in autoRouteView uses a nested ternary, which violates the project style rule against multi-level ternaries. Refactor the logic around getFallbackAutoRoute and the routes assignment to use if-else branches or an early return instead, keeping the behavior the same while making the control flow explicit.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@web/default/src/features/pricing/lib/auto-route-view.ts`:
- Around line 74-80: The routes selection in autoRouteView uses a nested
ternary, which violates the project style rule against multi-level ternaries.
Refactor the logic around getFallbackAutoRoute and the routes assignment to use
if-else branches or an early return instead, keeping the behavior the same while
making the control flow explicit.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 3ef241ff-3f2f-4330-9556-38dadcdb499c
📒 Files selected for processing (5)
web/default/src/features/pricing/components/model-details.tsxweb/default/src/features/pricing/components/pricing-sidebar.tsxweb/default/src/features/pricing/hooks/use-pricing-data.tsweb/default/src/features/pricing/index.tsxweb/default/src/features/pricing/lib/auto-route-view.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/features/pricing/hooks/use-pricing-data.tsweb/default/src/features/pricing/index.tsxweb/default/src/features/pricing/lib/auto-route-view.tsweb/default/src/features/pricing/components/pricing-sidebar.tsxweb/default/src/features/pricing/components/model-details.tsx
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/pricing/hooks/use-pricing-data.tsweb/default/src/features/pricing/index.tsxweb/default/src/features/pricing/lib/auto-route-view.tsweb/default/src/features/pricing/components/pricing-sidebar.tsxweb/default/src/features/pricing/components/model-details.tsx
web/default/src/features/**/lib/**/*.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
表单应使用 React Hook Form + Zod:在功能模块的
lib/下定义 schema,并用z.infer导出表单类型;useForm应配合@hookform/resolvers/zod进行校验。
Files:
web/default/src/features/pricing/lib/auto-route-view.ts
🔇 Additional comments (5)
web/default/src/features/pricing/lib/auto-route-view.ts (1)
26-29: LGTM!Also applies to: 56-67, 69-92
web/default/src/features/pricing/components/model-details.tsx (1)
758-758: LGTM!Also applies to: 1412-1412
web/default/src/features/pricing/components/pricing-sidebar.tsx (1)
61-61: LGTM!Also applies to: 78-79, 168-226, 351-357
web/default/src/features/pricing/hooks/use-pricing-data.ts (1)
70-70: LGTM!web/default/src/features/pricing/index.tsx (1)
218-222: LGTM!Also applies to: 252-256, 283-284
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@model/user.go`:
- Around line 396-398: Update releaseMySQLNamedLock to capture the value
returned by scanNullableInt64 and return an error when it is nil or not equal to
1; only return nil when RELEASE_LOCK returns 1, while preserving any scan error.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: 097ad689-21fa-4bf5-b948-0a54e48200ac
📒 Files selected for processing (2)
model/user.gomodel/user_update_test.go
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: CodeRabbit / Review
- GitHub Check: CodeRabbit / Review
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) and must not directly callencoding/jsonfor actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid directAUTO_INCREMENT/SERIAL, usecommonGroupCol/commonKeyColandcommonTrueVal/commonFalseValfor DB-specific SQL, branch withcommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supportsStreamOptions; if it does, add that channel tostreamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types withomitemptyso explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, readpkg/billingexpr/expr.mdfirst and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.
**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) instead of directly importing or callingencoding/jsonfor actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with thecommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQLflags when need...
Files:
model/user_update_test.gomodel/user.go
🔇 Additional comments (2)
model/user.go (1)
314-318: LGTM!Also applies to: 327-327, 356-360, 371-371, 381-394
model/user_update_test.go (1)
15-15: LGTM!Also applies to: 84-102
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@model/user.go`:
- Around line 396-405: Update the MySQL transaction/callback paths around the
callers of releaseMySQLNamedLock so a successful callback or committed
transaction remains the primary result. Do not return releaseErr when the write
succeeds; only return the callback/transaction error, while handling or logging
lock-release failures separately. Preserve releaseMySQLNamedLock’s existing
behavior and ensure callers such as OAuth and top-up still receive committed
writes as success.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: a16f84f5-9fea-4b39-b033-d5cb343d0412
📒 Files selected for processing (2)
model/user.gomodel/user_update_test.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) and must not directly callencoding/jsonfor actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid directAUTO_INCREMENT/SERIAL, usecommonGroupCol/commonKeyColandcommonTrueVal/commonFalseValfor DB-specific SQL, branch withcommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supportsStreamOptions; if it does, add that channel tostreamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types withomitemptyso explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, readpkg/billingexpr/expr.mdfirst and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.
**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) instead of directly importing or callingencoding/jsonfor actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with thecommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQLflags when need...
Files:
model/user_update_test.gomodel/user.go
🔇 Additional comments (2)
model/user.go (1)
388-409: LGTM!model/user_update_test.go (1)
85-108: LGTM!
| func releaseMySQLNamedLock(tx *gorm.DB, lockName string) error { | ||
| var released sql.NullInt64 | ||
| return tx.Raw("SELECT RELEASE_LOCK(?)", lockName).Scan(&released).Error | ||
| released, err := scanNullableInt64(tx.Raw("SELECT RELEASE_LOCK(?)", lockName).Row()) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if !isMySQLNamedLockSuccess(released) { | ||
| return errors.New("failed to release user email lock") | ||
| } | ||
| return nil | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect release/error-resolution flow around the two write paths
ast-grep outline model/user.go --match 'withNormalizedEmailLock|WithNormalizedEmailWriteTx' --view expanded
rg -n -C3 'releaseMySQLNamedLock' model/user.goRepository: MAX-API-Next/MAX-API
Length of output: 1214
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '301,382p' model/user.go | cat -n
printf '\n--- controller/oauth.go ---\n'
rg -n -C3 'WithNormalizedEmailWriteTx|withNormalizedEmailLock|releaseMySQLNamedLock' controller/oauth.go model/topup.goRepository: MAX-API-Next/MAX-API
Length of output: 4287
Don't let RELEASE_LOCK override a successful write. In model/user.go:321-331 and model/user.go:371-377, the MySQL paths return releaseErr after the callback/transaction succeeds, so a committed change can still surface as a failure to callers like controller/oauth.go and model/topup.go. Keep the callback result as the primary error and handle lock-release failures separately.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@model/user.go` around lines 396 - 405, Update the MySQL transaction/callback
paths around the callers of releaseMySQLNamedLock so a successful callback or
committed transaction remains the primary result. Do not return releaseErr when
the write succeeds; only return the callback/transaction error, while handling
or logging lock-release failures separately. Preserve releaseMySQLNamedLock’s
existing behavior and ensure callers such as OAuth and top-up still receive
committed writes as success.
Important
📝 变更描述 / Description
(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
(请在此粘贴截图、关键日志或测试报告,以证明变更生效)