fix(settings): improve profile settings UI and i18n support

- Remove First Name and Last Name fields from Update Profile Information dialog
- Add i18n support for copy button messages (Copied to clipboard, Copy failed)
- Add Chinese translation for 'Update Profile Information'
- Fix QR code centering in 2FA dialog
- Fix disable account dialog formatting with proper line breaks
- Change disable account dialog icon type to warning for semantic correctness
This commit is contained in:
jingrow 2026-01-04 20:50:22 +08:00
parent 911ae5e53b
commit 79b92e7aae
4 changed files with 1480 additions and 95 deletions

View File

@ -21,6 +21,7 @@
"Agent Detail": "智能体详情",
"Flow Builder": "流程编排",
"Profile": "个人资料",
"Update Profile Information": "更新个人资料信息",
"Logout": "退出登录",
"Logged out": "已退出登录",
"AI Agent Workflow Platform": "AI Agent 工作流平台",
@ -355,6 +356,8 @@
"Unsaved": "未保存",
"Saved": "已保存",
"Copy failed, please copy manually": "复制失败,请手动复制",
"Copied to clipboard": "已复制到剪贴板",
"Copy failed": "复制失败",
"All": "全部",
"Recent": "最近使用",
"Favorites": "收藏",
@ -1237,5 +1240,122 @@
"Online Support": "在线客服",
"Feedback & Suggestions": "反馈建议",
"Guangzhou Sunflower Network Information Technology Co., Ltd.": "广州向日葵网络信息技术有限公司",
"All Rights Reserved": "版权所有"
"All Rights Reserved": "版权所有",
"API Access": "API 访问",
"API key and API secret can be used to access": "API 密钥和 API 密钥可用于访问",
"API key and API secret pairs can be used to access the Jingrow API.": "API 密钥和 API 密钥对可用于访问 Jingrow API。",
"Jingrow API": "Jingrow API",
"Create New API Key": "创建新的 API 密钥",
"Regenerate API Key": "重新生成 API 密钥",
"You don't have an API key yet. Click the button above to create one.": "您还没有 API 密钥。请点击上方按钮创建一个。",
"Please copy the API secret now. You won't be able to see it again!": "请立即复制 API 密钥。您将无法再次查看它!",
"API Secret": "API 密钥",
"SSH Keys": "SSH 密钥",
"Add SSH Key": "添加 SSH 密钥",
"Add New SSH Key": "添加新的 SSH 密钥",
"SSH Key": "SSH 密钥",
"SSH Fingerprint": "SSH 指纹",
"Added Time": "添加时间",
"Set as Default": "设为默认",
"No SSH keys configured": "未配置 SSH 密钥",
"Add a new SSH key to your account": "为您的账户添加新的 SSH 密钥",
"SSH key is required": "SSH 密钥是必填项",
"Link Partner Account": "关联合作伙伴账户",
"Enter the partner code provided by your partner": "输入您的合作伙伴提供的合作伙伴代码",
"Partner Code": "合作伙伴代码",
"For example: rGjw3hJ81b": "例如rGjw3hJ81b",
"Submit": "提交",
"Remove Partner": "移除合作伙伴",
"This will remove the partner associated with your account. Are you sure you want to remove this partner?": "这将移除与您的账户关联的合作伙伴。确定要移除此合作伙伴吗?",
"SSH key added successfully": "SSH 密钥添加成功",
"Failed to add SSH key": "添加 SSH 密钥失败",
"SSH key updated successfully": "SSH 密钥更新成功",
"Failed to set SSH key as default": "设置默认 SSH 密钥失败",
"SSH key deleted successfully": "SSH 密钥删除成功",
"Failed to delete SSH key": "删除 SSH 密钥失败",
"Are you sure you want to delete this SSH key?": "确定要删除此 SSH 密钥吗?",
"Advanced Features": "高级功能",
"Enable private benches": "启用私有工作台",
"Enable security portal": "启用安全门户",
"Save Changes": "保存更改",
"Feature flags updated successfully": "功能标志更新成功",
"Failed to update feature flags": "更新功能标志失败",
"Marketplace Developer": "应用市场开发者",
"Developers can publish their apps on the marketplace for users to subscribe to, either paid or free.": "开发者可以在应用市场发布自己的应用,供用户付费或免费订阅。",
"Become a Developer": "成为开发者",
"Become a Marketplace Developer?": "成为应用市场开发者?",
"After confirmation, you will be able to publish apps to our marketplace.": "确认后,您将能够在我们的应用市场发布应用。",
"Enable Two-Factor Authentication": "启用双因素认证",
"Disable Two-Factor Authentication": "禁用双因素认证",
"Enable two-factor authentication for your account to add an extra layer of security": "为您的账户启用双因素认证以增加额外的安全层",
"Disable two-factor authentication for your account": "为您的账户禁用双因素认证",
"Enable": "启用",
"Disable": "禁用",
"Reset Password": "重置密码",
"Change your account login password": "更改您的账户登录密码",
"Disable Account": "禁用账户",
"Enable Account": "启用账户",
"Disable your account and stop billing": "禁用您的账户并停止计费",
"Enable your account and resume billing": "启用您的账户并恢复计费",
"After confirming this action:": "确认此操作后:",
"Your account will be disabled": "您的账户将被禁用",
"Your activated sites will be suspended immediately and deleted after one week.": "您已激活的站点将立即暂停,并在一周后删除。",
"Your account billing will stop": "您的账户计费将停止",
"You can log in later to re-enable your account. Do you want to continue?": "您可以稍后登录以重新启用您的账户。是否继续?",
"Your account will be enabled": "您的账户将被启用",
"Your suspended sites will be reactivated": "您已暂停的站点将被重新激活",
"Your account billing will resume": "您的账户计费将恢复",
"Do you want to continue?": "是否继续?",
"Referral Program": "推荐有礼",
"Your exclusive referral link": "您的专属推荐链接",
"Invite others to join Jingrow,": "邀请他人加入 Jingrow",
"when they register and spend at least ¥100, you will get ¥20": "当他们注册并消费至少¥100时您将获得¥20",
"Jingrow Partner": "Jingrow 合作伙伴",
"Jingrow partner associated with your account": "与您的账户关联的 Jingrow 合作伙伴",
"Add Partner Code": "添加合作伙伴代码",
"Unlink Partner": "取消关联合作伙伴",
"Have a Jingrow partner referral code? Click": "有 Jingrow 合作伙伴推荐代码吗?点击",
"to associate with your partner team.": "以与您的合作伙伴团队关联。",
"Feature coming soon": "功能即将推出",
"is an invalid referral code": "是无效的推荐代码",
"Current Password": "当前密码",
"New Password": "新密码",
"Please enter current password": "请输入当前密码",
"Please enter new password": "请输入新密码",
"Please re-enter new password": "请重新输入新密码",
"New password cannot be the same as current password": "新密码不能与当前密码相同",
"Password strength is good 👍": "密码强度良好 👍",
"Tip: Password should contain symbols, numbers and uppercase letters": "提示:密码应包含符号、数字和大写字母",
"Password updated successfully": "密码更新成功",
"Your password has been updated": "您的密码已更新",
"Current password is incorrect": "当前密码不正确",
"Setting you as a developer...": "正在将您设置为开发者...",
"You can now publish apps to our marketplace": "您现在可以在我们的应用市场发布应用了",
"Failed to mark you as a developer": "将您设置为开发者失败",
"Approval Request has already been sent to Partner": "批准请求已发送给合作伙伴",
"Approval Request has been sent to Partner": "批准请求已发送给合作伙伴",
"If you disable two-factor authentication, your account will become insecure": "如果您禁用双因素认证,您的账户将变得不安全",
"Steps to Disable Two-Factor Authentication": "禁用双因素认证的步骤",
"Open the authenticator app": "打开身份验证器应用",
"Enter the code from the app below": "在下方输入应用中的代码",
"Verify the code in the app to disable two-factor authentication": "输入应用中的验证码以禁用双因素认证",
"Steps to Enable Two-Factor Authentication": "启用双因素认证的步骤",
"Download an authenticator app on your phone, such as Alibaba Cloud APP, etc.": "在手机上下载身份验证器应用,例如阿里云 APP 等",
"Scan the QR code": "扫描二维码",
"Enter the code from the authenticator app": "输入身份验证器应用中的代码",
"Enter the code from the authenticator app below": "在下方输入身份验证器应用中的代码",
"Note": "注意",
"If you cannot access the authenticator app, your account will be locked. Please ensure you back up your vault/key.": "如果您无法访问身份验证器应用,您的账户将被锁定。请确保您已备份您的密钥。",
"Setup Key": "设置密钥",
"Verify the code in the app to enable two-factor authentication": "输入应用中的验证码以启用双因素认证",
"Please enter the code from the authenticator app": "请输入身份验证器应用中的代码",
"Two-factor authentication enabled successfully": "双因素认证已成功启用",
"Two-factor authentication disabled successfully": "双因素认证已成功禁用",
"Invalid TOTP code, please try again": "无效的 TOTP 代码,请重试",
"Failed to enable two-factor authentication": "启用双因素认证失败",
"Failed to disable two-factor authentication": "禁用双因素认证失败",
"Failed to load QR code": "加载二维码失败",
"Enabling two-factor authentication...": "正在启用双因素认证...",
"Disabling two-factor authentication...": "正在禁用双因素认证..."
}

View File

@ -233,7 +233,7 @@ export const updateFeatureFlags = async (values: Record<string, boolean>): Promi
// 获取用户信息(包含 API Key
// 使用 jcloud.api.account.get API 获取账户信息
export const getUserAccountInfo = async (): Promise<{ success: boolean; data?: any; message?: string }> => {
export const getUserAccountInfo = async (): Promise<{ success: boolean; data?: any; team?: any; message?: string }> => {
try {
const response = await axios.get(
`/api/action/jcloud.api.account.get`,
@ -246,7 +246,7 @@ export const getUserAccountInfo = async (): Promise<{ success: boolean; data?: a
const result = response.data?.message || response.data
if (result?.user) {
return { success: true, data: result.user }
return { success: true, data: result.user, team: result.team }
}
return { success: false, message: 'API 返回的数据中未找到用户信息' }
@ -257,3 +257,298 @@ export const getUserAccountInfo = async (): Promise<{ success: boolean; data?: a
}
}
}
// 成为开发者(更新 Team 的 is_developer 字段)
// 使用 jcloud.api.client.set_value API与 jcloud dashboard 保持一致
export const becomeDeveloper = async (teamName: string): Promise<{ success: boolean; data?: any; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.client.set_value`,
{
pagetype: 'Team',
name: teamName,
fieldname: { is_developer: 1 }
},
{
headers: get_session_api_headers(),
withCredentials: true
}
)
// set_value API 返回更新后的 Team 对象
const result = response.data?.message || response.data
return { success: true, data: result, message: '成为开发者成功' }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '成为开发者失败'
}
}
}
// 禁用账户
export const disableAccount = async (totpCode?: string): Promise<{ success: boolean; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.account.disable_account`,
totpCode ? { totp_code: totpCode } : {},
{
headers: get_session_api_headers(),
withCredentials: true
}
)
return { success: true, message: response.data?.message || '账户已禁用' }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '禁用账户失败'
}
}
}
// 启用账户
export const enableAccount = async (): Promise<{ success: boolean; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.account.enable_account`,
{},
{
headers: get_session_api_headers(),
withCredentials: true
}
)
return { success: true, message: response.data?.message || '账户已启用' }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '启用账户失败'
}
}
}
// 更新密码
export const updatePassword = async (params: {
old_password: string
new_password: string
confirm_password: string
logout_all_sessions?: number
}): Promise<{ success: boolean; message?: string; redirectUrl?: string }> => {
try {
const response = await axios.post(
`/api/action/jingrow.core.pagetype.user.user.update_password`,
{
old_password: params.old_password,
new_password: params.new_password,
confirm_password: params.confirm_password,
logout_all_sessions: params.logout_all_sessions || 1
},
{
headers: get_session_api_headers(),
withCredentials: true
}
)
const result = response.data?.message || response.data
return {
success: true,
message: '密码更新成功',
redirectUrl: typeof result === 'string' ? result : undefined
}
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '更新密码失败'
}
}
}
// 测试密码强度
export const testPasswordStrength = async (params: {
old_password: string
new_password: string
}): Promise<{ success: boolean; data?: { score: number; feedback: any }; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jingrow.core.pagetype.user.user.test_password_strength`,
{
old_password: params.old_password,
new_password: params.new_password
},
{
headers: get_session_api_headers(),
withCredentials: true
}
)
const result = response.data?.message || response.data
return { success: true, data: result }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '测试密码强度失败'
}
}
}
// 验证合作伙伴代码
export const validatePartnerCode = async (code: string): Promise<{ success: boolean; isValid: boolean; partnerName?: string; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.partner.validate_partner_code`,
{ code },
{
headers: get_session_api_headers(),
withCredentials: true
}
)
const result = response.data?.message || response.data
if (Array.isArray(result) && result.length >= 2) {
return {
success: true,
isValid: result[0] === true,
partnerName: result[1] || undefined
}
}
return { success: true, isValid: false }
} catch (error: any) {
return {
success: false,
isValid: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '验证合作伙伴代码失败'
}
}
}
// 添加合作伙伴代码
export const addPartnerCode = async (referralCode: string): Promise<{ success: boolean; message?: string; isAlreadySent?: boolean }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.partner.add_partner`,
{ referral_code: referralCode },
{
headers: get_session_api_headers(),
withCredentials: true
}
)
const result = response.data?.message || response.data
if (result === 'Request already sent') {
return { success: true, message: '请求已发送', isAlreadySent: true }
}
return { success: true, message: '请求已发送' }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '添加合作伙伴代码失败'
}
}
}
// 移除合作伙伴
export const removePartner = async (): Promise<{ success: boolean; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.partner.remove_partner`,
{},
{
headers: get_session_api_headers(),
withCredentials: true
}
)
return { success: true, message: response.data?.message || '合作伙伴已移除' }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '移除合作伙伴失败'
}
}
}
// 获取合作伙伴名称
export const getPartnerName = async (partnerEmail: string): Promise<{ success: boolean; data?: string; message?: string }> => {
try {
const response = await axios.get(
`/api/action/jcloud.api.partner.get_partner_name`,
{
params: { partner_email: partnerEmail },
headers: get_session_api_headers(),
withCredentials: true
}
)
const result = response.data?.message || response.data
return { success: true, data: result }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '获取合作伙伴名称失败'
}
}
}
// 获取 2FA QR 码 URL
export const get2FAQRCodeUrl = async (): Promise<{ success: boolean; data?: string; message?: string }> => {
try {
const response = await axios.get(
`/api/action/jcloud.api.account.get_2fa_qr_code_url`,
{
headers: get_session_api_headers(),
withCredentials: true
}
)
const result = response.data?.message || response.data
return { success: true, data: result }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '获取 2FA QR 码失败'
}
}
}
// 启用 2FA
export const enable2FA = async (totpCode: string): Promise<{ success: boolean; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.account.enable_2fa`,
{ totp_code: totpCode },
{
headers: get_session_api_headers(),
withCredentials: true
}
)
return { success: true, message: response.data?.message || '双因素认证已启用' }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '启用双因素认证失败'
}
}
}
// 禁用 2FA
export const disable2FA = async (totpCode: string): Promise<{ success: boolean; message?: string }> => {
try {
const response = await axios.post(
`/api/action/jcloud.api.account.disable_2fa`,
{ totp_code: totpCode },
{
headers: get_session_api_headers(),
withCredentials: true
}
)
return { success: true, message: response.data?.message || '双因素认证已禁用' }
} catch (error: any) {
return {
success: false,
message: error.response?.data?.detail || error.response?.data?.message || error.message || '禁用双因素认证失败'
}
}
}

View File

@ -29,6 +29,7 @@
import { ref } from 'vue'
import { NInput, NButton, NIcon, useMessage } from 'naive-ui'
import { Icon } from '@iconify/vue'
import { t } from '../i18n'
interface Props {
textContent: string
@ -50,12 +51,12 @@ const handleCopy = async () => {
try {
await navigator.clipboard.writeText(props.textContent)
copied.value = true
message.success('已复制到剪贴板')
message.success(t('Copied to clipboard'))
setTimeout(() => {
copied.value = false
}, 2000)
} catch (error) {
message.error('复制失败')
message.error(t('Copy failed'))
} finally {
copying.value = false
}

File diff suppressed because it is too large Load Diff