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:
parent
911ae5e53b
commit
79b92e7aae
@ -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...": "正在禁用双因素认证..."
|
||||
}
|
||||
|
||||
@ -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 || '禁用双因素认证失败'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user