-
Notifications
You must be signed in to change notification settings - Fork 8.3k
feat: add profile setting #6897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
WalkthroughThis PR introduces a comprehensive user profile feature across all web applications and the common-ui library. It adds profile page routing, menu navigation items, localized labels, and tabbed settings interfaces for user information, security, password management, and notifications. A new reusable profile UI module is published from the common-ui package. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Menu as Profile Menu
participant Router
participant Page as Profile Page
participant Store as User Store
participant API as User API
participant TabComponent as Tab Component
User->>Menu: Click Profile
Menu->>Router: push({ name: 'Profile' })
Router->>Page: Navigate to /profile
Page->>Store: Get user info
Store-->>Page: User data
Page->>API: getUserInfoApi() [base-setting]
API-->>Page: User profile data
Page->>TabComponent: Set initial tab (basic)
TabComponent-->>Page: Render BaseSetting
User->>TabComponent: Click security/password/notice tab
TabComponent-->>Page: Update active tab
Page->>TabComponent: Render corresponding sub-component
TabComponent-->>User: Display new settings form
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 27
♻️ Duplicate comments (4)
apps/web-naive/src/views/_core/profile/password-setting.vue (1)
1-66: Duplicate implementation.This file duplicates the same implementation and issues already flagged in
apps/web-antd/src/views/_core/profile/password-setting.vueandapps/web-tdesign/src/views/_core/profile/password-setting.vue:
- Unused ref at line 10
- Missing API implementation at lines 55-57
- Hard-coded Chinese strings throughout
Please refer to the review comments on the web-antd variant for detailed recommendations.
apps/web-ele/src/layouts/basic.vue (1)
66-72: Same duplication as noted in web-tdesign layout.This Profile menu implementation is identical to the one in apps/web-tdesign/src/layouts/basic.vue and other layout files. Refer to the earlier comment about extracting to shared configuration.
apps/web-antd/src/layouts/basic.vue (1)
66-72: Duplicate implementation.Same Profile menu duplication issue noted in the web-tdesign layout review.
playground/src/layouts/basic.vue (1)
79-85: Duplicate implementation.Same Profile menu duplication issue noted in earlier layout file reviews.
🧹 Nitpick comments (29)
apps/web-antd/src/views/_core/profile/password-setting.vue (2)
10-10: Unused ref declaration.The
profilePasswordSettingRefis declared but never used in the component.If you intend to expose form API methods for external access or programmatic control, wire this ref to the component. Otherwise, remove it to reduce clutter:
-const profilePasswordSettingRef = ref();
16-56: Hard-coded Chinese strings prevent internationalization.All labels, placeholders, and messages are hard-coded in Chinese, preventing proper i18n support.
Refactor to use the project's i18n system. Check if locale keys already exist under
page.auth.profileor similar namespaces, and use$t()or the appropriate i18n helper:label: $t('profile.password.oldPassword'), placeholder: $t('profile.password.oldPasswordPlaceholder'),apps/web-tdesign/src/views/_core/profile/password-setting.vue (1)
1-66: Near-duplicate implementation across UI frameworks.This file is nearly identical to
apps/web-antd/src/views/_core/profile/password-setting.vue(andapps/web-naive/src/views/_core/profile/password-setting.vue), differing only in the message adapter import. The same issues apply:
- Unused
profilePasswordSettingRefat line 10- Missing API implementation in
handleSubmit(lines 55-57)- Hard-coded Chinese strings throughout (lines 16-56)
Consider extracting the shared form schema logic into a composable or shared module to reduce duplication:
// shared/composables/usePasswordSettingSchema.ts export function usePasswordSettingSchema() { return computed((): VbenFormSchema[] => [ // shared schema definition ]); }Then import and use it in each framework-specific file, keeping only the framework-specific message adapter.
apps/web-naive/src/views/_core/profile/base-setting.vue (1)
29-56: Hard-coded Chinese strings prevent internationalization.All field labels are hard-coded in Chinese (lines 34, 39, 48, 53), preventing proper i18n support.
Use the project's i18n system for labels to support multiple locales. Given that locale files in the PR add
page.auth.profile, consider adding sub-keys for form fields.packages/effects/common-ui/src/ui/profile/base-setting.vue (1)
37-43: No user feedback on validation failure.When form validation fails, the function silently returns without providing any feedback to the user about which fields are invalid or why submission failed.
Consider emitting a validation error event or ensuring the form component itself displays validation errors:
async function handleSubmit() { const { valid } = await formApi.validate(); - const values = await formApi.getValues(); if (valid) { + const values = await formApi.getValues(); emit('submit', values); + } else { + // Form validation errors should be displayed by the form component + // Optionally emit a validation-failed event if needed } }packages/effects/common-ui/src/ui/profile/profile.vue (2)
20-23: Misleading default title for profile component.The default title "关于项目" (About Project) doesn't match the profile context of this component.
Update the default to something more appropriate:
withDefaults(defineProps<Props>(), { - title: '关于项目', + title: '个人中心', // or 'Profile' for English tabs: () => [], });
25-25: Consider initializing model with default value.The
tabsValuemodel is not initialized, which could cause issues if no initial value is provided by the parent.Initialize with the first tab's value as default:
-const tabsValue = defineModel<string>('modelValue'); +const props = withDefaults(defineProps<Props>(), { + title: '关于项目', + tabs: () => [], +}); + +const tabsValue = defineModel<string>('modelValue', { + default: () => props.tabs[0]?.value ?? '', +});Note: This requires accessing props, so you'll need to capture the props object from
withDefaults.apps/web-tdesign/src/layouts/basic.vue (1)
66-72: Consider extracting the Profile menu configuration to reduce duplication.This exact Profile menu item implementation is duplicated across all layout files (web-tdesign, web-ele, web-antd, playground). Consider extracting the menu configuration to a shared constant or composable to maintain consistency and reduce maintenance burden.
playground/src/views/_core/profile/base-setting.vue (1)
14-56: Consider localizing the hardcoded Chinese strings.The form labels and role options use hardcoded Chinese strings. While this may be intentional for the playground, consider using i18n keys for consistency with the rest of the application and to support multiple locales.
apps/web-antd/src/views/_core/profile/security-setting.vue (1)
6-39: Consider consolidating duplicated security setting schemas.This formSchema definition is nearly identical to the one in
playground/src/views/_core/profile/security-setting.vueand likely appears in other app variants as well. The duplication creates maintenance overhead.Consider:
- Extracting the schema to a shared configuration file or composable
- Using i18n keys instead of hardcoded text (as noted in the playground file review)
- Fetching user-specific security data from the backend
Example shared composable pattern:
// shared/composables/useSecuritySchema.ts export function useSecuritySchema(userData) { return computed(() => [ { value: userData.value.hasPassword, fieldName: 'accountPassword', label: $t('profile.security.accountPassword.label'), description: computed(() => $t('profile.security.accountPassword.description', { strength: userData.value.passwordStrength }) ), }, // ... rest of schema ]); }packages/effects/common-ui/src/ui/profile/security-setting.vue (1)
20-26: Consider stronger typing for the change event.The emit type uses
Recordable<any>which weakens type safety. Since the emitted object always hasfieldName: stringandvalue: boolean, consider defining a specific type.Apply this pattern:
+interface SecuritySettingChangeEvent { + fieldName: string; + value: boolean; +} + const emit = defineEmits<{ - change: [Recordable<any>]; + change: [SecuritySettingChangeEvent]; }>();apps/web-ele/src/views/_core/profile/notification-setting.vue (1)
6-27: Replace computed with const for static data.The
formSchemais wrapped incomputed()but returns static data that never changes. This adds unnecessary reactivity overhead.Apply this diff:
-const formSchema = computed(() => { - return [ +const formSchema = [ { value: true, fieldName: 'accountPassword', label: '账户密码', description: '其他用户的消息将以站内信的形式通知', }, { value: true, fieldName: 'systemMessage', label: '系统消息', description: '系统消息将以站内信的形式通知', }, { value: true, fieldName: 'todoTask', label: '待办任务', description: '待办任务将以站内信的形式通知', }, - ]; -}); +];apps/web-antd/src/views/_core/profile/index.vue (1)
42-46: Consider dynamic component for better performance.Multiple
v-ifconditions cause all components to be loaded upfront. Consider using a dynamic component with:isorv-showfor better performance, especially if these components are heavy.Example with dynamic component:
<template> <Profile v-model:model-value="tabsValue" title="个人中心" :user-info="userStore.userInfo" :tabs="tabs" > <template #content> <component :is="currentComponent" /> </template> </Profile> </template> <script setup lang="ts"> // ... existing imports and code ... const componentMap = { basic: ProfileBase, security: ProfileSecuritySetting, password: ProfilePasswordSetting, notice: ProfileNotificationSetting, }; const currentComponent = computed(() => componentMap[tabsValue.value]); </script>apps/web-tdesign/src/views/_core/profile/security-setting.vue (1)
6-39: Replace computed with const for static data.The
formSchemais wrapped incomputed()but returns static data. This adds unnecessary reactivity overhead.playground/src/views/_core/profile/password-setting.vue (2)
22-30: Add password complexity validation.The new password field lacks validation for password complexity requirements (e.g., minimum length, character requirements). Consider adding validation rules to ensure password security.
62-62: Avoid hardcoded width class.The
class="w-1/3"may not be responsive on smaller screens. Consider using responsive Tailwind classes likeclass="w-full md:w-1/2 lg:w-1/3"for better mobile experience.apps/web-naive/src/views/_core/profile/security-setting.vue (1)
1-43: Consider reducing code duplication across app variants.This file is nearly identical to
apps/web-tdesign/src/views/_core/profile/security-setting.vueandapps/web-ele/src/views/_core/profile/security-setting.vue. Consider extracting the shared form schema logic into a composable or shared utility to maintain consistency and reduce duplication.apps/web-ele/src/views/_core/profile/security-setting.vue (1)
1-43: Significant code duplication across app variants.This file duplicates the same logic found in
apps/web-tdesign/src/views/_core/profile/security-setting.vue,apps/web-naive/src/views/_core/profile/security-setting.vue, and similar files in other app variants. Consider creating a shared composable (e.g.,useSecuritySettings()) that returns the form schema, which can be reused across all variants.Example composable:
// shared/composables/useSecuritySettings.ts export function useSecuritySettings() { return [ { value: true, fieldName: 'accountPassword', label: $t('profile.security.accountPassword.label'), description: $t('profile.security.accountPassword.description'), }, // ... other fields ]; }apps/web-ele/src/views/_core/profile/password-setting.vue (1)
10-10: Remove unused ref.The
profilePasswordSettingRefis declared but never used.-const profilePasswordSettingRef = ref();apps/web-antd/src/views/_core/profile/notification-setting.vue (1)
6-27: Consider making formSchema a const instead of computed.The
formSchemais wrapped incomputed()but returns static data that never changes. This adds unnecessary reactivity overhead.-const formSchema = computed(() => { - return [ +const formSchema = [ { value: true, fieldName: 'accountPassword', label: '账户密码', description: '其他用户的消息将以站内信的形式通知', }, // ... rest of items - ]; -}); +];playground/src/views/_core/profile/notification-setting.vue (1)
1-31: Significant code duplication detected across multiple apps.This file is nearly identical to:
apps/web-antd/src/views/_core/profile/notification-setting.vueapps/web-tdesign/src/views/_core/profile/notification-setting.vueThe same logic, structure, and hardcoded text are repeated across at least 3 different app variants. Consider:
- Moving shared form schema configuration to a common utility/constant
- Extracting text to shared i18n resources
- Potentially creating a shared configuration file that each app can import
This pattern appears throughout the profile feature (notification-setting, index.vue files are duplicated across apps). Consolidating common logic would significantly improve maintainability.
apps/web-tdesign/src/views/_core/profile/notification-setting.vue (1)
6-27: Replace computed with const for static data.Same as other notification-setting files -
formSchemadoesn't need reactivity since it returns static data.apps/web-tdesign/src/views/_core/profile/base-setting.vue (2)
14-27: Consider fetching roles from an API if they're dynamic.The
MOCK_prefix suggests this is temporary data. If user roles can vary or be configured, consider fetching them from an API endpoint instead of hardcoding.
29-56: Replace hardcoded Chinese labels with i18n keys.The form schema uses hardcoded Chinese strings for labels ('姓名', '用户名', '角色', '个人简介'). Since this PR includes localization additions in other files, these should use i18n for consistency.
Example refactor:
+import { useI18n } from 'vue-i18n'; + +const { t } = useI18n(); + const formSchema = computed((): VbenFormSchema[] => { return [ { fieldName: 'realName', component: 'Input', - label: '姓名', + label: t('profile.form.realName'), }, { fieldName: 'username', component: 'Input', - label: '用户名', + label: t('profile.form.username'), }, { fieldName: 'roles', component: 'Select', componentProps: { mode: 'tags', options: MOCK_ROLES_OPTIONS, }, - label: '角色', + label: t('profile.form.roles'), }, { fieldName: 'introduction', component: 'Textarea', - label: '个人简介', + label: t('profile.form.introduction'), }, ]; });apps/web-ele/src/views/_core/profile/index.vue (3)
16-33: Replace hardcoded Chinese labels with i18n keys.The tab labels use hardcoded Chinese strings. Since the PR adds localization files (page.json), these should use i18n for consistency and maintainability.
Example refactor:
+import { useI18n } from 'vue-i18n'; + +const { t } = useI18n(); + const tabs = ref([ { - label: '基本设置', + label: t('page.profile.tabs.basic'), value: 'basic', }, { - label: '安全设置', + label: t('page.profile.tabs.security'), value: 'security', }, { - label: '修改密码', + label: t('page.profile.tabs.password'), value: 'password', }, { - label: '新消息提醒', + label: t('page.profile.tabs.notice'), value: 'notice', }, ]);
38-38: Use i18n for the title.The hardcoded Chinese title '个人中心' should use i18n for consistency with other localization changes.
Apply this diff:
- title="个人中心" + :title="t('page.profile.title')"
43-46: Consider using dynamic component for better performance.Multiple
v-ifdirectives cause components to be created and destroyed on each tab switch. Consider using a dynamic component with:isorv-showfor better performance, especially if tab components maintain internal state.Example using dynamic component:
+<script setup lang="ts"> +const componentMap = { + basic: ProfileBase, + security: ProfileSecuritySetting, + password: ProfilePasswordSetting, + notice: ProfileNotificationSetting, +}; +</script> + <template #content> - <ProfileBase v-if="tabsValue === 'basic'" /> - <ProfileSecuritySetting v-if="tabsValue === 'security'" /> - <ProfilePasswordSetting v-if="tabsValue === 'password'" /> - <ProfileNotificationSetting v-if="tabsValue === 'notice'" /> + <component :is="componentMap[tabsValue]" /> </template>packages/effects/common-ui/src/ui/profile/password-setting.vue (1)
37-43: Optimize by fetching values only when validation succeeds.Currently,
getValues()is called before checking if the form is valid. This performs unnecessary work when validation fails.Apply this diff:
async function handleSubmit() { const { valid } = await formApi.validate(); - const values = await formApi.getValues(); if (valid) { + const values = await formApi.getValues(); emit('submit', values); } }packages/effects/common-ui/src/ui/profile/types.ts (1)
12-17: Consider a more specific name for this interface.The name
FormSchemaItemsuggests a generic form schema type, but the fixedvalue: booleanmakes it specific to toggle/switch fields used by notification settings. Consider renaming toNotificationSettingItemor similar to better reflect its purpose and avoid confusion.Example refactor:
-export interface FormSchemaItem { +export interface NotificationSettingItem { description: string; fieldName: string; label: string; value: boolean; } export interface SettingProps { - formSchema: FormSchemaItem[]; + formSchema: NotificationSettingItem[]; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (53)
apps/web-antd/src/layouts/basic.vue(3 hunks)apps/web-antd/src/locales/langs/en-US/page.json(1 hunks)apps/web-antd/src/locales/langs/zh-CN/page.json(1 hunks)apps/web-antd/src/router/routes/modules/vben.ts(1 hunks)apps/web-antd/src/views/_core/profile/base-setting.vue(1 hunks)apps/web-antd/src/views/_core/profile/index.vue(1 hunks)apps/web-antd/src/views/_core/profile/notification-setting.vue(1 hunks)apps/web-antd/src/views/_core/profile/password-setting.vue(1 hunks)apps/web-antd/src/views/_core/profile/security-setting.vue(1 hunks)apps/web-ele/src/layouts/basic.vue(3 hunks)apps/web-ele/src/locales/langs/en-US/page.json(1 hunks)apps/web-ele/src/locales/langs/zh-CN/page.json(1 hunks)apps/web-ele/src/router/routes/modules/vben.ts(1 hunks)apps/web-ele/src/views/_core/profile/base-setting.vue(1 hunks)apps/web-ele/src/views/_core/profile/index.vue(1 hunks)apps/web-ele/src/views/_core/profile/notification-setting.vue(1 hunks)apps/web-ele/src/views/_core/profile/password-setting.vue(1 hunks)apps/web-ele/src/views/_core/profile/security-setting.vue(1 hunks)apps/web-naive/src/layouts/basic.vue(3 hunks)apps/web-naive/src/locales/langs/en-US/page.json(1 hunks)apps/web-naive/src/locales/langs/zh-CN/page.json(1 hunks)apps/web-naive/src/router/routes/modules/vben.ts(1 hunks)apps/web-naive/src/views/_core/profile/base-setting.vue(1 hunks)apps/web-naive/src/views/_core/profile/index.vue(1 hunks)apps/web-naive/src/views/_core/profile/notification-setting.vue(1 hunks)apps/web-naive/src/views/_core/profile/password-setting.vue(1 hunks)apps/web-naive/src/views/_core/profile/security-setting.vue(1 hunks)apps/web-tdesign/src/layouts/basic.vue(3 hunks)apps/web-tdesign/src/locales/langs/en-US/page.json(1 hunks)apps/web-tdesign/src/locales/langs/zh-CN/page.json(1 hunks)apps/web-tdesign/src/router/routes/modules/vben.ts(1 hunks)apps/web-tdesign/src/views/_core/profile/base-setting.vue(1 hunks)apps/web-tdesign/src/views/_core/profile/index.vue(1 hunks)apps/web-tdesign/src/views/_core/profile/notification-setting.vue(1 hunks)apps/web-tdesign/src/views/_core/profile/password-setting.vue(1 hunks)apps/web-tdesign/src/views/_core/profile/security-setting.vue(1 hunks)packages/effects/common-ui/src/ui/index.ts(1 hunks)packages/effects/common-ui/src/ui/profile/base-setting.vue(1 hunks)packages/effects/common-ui/src/ui/profile/index.ts(1 hunks)packages/effects/common-ui/src/ui/profile/notification-setting.vue(1 hunks)packages/effects/common-ui/src/ui/profile/password-setting.vue(1 hunks)packages/effects/common-ui/src/ui/profile/profile.vue(1 hunks)packages/effects/common-ui/src/ui/profile/security-setting.vue(1 hunks)packages/effects/common-ui/src/ui/profile/types.ts(1 hunks)playground/src/layouts/basic.vue(3 hunks)playground/src/locales/langs/en-US/page.json(1 hunks)playground/src/locales/langs/zh-CN/page.json(1 hunks)playground/src/router/routes/modules/vben.ts(1 hunks)playground/src/views/_core/profile/base-setting.vue(1 hunks)playground/src/views/_core/profile/index.vue(1 hunks)playground/src/views/_core/profile/notification-setting.vue(1 hunks)playground/src/views/_core/profile/password-setting.vue(1 hunks)playground/src/views/_core/profile/security-setting.vue(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-12-04T04:41:30.161Z
Learnt from: mynetfan
Repo: vbenjs/vue-vben-admin PR: 5013
File: docs/src/components/layout-ui/page.md:31-31
Timestamp: 2024-12-04T04:41:30.161Z
Learning: 在 Vben Admin 项目的 `Page` 组件中,`extra` 内容仅通过 slots 提供,没有对应的 prop 属性。
Applied to files:
packages/effects/common-ui/src/ui/profile/profile.vue
📚 Learning: 2024-12-04T04:43:22.179Z
Learnt from: mynetfan
Repo: vbenjs/vue-vben-admin PR: 5013
File: docs/src/components/layout-ui/page.md:23-24
Timestamp: 2024-12-04T04:43:22.179Z
Learning: 在 `docs/src/components/layout-ui/page.md` 的 `Page` 组件中,`title` 和 `description` 属性有意使用 `string|slot` 类型表示法,表示它们可以接受字符串或插槽。
Applied to files:
packages/effects/common-ui/src/ui/profile/profile.vue
🧬 Code graph analysis (5)
playground/src/router/routes/modules/vben.ts (1)
playground/src/locales/index.ts (1)
$t(102-102)
apps/web-tdesign/src/router/routes/modules/vben.ts (1)
apps/web-tdesign/src/locales/index.ts (1)
$t(77-77)
apps/web-antd/src/router/routes/modules/vben.ts (5)
packages/locales/src/index.ts (1)
$t(13-13)apps/web-ele/src/locales/index.ts (1)
$t(102-102)apps/web-antd/src/locales/index.ts (1)
$t(102-102)apps/web-naive/src/locales/index.ts (1)
$t(38-38)playground/src/locales/index.ts (1)
$t(102-102)
apps/web-naive/src/router/routes/modules/vben.ts (1)
apps/web-naive/src/locales/index.ts (1)
$t(38-38)
apps/web-ele/src/router/routes/modules/vben.ts (2)
packages/locales/src/index.ts (1)
$t(13-13)apps/web-ele/src/locales/index.ts (1)
$t(102-102)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Lint (ubuntu-latest)
- GitHub Check: Check (ubuntu-latest)
- GitHub Check: Test (windows-latest)
- GitHub Check: Lint (windows-latest)
- GitHub Check: Check (windows-latest)
- GitHub Check: post-update (ubuntu-latest)
- GitHub Check: post-update (windows-latest)
🔇 Additional comments (29)
apps/web-antd/src/locales/langs/zh-CN/page.json (1)
7-8: LGTM!The translation key addition is correctly formatted, and "个人中心" is an appropriate Chinese translation for "Profile".
apps/web-antd/src/locales/langs/en-US/page.json (1)
7-8: LGTM!The locale key addition is properly formatted with correct JSON syntax.
apps/web-ele/src/locales/langs/en-US/page.json (1)
7-8: LGTM! Clean locale addition.The JSON syntax is correct and the "Profile" translation is appropriate for the new profile feature.
apps/web-naive/src/locales/langs/en-US/page.json (1)
7-8: LGTM! Consistent locale addition.The change mirrors the locale update in other apps, maintaining consistency across the monorepo.
apps/web-naive/src/locales/langs/zh-CN/page.json (1)
7-8: LGTM! Appropriate Chinese translation.The translation "个人中心" (Personal Center) is idiomatic and commonly used for profile/account settings in Chinese applications.
playground/src/locales/langs/zh-CN/page.json (2)
9-9: Verify if this change is intentional.The trailing comma addition to "codeSentTo" appears unrelated to the profile feature. Please confirm this change is intentional.
10-10: LGTM! Consistent profile translation.The Chinese translation matches other apps in the PR.
packages/effects/common-ui/src/ui/index.ts (1)
5-5: LGTM! Proper barrel export.The export follows the existing pattern and properly exposes the profile module from the common-ui package.
apps/web-ele/src/locales/langs/zh-CN/page.json (1)
7-8: LGTM! Consistent Chinese localization.The translation is consistent with other apps and properly formatted.
apps/web-naive/src/layouts/basic.vue (2)
5-5: LGTM! Proper router setup.The
useRouterimport and router instance creation are correctly implemented to support navigation to the Profile route.Also applies to: 56-56
66-72: LGTM! Profile menu item properly configured.The Profile menu item is well-structured with:
- Named route navigation correctly referencing the 'Profile' route defined in
apps/web-naive/src/router/routes/modules/vben.ts- Localized text using the newly added translation key
- Appropriate icon
apps/web-ele/src/router/routes/modules/vben.ts (1)
92-101: LGTM! Profile route properly configured and consistent across all apps.The route follows existing patterns with:
- Lazy-loaded component for code splitting ✓
hideInMenu: trueto exclude from sidebar (accessible via user dropdown)- Localized title using the newly added translation key
- Consistent icon with the menu item
- Component verified at
apps/web-ele/src/views/_core/profile/index.vue✓- Route consistently implemented across all UI variants (web-antd, web-tdesign, web-naive, web-ele)
playground/src/locales/langs/en-US/page.json (1)
9-10: LGTM!The localization key is properly added with correct JSON formatting.
apps/web-antd/src/router/routes/modules/vben.ts (1)
92-101: LGTM!The Profile route is well-configured with appropriate meta properties, dynamic component import for code splitting, and follows the established routing patterns in the codebase.
playground/src/router/routes/modules/vben.ts (1)
104-113: LGTM!The Profile route definition is properly configured and follows the established routing patterns.
apps/web-tdesign/src/locales/langs/en-US/page.json (1)
7-8: LGTM!The translation entry is correctly added with proper JSON syntax and aligns with the profile feature addition.
apps/web-tdesign/src/locales/langs/zh-CN/page.json (1)
7-8: LGTM!The Chinese translation is properly added and consistent with the English locale file.
apps/web-tdesign/src/router/routes/modules/vben.ts (1)
92-101: LGTM!The Profile route is well-structured:
- Proper lazy loading for code splitting
hideInMenu: trueappropriately keeps the profile page out of the main navigation- Uses i18n for the title via
page.auth.profile- Consistent with existing route patterns in the file
apps/web-ele/src/views/_core/profile/base-setting.vue (2)
14-27: Clarify mock data usage.The constant is named
MOCK_ROLES_OPTIONS, suggesting this is placeholder data. If these roles are for demonstration purposes only, consider adding a comment. If this should fetch real role options from an API, implement that instead.Is this mock data intentional for the feature release, or should roles be fetched from a backend API?
29-56: Internationalize hardcoded Chinese text.All field labels are hardcoded in Chinese. Use the i18n system (via
$t()) for maintainability and multi-language support.⛔ Skipped due to learnings
Learnt from: mynetfan Repo: vbenjs/vue-vben-admin PR: 5587 File: playground/src/views/examples/loading/index.vue:15-18 Timestamp: 2025-02-23T04:21:24.691Z Learning: Chinese text in the description of the loading component example (`playground/src/views/examples/loading/index.vue`) is intentionally kept without i18n support.apps/web-naive/src/router/routes/modules/vben.ts (1)
92-101: LGTM! Well-structured route definition.The Profile route is properly configured with:
- Lazy-loaded component for better performance
- i18n support via
$t('page.auth.profile')- Hidden from menu (
hideInMenu: true), appropriate for user profile access- Consistent icon and naming conventions
Verify that the locale key
page.auth.profileis defined in the locale files mentioned in the PR (apps/web-naive/src/locales/langs/en-US/page.json and zh-CN/page.json).playground/src/views/_core/profile/password-setting.vue (1)
12-53: Internationalize hardcoded Chinese text.All labels and placeholders are hardcoded in Chinese. Use the i18n system for multi-language support.
⛔ Skipped due to learnings
Learnt from: mynetfan Repo: vbenjs/vue-vben-admin PR: 5587 File: playground/src/views/examples/loading/index.vue:15-18 Timestamp: 2025-02-23T04:21:24.691Z Learning: Chinese text in the description of the loading component example (`playground/src/views/examples/loading/index.vue`) is intentionally kept without i18n support.apps/web-tdesign/src/views/_core/profile/security-setting.vue (1)
6-39: Internationalize hardcoded Chinese text.All labels and descriptions are hardcoded in Chinese. Use the i18n system for multi-language support.
⛔ Skipped due to learnings
Learnt from: mynetfan Repo: vbenjs/vue-vben-admin PR: 5587 File: playground/src/views/examples/loading/index.vue:15-18 Timestamp: 2025-02-23T04:21:24.691Z Learning: Chinese text in the description of the loading component example (`playground/src/views/examples/loading/index.vue`) is intentionally kept without i18n support.apps/web-ele/src/views/_core/profile/security-setting.vue (1)
6-39: Internationalize hardcoded Chinese text.All labels and descriptions are hardcoded in Chinese. Use the i18n system for multi-language support.
⛔ Skipped due to learnings
Learnt from: mynetfan Repo: vbenjs/vue-vben-admin PR: 5587 File: playground/src/views/examples/loading/index.vue:15-18 Timestamp: 2025-02-23T04:21:24.691Z Learning: Chinese text in the description of the loading component example (`playground/src/views/examples/loading/index.vue`) is intentionally kept without i18n support.apps/web-ele/src/views/_core/profile/notification-setting.vue (1)
8-13: Internationalize hardcoded Chinese text.All labels and descriptions are hardcoded in Chinese. Consider using the i18n system (via
$t()) for better maintainability and multi-language support, consistent with locale updates elsewhere in the PR.⛔ Skipped due to learnings
Learnt from: mynetfan Repo: vbenjs/vue-vben-admin PR: 5587 File: playground/src/views/examples/loading/index.vue:15-18 Timestamp: 2025-02-23T04:21:24.691Z Learning: Chinese text in the description of the loading component example (`playground/src/views/examples/loading/index.vue`) is intentionally kept without i18n support.packages/effects/common-ui/src/ui/profile/index.ts (1)
1-6: LGTM!Clean barrel export structure for the profile UI module. The exports are well-organized and follow standard patterns.
playground/src/views/_core/profile/index.vue (1)
16-33: Extract hardcoded text and consider reducing duplication.Same i18n issue as other profile index files - hardcoded Chinese text for tabs and title. Additionally, this structure is duplicated across apps/web-naive, apps/web-tdesign, and playground, suggesting shared configuration could be extracted.
Also applies to: 38-38
⛔ Skipped due to learnings
Learnt from: mynetfan Repo: vbenjs/vue-vben-admin PR: 5587 File: playground/src/views/examples/loading/index.vue:15-18 Timestamp: 2025-02-23T04:21:24.691Z Learning: Chinese text in the description of the loading component example (`playground/src/views/examples/loading/index.vue`) is intentionally kept without i18n support.apps/web-tdesign/src/views/_core/profile/notification-setting.vue (1)
8-25: Extract hardcoded Chinese text to i18n resources.All user-facing text is hardcoded in Chinese. Extract to locale files for internationalization support.
⛔ Skipped due to learnings
Learnt from: mynetfan Repo: vbenjs/vue-vben-admin PR: 5587 File: playground/src/views/examples/loading/index.vue:15-18 Timestamp: 2025-02-23T04:21:24.691Z Learning: Chinese text in the description of the loading component example (`playground/src/views/examples/loading/index.vue`) is intentionally kept without i18n support.packages/effects/common-ui/src/ui/profile/notification-setting.vue (1)
1-53: LGTM! Clean controlled component implementation.The component follows Vue 3 best practices with a controlled component pattern, proper type safety, and clean event emission. The use of the shadcn-ui Form components ensures consistent styling and accessibility.
| const MOCK_ROLES_OPTIONS: BasicOption[] = [ | ||
| { | ||
| label: '管理员', | ||
| value: 'super', | ||
| }, | ||
| { | ||
| label: '用户', | ||
| value: 'user', | ||
| }, | ||
| { | ||
| label: '测试', | ||
| value: 'test', | ||
| }, | ||
| ]; | ||
| const formSchema = computed((): VbenFormSchema[] => { | ||
| return [ | ||
| { | ||
| fieldName: 'realName', | ||
| component: 'Input', | ||
| label: '姓名', | ||
| }, | ||
| { | ||
| fieldName: 'username', | ||
| component: 'Input', | ||
| label: '用户名', | ||
| }, | ||
| { | ||
| fieldName: 'roles', | ||
| component: 'Select', | ||
| componentProps: { | ||
| mode: 'tags', | ||
| options: MOCK_ROLES_OPTIONS, | ||
| }, | ||
| label: '角色', | ||
| }, | ||
| { | ||
| fieldName: 'introduction', | ||
| component: 'Textarea', | ||
| label: '个人简介', | ||
| }, | ||
| ]; | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Use i18n for labels instead of hardcoded Chinese text.
Both MOCK_ROLES_OPTIONS and formSchema contain hardcoded Chinese labels. For proper internationalization support, these should use translation keys via $t() or similar i18n utilities.
Example refactor:
const MOCK_ROLES_OPTIONS: BasicOption[] = [
{
- label: '管理员',
+ label: $t('profile.roles.admin'),
value: 'super',
},
// ... other options
];Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/web-antd/src_views/_core/profile/base-setting.vue around lines 14 to 56,
the MOCK_ROLES_OPTIONS and formSchema use hardcoded Chinese labels; replace
these with i18n translation keys by calling the translator (e.g., const { t } =
useI18n() or this.$t) when building options and schema so labels become
t('profile.role.admin'), t('profile.label.name'), etc.; add/choose appropriate
translation keys in the locale files and ensure componentProps.options and
schema.label use the translated strings (keep keys consistent and computed so
reactivity works).
| onMounted(async () => { | ||
| const data = await getUserInfoApi(); | ||
| profileBaseSettingRef.value.getFormApi().setValues(data); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling and null check for the API call.
The onMounted hook has two issues:
- No error handling: If
getUserInfoApi()fails, the error is unhandled and users receive no feedback - Missing null check:
profileBaseSettingRef.valuecould be null/undefined if the component hasn't rendered yet
Apply this diff:
onMounted(async () => {
- const data = await getUserInfoApi();
- profileBaseSettingRef.value.getFormApi().setValues(data);
+ try {
+ const data = await getUserInfoApi();
+ if (profileBaseSettingRef.value) {
+ profileBaseSettingRef.value.getFormApi().setValues(data);
+ }
+ } catch (error) {
+ console.error('Failed to load user profile:', error);
+ // Consider showing user-facing error notification
+ }
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onMounted(async () => { | |
| const data = await getUserInfoApi(); | |
| profileBaseSettingRef.value.getFormApi().setValues(data); | |
| }); | |
| onMounted(async () => { | |
| try { | |
| const data = await getUserInfoApi(); | |
| if (profileBaseSettingRef.value) { | |
| profileBaseSettingRef.value.getFormApi().setValues(data); | |
| } | |
| } catch (error) { | |
| console.error('Failed to load user profile:', error); | |
| // Consider showing user-facing error notification | |
| } | |
| }); |
🤖 Prompt for AI Agents
In apps/web-antd/src/views/_core/profile/base-setting.vue around lines 58 to 61,
the onMounted block lacks error handling and does not guard against
profileBaseSettingRef.value being null; wrap the async call in a try/catch,
await getUserInfoApi() inside the try, check that profileBaseSettingRef.value
and profileBaseSettingRef.value.getFormApi() are defined (or await nextTick()
before accessing) and only call setValues when data is non-null, and in the
catch log the error and surface user feedback (e.g., show an error notification)
so failures are handled gracefully.
| const tabs = ref([ | ||
| { | ||
| label: '基本设置', | ||
| value: 'basic', | ||
| }, | ||
| { | ||
| label: '安全设置', | ||
| value: 'security', | ||
| }, | ||
| { | ||
| label: '修改密码', | ||
| value: 'password', | ||
| }, | ||
| { | ||
| label: '新消息提醒', | ||
| value: 'notice', | ||
| }, | ||
| ]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Internationalize hardcoded Chinese labels.
Tab labels are hardcoded in Chinese. Use the i18n system for multi-language support.
🤖 Prompt for AI Agents
In apps/web-antd/src/views/_core/profile/index.vue around lines 16 to 33, the
tab labels are hardcoded in Chinese; replace them with i18n lookups by
importing/using the locale composable (useI18n or $t) in the component setup and
build the tabs array with t('profile.tabs.basic'), t('profile.tabs.security'),
t('profile.tabs.password'), t('profile.tabs.notice') (or equivalent keys); also
add those keys to your locale JSON/YAML files for all supported languages so
translations exist and keep the tab value fields unchanged.
| { | ||
| value: true, | ||
| fieldName: 'accountPassword', | ||
| label: '账户密码', | ||
| description: '其他用户的消息将以站内信的形式通知', | ||
| }, | ||
| { | ||
| value: true, | ||
| fieldName: 'systemMessage', | ||
| label: '系统消息', | ||
| description: '系统消息将以站内信的形式通知', | ||
| }, | ||
| { | ||
| value: true, | ||
| fieldName: 'todoTask', | ||
| label: '待办任务', | ||
| description: '待办任务将以站内信的形式通知', | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Extract hardcoded Chinese text to i18n resource files.
All labels and descriptions are hardcoded in Chinese, preventing internationalization.
Extract to locale files and use i18n keys like $t('profile.notification.accountPassword.label') and $t('profile.notification.accountPassword.description').
🤖 Prompt for AI Agents
In apps/web-antd/src/views/_core/profile/notification-setting.vue around lines 8
to 25, the notification item labels and descriptions are hardcoded in Chinese;
replace each literal with i18n lookups (e.g.
$t('profile.notification.accountPassword.label') and
$t('profile.notification.accountPassword.description')) and add corresponding
keys for accountPassword, systemMessage and todoTask in the locale resource
files (both zh and en or other supported locales). Keep existing fieldName and
value fields unchanged, ensure the i18n keys follow the suggested hierarchy
(profile.notification.<field>.(label|description)), and provide sensible
fallback strings in the locale files.
| function handleSubmit() { | ||
| message.success('密码修改成功'); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Missing API implementation for password change.
The submit handler only displays a client-side success message without making an actual API call to change the password on the server.
Implement the password change API call before the success message:
-function handleSubmit() {
+async function handleSubmit(values: Record<string, any>) {
+ try {
+ // Example: await changePasswordApi(values);
+ // TODO: Implement actual API call
- message.success('密码修改成功');
+ message.success('密码修改成功');
+ } catch (error) {
+ message.error('密码修改失败');
+ }
}Run the following script to verify if a password change API already exists in the codebase:
🏁 Script executed:
#!/bin/bash
# Search for password change API implementations
rg -nP --type=ts 'password|Password' -g '**/api/**' -C2Length of output: 2854
🏁 Script executed:
#!/bin/bash
# Search for password change/update API with various naming patterns
rg -nP '(change|update|modify|set).*[Pp]assword' --type=ts -C2Length of output: 0
🏁 Script executed:
#!/bin/bash
# Look at the password-setting.vue component to understand context
cat apps/web-antd/src/views/_core/profile/password-setting.vueLength of output: 1516
🏁 Script executed:
#!/bin/bash
# Search for ProfilePasswordSetting component definition
fd -type f -name "*.ts" -o -name "*.vue" | xargs grep -l "ProfilePasswordSetting" | head -20Length of output: 170
🏁 Script executed:
#!/bin/bash
# Search for any password endpoint in backend (beyond login)
find . -type f \( -name "*.ts" -o -name "*.js" \) -path "*/api/*" -o -path "*/backend*" | xargs grep -l "password" 2>/dev/null | grep -v node_modulesLength of output: 305
🏁 Script executed:
#!/bin/bash
# Check if handleSubmit receives parameters from the form component
rg -nP "handleSubmit|@submit" apps/web-antd/src/views/_core/profile/password-setting.vue -A5 -B5Length of output: 308
🏁 Script executed:
#!/bin/bash
# Fix the fd command - search for ProfilePasswordSetting
rg -l "ProfilePasswordSetting" --type ts --type vue | head -20Length of output: 27
🏁 Script executed:
#!/bin/bash
# Check backend-mock structure to understand API patterns
find apps/backend-mock/api -type f -name "*.ts" | head -20Length of output: 830
🏁 Script executed:
#!/bin/bash
# Search for other submit handlers to understand parameter passing pattern
rg -nP "function\s+handle\w+\s*\([^)]*\)\s*\{" apps/web-antd/src/views/ -C2 | head -50Length of output: 1754
Missing API implementation AND handler parameter for password change.
The submit handler doesn't accept form values and has no API call to change the password on the server. Other similar forms in the codebase (register, forget-password) correctly receive form values and handle them.
Two issues to fix:
- Handler signature: Add parameter to receive form values (currently receives nothing)
- Backend endpoint: No password change endpoint exists in the backend
- API call: Add the actual API call before the success message
-function handleSubmit() {
+async function handleSubmit(values: Record<string, any>) {
+ try {
+ // Example: await changePasswordApi(values);
+ // TODO: Implement actual API call and create backend endpoint
- message.success('密码修改成功');
+ message.success('密码修改成功');
+ } catch (error) {
+ message.error('密码修改失败');
+ }
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/web-antd/src/views/_core/profile/password-setting.vue around lines 55 to
57, the handleSubmit function currently has no parameter and does not call the
backend to change the password; update the handler to accept the form values
parameter (e.g., values or formData), call the appropriate password-change API
endpoint (implement the backend endpoint if missing) using those values and
await its response, handle errors (show error message on failure) and only show
message.success('密码修改成功') after the API confirms success.
| <Form class="space-y-8"> | ||
| <div class="space-y-4"> | ||
| <template v-for="item in formSchema" :key="item.fieldName"> | ||
| <FormField type="checkbox" :name="item.fieldName"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify FormField type for Switch components.
The FormField uses type="checkbox" for Switch components. Verify this aligns with the form validation library's expectations—some form libraries distinguish between checkbox and switch/toggle types for proper accessibility and validation behavior.
Check the @vben-core/shadcn-ui Form documentation to confirm whether type="checkbox" is the correct type for Switch components or if a more specific type exists.
🌐 Web query:
shadcn-ui Form component type options for Switch
💡 Result:
Short answer — how to wire the shadcn-ui Switch inside the Form components:
- Switch component props: checked?, onCheckedChange?(checked:boolean), name?, disabled? (use these to control it). [1]
- React Hook Form (FormField): use field.value and field.onChange on ; add aria-invalid on the Switch and data-invalid on the Field to show errors. [2]
- TanStack Form (FormField): use field.state.value and field.handleChange on ; add aria-invalid on the Switch and data-invalid on the Field for errors. [3]
Sources: shadcn-ui Switch API and form docs. [1][2][3]
References
[1] shadcn-ui Switch API.
[2] shadcn-ui React Hook Form docs.
[3] shadcn-ui TanStack Form docs.
---
🏁 Script executed:
```shell
#!/bin/bash
# Find FormField component definition
fd -e vue -e ts -e tsx -e jsx --type f | xargs rg -l "FormField" -g "!node_modules" | head -20
Length of output: 698
🏁 Script executed:
#!/bin/bash
# Search for FormField component implementation/export
rg -nP "export.*FormField|component.*FormField" -g "!node_modules" --type ts --type tsx --type vueLength of output: 27
🏁 Script executed:
#!/bin/bash
# Find Switch + FormField usage patterns to see how type is used
rg -nB2 -A2 'FormField.*type=' -g "!node_modules" --type vueLength of output: 27
🏁 Script executed:
#!/bin/bash
# Check if there are any comments or documentation about FormField types
rg -nP "type\s*=\s*['\"]" packages/effects/common-ui/src/ui/profile/security-setting.vueLength of output: 61
---
🏁 Script executed:
```shell
#!/bin/bash
# Read the FormField component definition
cat packages/@core/ui-kit/form-ui/src/form-render/form-field.vue
Length of output: 10412
🏁 Script executed:
#!/bin/bash
# Check type definitions
cat packages/@core/ui-kit/form-ui/src/types.tsLength of output: 9282
🏁 Script executed:
#!/bin/bash
# Find all FormField type attribute usages
grep -r "FormField.*type=" packages/ --include="*.vue" | head -30Length of output: 247
🏁 Script executed:
#!/bin/bash
# Check the security-setting.vue file context around line 32
cat packages/effects/common-ui/src/ui/profile/security-setting.vueLength of output: 1342
Remove invalid type="checkbox" attribute from FormField.
The type="checkbox" attribute on <FormField> at line 32 is invalid—shadcn-ui's FormField is a state-management wrapper that doesn't accept a type prop. The actual control type is determined by the component inside <FormControl> (in this case, Switch). Remove the attribute.
<FormField :name="item.fieldName">
🤖 Prompt for AI Agents
In packages/effects/common-ui/src/ui/profile/security-setting.vue around line
32, the FormField is incorrectly given a type="checkbox" prop which is invalid
for shadcn-ui's FormField wrapper; remove the type="checkbox" attribute so the
FormField is only passed the name prop and let the inner FormControl/Switch
determine the control type.
| onMounted(async () => { | ||
| const data = await getUserInfoApi(); | ||
| profileBaseSettingRef.value.getFormApi().setValues(data); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Add error handling for the API call.
The onMounted hook lacks error handling for the async getUserInfoApi() call. If the API fails, the application could show cryptic errors or fail silently.
Apply this diff to add error handling:
onMounted(async () => {
- const data = await getUserInfoApi();
- profileBaseSettingRef.value.getFormApi().setValues(data);
+ try {
+ const data = await getUserInfoApi();
+ profileBaseSettingRef.value?.getFormApi().setValues(data);
+ } catch (error) {
+ console.error('Failed to load user info:', error);
+ // Consider showing a user-friendly error message
+ }
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onMounted(async () => { | |
| const data = await getUserInfoApi(); | |
| profileBaseSettingRef.value.getFormApi().setValues(data); | |
| }); | |
| onMounted(async () => { | |
| try { | |
| const data = await getUserInfoApi(); | |
| profileBaseSettingRef.value?.getFormApi().setValues(data); | |
| } catch (error) { | |
| console.error('Failed to load user info:', error); | |
| // Consider showing a user-friendly error message | |
| } | |
| }); |
🤖 Prompt for AI Agents
In playground/src/views/_core/profile/base-setting.vue around lines 58 to 61,
the onMounted async call to getUserInfoApi() lacks error handling; wrap the
await in try/catch, handle errors by logging (or sending to a logger) and
showing a user-friendly fallback (e.g., a toast/error state or default values)
and ensure profileBaseSettingRef.value.getFormApi().setValues(data) only runs
when the API returns valid data; also consider setting a loading state before
the call and clearing it in finally.
| onMounted(async () => { | ||
| const data = await getUserInfoApi(); | ||
| profileBaseSettingRef.value.getFormApi().setValues(data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Add null safety check for ref access.
The code accesses profileBaseSettingRef.value without checking if it's defined, which could cause a runtime error if the component hasn't mounted yet.
Use optional chaining as shown in the previous comment, or add an explicit null check.
🤖 Prompt for AI Agents
In playground/src/views/_core/profile/base-setting.vue around line 60, the code
directly accesses profileBaseSettingRef.value.getFormApi().setValues(data)
without null safety; update the call to guard against undefined by using
optional chaining (e.g.,
profileBaseSettingRef.value?.getFormApi()?.setValues(data)) or add an explicit
check (if (profileBaseSettingRef.value) { ... }) before invoking
getFormApi().setValues to prevent runtime errors when the ref isn't mounted.
| function handleSubmit() { | ||
| message.success('密码修改成功'); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement actual password change API call.
The handleSubmit function only displays a success message without calling any API to actually change the password. This creates a false success state.
Consider implementing:
async function handleSubmit() {
try {
const values = profilePasswordSettingRef.value?.getFormApi()?.getValues();
await changePasswordApi(values);
message.success('密码修改成功');
} catch (error) {
message.error('密码修改失败');
}
}🤖 Prompt for AI Agents
In playground/src/views/_core/profile/password-setting.vue around lines 55 to
57, handleSubmit currently only shows a success toast and does not call the
backend, producing a false success; update handleSubmit to read form values from
profilePasswordSettingRef, call the change password API (await
changePasswordApi(values)), and handle errors by showing an error message;
ensure you perform validation or handle API validation errors, disable the
submit button or show a loading state while awaiting, and catch exceptions to
call message.error('密码修改失败').
| const formSchema = computed(() => { | ||
| return [ | ||
| { | ||
| value: true, | ||
| fieldName: 'accountPassword', | ||
| label: '账户密码', | ||
| description: '当前密码强度:强', | ||
| }, | ||
| { | ||
| value: true, | ||
| fieldName: 'securityPhone', | ||
| label: '密保手机', | ||
| description: '已绑定手机:138****8293', | ||
| }, | ||
| { | ||
| value: true, | ||
| fieldName: 'securityQuestion', | ||
| label: '密保问题', | ||
| description: '未设置密保问题,密保问题可有效保护账户安全', | ||
| }, | ||
| { | ||
| value: true, | ||
| fieldName: 'securityEmail', | ||
| label: '备用邮箱', | ||
| description: '已绑定邮箱:ant***sign.com', | ||
| }, | ||
| { | ||
| value: false, | ||
| fieldName: 'securityMfa', | ||
| label: 'MFA 设备', | ||
| description: '未绑定 MFA 设备,绑定后,可以进行二次确认', | ||
| }, | ||
| ]; | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Extract hardcoded text to i18n and fetch dynamic data.
The form schema contains hardcoded Chinese text and mock data that should be handled differently:
- Labels and descriptions should use i18n keys for internationalization
- User-specific data (phone number, email, MFA status) should be fetched from the backend rather than hardcoded
- Consider whether
valueshould represent actual user settings rather than static booleans
Example pattern for i18n:
- label: '账户密码',
- description: '当前密码强度:强',
+ label: $t('profile.security.accountPassword.label'),
+ description: computed(() =>
+ $t('profile.security.accountPassword.description', { strength: userSecurityData.value.passwordStrength })
+ ),Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In playground/src/views/_core/profile/security-setting.vue around lines 6 to 39,
the formSchema currently contains hardcoded Chinese text and mock user data;
replace all literal labels and descriptions with i18n keys (use the component's
t(...) or $t(...) calls) and build description strings from translated
templates, and remove hardcoded user values; instead fetch the current user's
security data (phone, email, mfa enabled, password strength, security question
status) from the backend into a reactive state (e.g., onMounted or a store
action) and make the computed formSchema derive its value and description from
that reactive data (mask phone/email when composing description, use boolean
flags from the response for the value fields) so the UI is internationalized and
reflects real user settings rather than static booleans and mock text.
Description
Type of change
Please delete options that are not relevant.
pnpm-lock.yamlunless you introduce a new test example.Checklist
pnpm run docs:devcommand.pnpm test.feat:,fix:,perf:,docs:, orchore:.Summary by CodeRabbit
Release Notes