From 01ac12c171f8b1b7bd5ce3addfdacadf8c08e83b Mon Sep 17 00:00:00 2001 From: speakeloudest Date: Sun, 10 Aug 2025 03:07:37 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9B=BD=E9=99=85=E5=8C=96=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 7 +- .../components/Announcement/Dialog.tsx | 16 ++-- .../(content)/(user)/dashboard/content.tsx | 79 +++++++++++-------- .../(main)/(content)/(user)/document/page.tsx | 6 +- .../app/(main)/(content)/(user)/layout.tsx | 3 +- .../order/components/OrderDetailDialog.tsx | 12 +-- .../(main)/(content)/(user)/order/page.tsx | 2 +- .../(user)/profile/change-password.tsx | 6 +- .../(user)/profile/notify-settings.tsx | 6 +- .../(user)/profile/third-party-accounts.tsx | 6 +- .../(content)/(user)/subscribe/page.tsx | 8 +- .../(main)/(content)/(user)/wallet/page.tsx | 10 ++- .../affiliate/components/AffiliateDialog.tsx | 4 +- apps/user/components/affiliate/index.tsx | 59 +++++++------- apps/user/components/subscribe/purchase.tsx | 14 ++-- apps/user/components/subscribe/recharge.tsx | 2 +- apps/user/components/subscribe/renewal.tsx | 2 +- .../{eslint.config.js => eslint.config.mjs} | 0 apps/user/locales/en-US/affiliate.json | 17 +++- apps/user/locales/en-US/dashboard.json | 25 +++++- apps/user/locales/en-US/document.json | 4 +- apps/user/locales/en-US/order.json | 5 +- apps/user/locales/en-US/profile.json | 8 +- apps/user/locales/en-US/subscribe.json | 11 ++- apps/user/locales/en-US/wallet.json | 3 + apps/user/locales/zh-CN/affiliate.json | 17 +++- apps/user/locales/zh-CN/dashboard.json | 25 +++++- apps/user/locales/zh-CN/document.json | 4 +- apps/user/locales/zh-CN/order.json | 5 +- apps/user/locales/zh-CN/profile.json | 8 +- apps/user/locales/zh-CN/subscribe.json | 11 ++- apps/user/locales/zh-CN/wallet.json | 3 + apps/user/next.config.ts | 3 + 33 files changed, 268 insertions(+), 123 deletions(-) rename apps/user/{eslint.config.js => eslint.config.mjs} (100%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 353034a..33f54fb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ { + "chat.editor.fontSize": 16, + "debug.console.fontSize": 14, + "editor.fontSize": 16, "eslint.workingDirectories": [ { "mode": "auto" @@ -11,5 +14,7 @@ "*.jsx": "${capture}.js", "*.tsx": "${capture}.ts", "README.md": "*.md, LICENSE" - } + }, + "scm.inputFontSize": 13, + "terminal.integrated.fontSize": 12 } diff --git a/apps/user/app/(main)/(content)/(user)/dashboard/components/Announcement/Dialog.tsx b/apps/user/app/(main)/(content)/(user)/dashboard/components/Announcement/Dialog.tsx index 31311d6..77697c6 100644 --- a/apps/user/app/(main)/(content)/(user)/dashboard/components/Announcement/Dialog.tsx +++ b/apps/user/app/(main)/(content)/(user)/dashboard/components/Announcement/Dialog.tsx @@ -17,6 +17,7 @@ import { DialogTitle, } from '@workspace/airo-ui/components/dialog'; import { Pagination } from '@workspace/airo-ui/custom-components/pro-table/pagination'; +import { useTranslations } from 'next-intl'; import { useImperativeHandle, useRef, useState } from 'react'; import { Popup, PopupData, PopupRef } from './Popup'; @@ -37,6 +38,7 @@ interface DialogProps { } export const AnnouncementDialog = ({ ref }: DialogProps) => { + const t = useTranslations('dashboard'); const [open, setOpen] = useState(false); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -101,12 +103,14 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => { - 网站公告 + + {t('announcementTitle')} +
{isLoading ? ( -
加载中...
+
{t('loading')}
) : ( <> {announcementData?.list?.map((item: AnnouncementItem) => { @@ -116,7 +120,7 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => { className='flex items-center rounded-[20px] bg-[#B5C9E2] px-4 py-2 sm:p-4' >

- {item.pinned && '【置顶公告】'}{' '} + {item.pinned && t('pinnedAnnouncement')}{' '} {item.content} @@ -126,7 +130,7 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => { className='cursor-pointer text-xs text-[#225BA9] sm:text-sm' onClick={() => handleOpenPopup(item)} > - 查看详情 + {t('viewDetails')}

@@ -139,9 +143,9 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => { - `第 ${pageIndex} 页,共 ${pageCount} 页`, + t('pageOf', { pageIndex: pageIndex, pageCount: pageCount }), }} /> diff --git a/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx b/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx index 95f453d..c3da925 100644 --- a/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx +++ b/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx @@ -111,7 +111,9 @@ export default function Content() { if (data && userSubscribe?.length > 0 && !userSubscribeProtocol.length) { const list = getUserSubscribe(userSubscribe[0]?.token, data.protocol); setUserSubscribeProtocol(list); - setUserSubscribeProtocolCurrent(list[0]); + if (list.length > 0) { + setUserSubscribeProtocolCurrent(list[0]); + } } }, [data, userSubscribe, userSubscribeProtocol.length]); @@ -129,7 +131,7 @@ export default function Content() { const currentIndex = userSubscribeProtocol.findIndex( (url) => url === userSubscribeProtocolCurrent, ); - return currentIndex !== -1 ? `${t('subscriptionUrl')}${currentIndex + 1}` : '地址1'; + return currentIndex !== -1 ? `${t('subscriptionUrl')}${currentIndex + 1}` : t('address1'); }; const popupRef = useRef(null); @@ -140,19 +142,23 @@ export default function Content() { {/* 账户概况 Card */}
-

账户概况

+

+ {t('accountOverview')} +

{user?.auth_methods?.[0]?.auth_identifier}

- 年度套餐用户 + + {t('annualPlanUser')} +
- 账户余额 + {t('accountBalance')}

- 套餐状态 + {t('planStatus')} - 生效中 + {t('inEffect')}

- 套餐到期时间:{formatDate(userSubscribe?.[0]?.expire_time, false)} + {t('planExpirationTime')} + {formatDate(userSubscribe?.[0]?.expire_time, false)}
@@ -195,7 +202,7 @@ export default function Content() {
- 可用设备 + {t('availableDevices')}
@@ -206,13 +213,14 @@ export default function Content() {
- 在线:uu/{userSubscribe?.[0]?.subscribe.device_limit} + {t('online')} + {userSubscribe?.[0]?.subscribe.device_limit}
- 已使用流量/总流量: + {t('usedTrafficTotalTraffic')} - 剩余: + {t('remaining')} {100 - - ( - (userSubscribe?.[0]?.upload + userSubscribe?.[0]?.download) / - userSubscribe?.[0]?.traffic - ).toFixed(0)} + Math.round( + (((userSubscribe?.[0]?.upload || 0) + (userSubscribe?.[0]?.download || 0)) / + (userSubscribe?.[0]?.traffic || 1)) * + 100, + )} %
@@ -251,13 +260,15 @@ export default function Content() { className={'absolute bottom-0 left-0 right-0 h-[60px] bg-white/30 backdrop-blur-[1px]'} >
-

网站公告

+

+ {t('siteAnnouncements')} +

{announcementData?.length ? ( ) : null}
@@ -268,7 +279,7 @@ export default function Content() { return (

- {item.pinned && '【置顶公告】'}{' '} + {item.pinned && t('pinnedAnnouncement')}{' '} {item.content} @@ -276,9 +287,9 @@ export default function Content() {

popupRef.current.open(item)} + onClick={() => popupRef.current?.open(item)} > - 查看详情 + {t('viewDetails')}
@@ -292,26 +303,30 @@ export default function Content() { {/* 我的订阅 Card */}
-

我的订阅

+

+ {t('mySubscription')} +

- 新手教程 + {t('beginnerTutorial')}
{userSubscribe?.[0] && data.protocol ? (

- 复制订阅链接或点击二维码按钮扫码 + {t('copySubscriptionLinkOrScanQrCode')}

{/* 统计信息 */}
-

总流量

+

+ {t('totalTraffic')} +

-

扫描码订阅

+

+ {t('scanCodeToSubscribe')} +

{ await resetUserSubscribeToken({ - user_subscribe_id: userSubscribe?.[0]?.id, + user_subscribe_id: userSubscribe?.[0]?.id || 0, }); await refetch(); toast.success(t('resetSuccess')); diff --git a/apps/user/app/(main)/(content)/(user)/document/page.tsx b/apps/user/app/(main)/(content)/(user)/document/page.tsx index b84df6a..a357df3 100644 --- a/apps/user/app/(main)/(content)/(user)/document/page.tsx +++ b/apps/user/app/(main)/(content)/(user)/document/page.tsx @@ -62,10 +62,8 @@ export default function Page() { {TutorialList && TutorialList?.length > 0 && (
-
新手教程
-
- 选择对应操作系统,查看对应软件配置教程 -
+
{t('tutorialTitle')}
+
{t('tutorialDescription')}
{TutorialList?.map((tutorial) => ( diff --git a/apps/user/app/(main)/(content)/(user)/layout.tsx b/apps/user/app/(main)/(content)/(user)/layout.tsx index de5c72d..903b85f 100644 --- a/apps/user/app/(main)/(content)/(user)/layout.tsx +++ b/apps/user/app/(main)/(content)/(user)/layout.tsx @@ -1,4 +1,5 @@ import Announcement from '@/components/announcement'; +import LanguageSwitch from '@/components/language-switch'; import { SidebarInset, SidebarProvider } from '@workspace/airo-ui/components/sidebar'; import { cookies } from 'next/headers'; import { Header } from './Header'; @@ -12,8 +13,8 @@ export default async function DashboardLayout({ children }: { children: React.Re +
- {' '}
{children}
diff --git a/apps/user/app/(main)/(content)/(user)/order/components/OrderDetailDialog.tsx b/apps/user/app/(main)/(content)/(user)/order/components/OrderDetailDialog.tsx index 0f4244d..6639b76 100644 --- a/apps/user/app/(main)/(content)/(user)/order/components/OrderDetailDialog.tsx +++ b/apps/user/app/(main)/(content)/(user)/order/components/OrderDetailDialog.tsx @@ -15,13 +15,13 @@ interface OrderDetailDialogProps { orderNo?: string; } -interface OrderDetailDialogRef { +export interface OrderDetailDialogRef { show: (orderNo: string) => void; hide: () => void; } const OrderDetailDialog = forwardRef((props, ref) => { - const t = useTranslations('subscribe'); + const t = useTranslations('order'); const { getUserInfo } = useGlobalStore(); const router = useRouter(); const [open, setOpen] = useState(false); @@ -65,17 +65,17 @@ const OrderDetailDialog = forwardRef
- 订单详情 + {t('orderDetail')}
-
订单号
+
{t('orderNo')}
{orderNo}
-
支付方式
-
钱包余额
+
{t('paymentMethod')}
+
{t('walletBalance')}
diff --git a/apps/user/app/(main)/(content)/(user)/order/page.tsx b/apps/user/app/(main)/(content)/(user)/order/page.tsx index d6120c5..4bd5fdd 100644 --- a/apps/user/app/(main)/(content)/(user)/order/page.tsx +++ b/apps/user/app/(main)/(content)/(user)/order/page.tsx @@ -45,7 +45,7 @@ export default function Page() { ref.current?.refresh(); }} > - 取消订单 + {t('cancelOrder')}
-
修改登录密码
+
{t('description')}
@@ -102,7 +102,7 @@ export default function ChangePassword() { 'h-full rounded-[50px] border-0 border-[#0F2C53] bg-[#0F2C53] px-[55px] py-[9px] text-xl font-bold text-white transition hover:bg-[#225BA9] hover:text-white' } > - 保存 + {t('save')}
diff --git a/apps/user/app/(main)/(content)/(user)/profile/notify-settings.tsx b/apps/user/app/(main)/(content)/(user)/profile/notify-settings.tsx index 71a08b7..9fc4a17 100644 --- a/apps/user/app/(main)/(content)/(user)/profile/notify-settings.tsx +++ b/apps/user/app/(main)/(content)/(user)/profile/notify-settings.tsx @@ -51,10 +51,10 @@ export default function NotifySettings() { 'h-[32px] w-[110px] rounded-[50px] border-0 border-[#0F2C53] bg-[#0F2C53] text-center text-base font-medium leading-[32px] text-white transition hover:bg-[#225BA9] hover:text-white sm:hidden' } > - 保存 + {t('notify.save')}
-
是否邮箱通知推送
+
{t('notify.description')}
- 保存 + {t('notify.save')}
diff --git a/apps/user/app/(main)/(content)/(user)/profile/third-party-accounts.tsx b/apps/user/app/(main)/(content)/(user)/profile/third-party-accounts.tsx index 9e2e4e1..e1e644d 100644 --- a/apps/user/app/(main)/(content)/(user)/profile/third-party-accounts.tsx +++ b/apps/user/app/(main)/(content)/(user)/profile/third-party-accounts.tsx @@ -245,13 +245,13 @@ export default function ThirdPartyAccounts() { 'h-[32px] w-[110px] rounded-full bg-[#D9D9D9] text-center font-medium leading-[32px] text-white sm:hidden' } > - 保存 + {t('save')}
{user?.auth_methods?.[0]?.auth_identifier}
-
Email
+
{t('emailLabel')}
- 保存 + {t('save')}
diff --git a/apps/user/app/(main)/(content)/(user)/subscribe/page.tsx b/apps/user/app/(main)/(content)/(user)/subscribe/page.tsx index 69fb92e..585d580 100644 --- a/apps/user/app/(main)/(content)/(user)/subscribe/page.tsx +++ b/apps/user/app/(main)/(content)/(user)/subscribe/page.tsx @@ -76,14 +76,14 @@ export default function Page() { 'hidden text-4xl font-bold text-[#0F2C53] sm:block md:mb-4 md:text-center md:text-5xl' } > - 选择套餐 + {t('title')}
- 选择最适合您的服务套餐 + {t('description')}
- 年付套餐 + {t('yearlyPlan')} - 月付套餐 + {t('monthlyPlan')} diff --git a/apps/user/app/(main)/(content)/(user)/wallet/page.tsx b/apps/user/app/(main)/(content)/(user)/wallet/page.tsx index 2fe6809..f201474 100644 --- a/apps/user/app/(main)/(content)/(user)/wallet/page.tsx +++ b/apps/user/app/(main)/(content)/(user)/wallet/page.tsx @@ -38,7 +38,7 @@ export default function Page() {
-

总资产

+

{t('totalAssets')}

@@ -47,7 +47,9 @@ export default function Page() {
-

账户余额

+

+ {t('accountBalance')} +

@@ -70,9 +72,9 @@ export default function Page() {

- 返佣邀请码 + {t('referralCode')} - 返佣详情 + {t('referralDetails')}

diff --git a/apps/user/components/affiliate/components/AffiliateDialog.tsx b/apps/user/components/affiliate/components/AffiliateDialog.tsx index 8915e49..159c919 100644 --- a/apps/user/components/affiliate/components/AffiliateDialog.tsx +++ b/apps/user/components/affiliate/components/AffiliateDialog.tsx @@ -57,11 +57,11 @@ export const AffiliateDialog = ({ ref }: AffiliateDialogProps) => { return (

-
用户识别代码
+
{t('userIdentifier')}
{invite.identifier}
-
时间
+
{t('time')}
{formatDate(invite.registered_at)}
diff --git a/apps/user/components/affiliate/index.tsx b/apps/user/components/affiliate/index.tsx index db8d2d7..af52e42 100644 --- a/apps/user/components/affiliate/index.tsx +++ b/apps/user/components/affiliate/index.tsx @@ -52,23 +52,23 @@ export default function Affiliate() {
{t('totalCommission')}
-
- 佣金金额,邀请成功后自动转入钱包余额 -
+
{t('commissionInfo')}
- 历史推荐用户:7 + {t('historicalRecommendedUsers')}
-

佣金总额

+

+ {t('totalCommission')} +

- 返佣邀请码 + {t('commissionInviteCode')} { @@ -111,12 +111,12 @@ export default function Affiliate() {

-

邀请记录

+

{t('inviteRecords')}

dialogRef.current.open()} + onClick={() => dialogRef.current?.open()} > - 更多 + {t('more')}
@@ -132,11 +132,11 @@ export default function Affiliate() { return (
-
用户识别代码
+
{t('userIdentifier')}
{invite.identifier}
-
时间
+
{t('time')}
{formatDate(invite.registered_at)}
@@ -152,15 +152,16 @@ export default function Affiliate() {
-

佣金计算

+

+ {t('commissionCalculation')} +

- 在下方填入对应邀请用户数量,即可计算不同比例返佣金额 *该表以Pro - Plan计算,其它套餐比例不变,以实际金额计算为准 + {t('commissionCalculationInfo')}
{(() => { - // 假设以 Pro 计划计算:$60/月,$576/年 + // Pro plan: $60/month, $576/year const MONTHLY_PRICE = 60; const YEARLY_PRICE = 576; @@ -174,20 +175,20 @@ export default function Affiliate() { return (
- {/* 计算面板容器 */} + {/* Calculator panel container */}
- {/* 左:行表头(月付套餐 / 年付套餐) */} + {/* Left: row headers (Monthly Plan / Yearly Plan) */}
- 月付套餐 + {t('monthlyPackage')}
- 年付套餐 + {t('annualPackage')}
- {/* 中:首充用户(双层圆角 + 三行) */} + {/* Middle: First-time top-up users (double rounded corners + three rows) */}
-
+
- 首充用户 + {t('firstTimeTopUpUser')}
@@ -231,14 +232,14 @@ export default function Affiliate() {
- {/* 蓝色投影块 */} + {/* Blue shadow block */}
- {/* 右:再次充值用户(灰卡 + 三行) */} + {/* Right: Repeat top-up users (gray card + three rows) */}
- 再次充值用户 + {t('repeatTopUpUser')}
@@ -250,7 +251,7 @@ export default function Affiliate() { {' '} - / 月 + {t('perMonth')}
@@ -263,12 +264,12 @@ export default function Affiliate() { {' '} - / 年 + {t('perYear')}
- {/* 用户数调节 */} + {/* User count adjustment */}