feat: 国际化处理
This commit is contained in:
@@ -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<PaginationState>({
|
||||
pageIndex: 0,
|
||||
@@ -101,12 +103,14 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => {
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent className='flex flex-col sm:grid sm:max-w-[600px]'>
|
||||
<DialogHeader>
|
||||
<DialogTitle className={'text-left text-2xl sm:text-4xl'}>网站公告</DialogTitle>
|
||||
<DialogTitle className={'text-left text-2xl sm:text-4xl'}>
|
||||
{t('announcementTitle')}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className='space-y-4'>
|
||||
{isLoading ? (
|
||||
<div className='py-8 text-center'>加载中...</div>
|
||||
<div className='py-8 text-center'>{t('loading')}</div>
|
||||
) : (
|
||||
<>
|
||||
{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'
|
||||
>
|
||||
<p className='line-clamp-2 flex-1 text-[10px] text-[#225BA9] sm:text-sm'>
|
||||
{item.pinned && '【置顶公告】'}{' '}
|
||||
{item.pinned && t('pinnedAnnouncement')}{' '}
|
||||
<span className={`${item.pinned ? 'text-white' : 'text-[#4D4D4D]'}`}>
|
||||
{item.content}
|
||||
</span>
|
||||
@@ -126,7 +130,7 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => {
|
||||
className='cursor-pointer text-xs text-[#225BA9] sm:text-sm'
|
||||
onClick={() => handleOpenPopup(item)}
|
||||
>
|
||||
查看详情
|
||||
{t('viewDetails')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -139,9 +143,9 @@ export const AnnouncementDialog = ({ ref }: DialogProps) => {
|
||||
<Pagination
|
||||
table={table}
|
||||
text={{
|
||||
textRowsPerPage: '每页显示',
|
||||
textRowsPerPage: t('rowsPerPage'),
|
||||
textPageOf: (pageIndex, pageCount) =>
|
||||
`第 ${pageIndex} 页,共 ${pageCount} 页`,
|
||||
t('pageOf', { pageIndex: pageIndex, pageCount: pageCount }),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -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<PopupRef>(null);
|
||||
@@ -140,19 +142,23 @@ export default function Content() {
|
||||
{/* 账户概况 Card */}
|
||||
<Card className='rounded-[20px] border border-[#D9D9D9] p-6 shadow-[0px_0px_52.6px_1px_rgba(15,44,83,0.05)]'>
|
||||
<div className='mb-1 sm:mb-4'>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>账户概况</h3>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>
|
||||
{t('accountOverview')}
|
||||
</h3>
|
||||
<p className='mt-1 text-xs text-[#666666] sm:text-sm'>
|
||||
{user?.auth_methods?.[0]?.auth_identifier}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='mb-3 sm:mb-6'>
|
||||
<span className='text-2xl font-medium text-[#091B33] sm:text-3xl'>年度套餐用户</span>
|
||||
<span className='text-2xl font-medium text-[#091B33] sm:text-3xl'>
|
||||
{t('annualPlanUser')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] px-4 py-[10px]'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<span className='text-sm font-light text-[#666666]'>账户余额</span>
|
||||
<span className='text-sm font-light text-[#666666]'>{t('accountBalance')}</span>
|
||||
<Recharge
|
||||
className={
|
||||
'border-0 bg-transparent p-0 text-sm font-normal text-[#225BA9] shadow-none outline-0 hover:bg-transparent'
|
||||
@@ -170,21 +176,22 @@ export default function Content() {
|
||||
<div className='mb-4'>
|
||||
<h3 className='flex items-center justify-between text-[#666666]'>
|
||||
<div className={'flex items-center justify-between'}>
|
||||
<span className={'text-base font-medium sm:text-xl'}>套餐状态</span>
|
||||
<span className={'text-base font-medium sm:text-xl'}>{t('planStatus')}</span>
|
||||
<span className={'ml-2.5 rounded-full bg-[#A8D4ED] px-2 text-[8px] text-white'}>
|
||||
生效中
|
||||
{t('inEffect')}
|
||||
</span>
|
||||
</div>
|
||||
<ResetTraffic
|
||||
className={
|
||||
'border-0 bg-transparent p-0 text-sm font-normal text-[#225BA9] shadow-none outline-0 hover:bg-transparent'
|
||||
}
|
||||
id={userSubscribe?.[0]?.id}
|
||||
id={userSubscribe?.[0]?.id || 0}
|
||||
replacement={userSubscribe?.[0]?.subscribe.replacement}
|
||||
/>
|
||||
</h3>
|
||||
<div className='mb-2 text-sm text-[#666666] sm:mb-[22px] sm:mt-1'>
|
||||
套餐到期时间:{formatDate(userSubscribe?.[0]?.expire_time, false)}
|
||||
{t('planExpirationTime')}
|
||||
{formatDate(userSubscribe?.[0]?.expire_time, false)}
|
||||
</div>
|
||||
<div className='mb-3 sm:mb-6'>
|
||||
<span className='text-2xl font-medium text-[#091B33] sm:text-3xl'>
|
||||
@@ -195,7 +202,7 @@ export default function Content() {
|
||||
|
||||
<div className='mb-4 flex items-center justify-between'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<span className='text-xs sm:text-sm'>可用设备</span>
|
||||
<span className='text-xs sm:text-sm'>{t('availableDevices')}</span>
|
||||
<div className='flex gap-2'>
|
||||
<div className='h-4 w-4 rounded-full bg-[#225BA9]'></div>
|
||||
<div className='h-4 w-4 rounded-full bg-[#D9D9D9]'></div>
|
||||
@@ -206,13 +213,14 @@ export default function Content() {
|
||||
</div>
|
||||
</div>
|
||||
<span className='text-xs sm:text-sm'>
|
||||
在线:uu/{userSubscribe?.[0]?.subscribe.device_limit}
|
||||
{t('online')}
|
||||
{userSubscribe?.[0]?.subscribe.device_limit}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div className='mb-1 flex items-center justify-between'>
|
||||
<span className='text-xs sm:text-sm'>
|
||||
已使用流量/总流量:
|
||||
{t('usedTrafficTotalTraffic')}
|
||||
<Display
|
||||
type='traffic'
|
||||
value={userSubscribe?.[0]?.upload + userSubscribe?.[0]?.download}
|
||||
@@ -226,20 +234,21 @@ export default function Content() {
|
||||
/>
|
||||
</span>
|
||||
<span className='text-xs sm:text-sm'>
|
||||
剩余:
|
||||
{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,
|
||||
)}
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
<div className='flex h-5 w-full items-center rounded-[20px] bg-[#EAEAEA] p-0.5'>
|
||||
<div
|
||||
className='h-full rounded-[20px] bg-[#225BA9]'
|
||||
className={'h-full rounded-[20px] bg-[#225BA9]'}
|
||||
style={{
|
||||
width: `${((userSubscribe?.[0]?.upload + userSubscribe?.[0]?.download) / userSubscribe?.[0]?.traffic).toFixed(0)}%`,
|
||||
width: `${Math.round((((userSubscribe?.[0]?.upload || 0) + (userSubscribe?.[0]?.download || 0)) / (userSubscribe?.[0]?.traffic || 1)) * 100)}%`,
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
@@ -251,13 +260,15 @@ export default function Content() {
|
||||
className={'absolute bottom-0 left-0 right-0 h-[60px] bg-white/30 backdrop-blur-[1px]'}
|
||||
></div>
|
||||
<div className='mb-3 flex items-center justify-between sm:mb-4'>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>网站公告</h3>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>
|
||||
{t('siteAnnouncements')}
|
||||
</h3>
|
||||
{announcementData?.length ? (
|
||||
<Button
|
||||
className='border-0 bg-transparent p-0 text-sm font-normal text-[#225BA9] shadow-none outline-0 hover:bg-transparent'
|
||||
onClick={() => dialogRef.current.open()}
|
||||
onClick={() => dialogRef.current?.open()}
|
||||
>
|
||||
更多
|
||||
{t('more')}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
@@ -268,7 +279,7 @@ export default function Content() {
|
||||
return (
|
||||
<div className='flex items-center rounded-[20px] bg-[#B5C9E2] px-4 py-2 sm:p-4'>
|
||||
<p className='line-clamp-2 flex-1 text-[10px] text-[#225BA9] sm:text-sm'>
|
||||
{item.pinned && '【置顶公告】'}{' '}
|
||||
{item.pinned && t('pinnedAnnouncement')}{' '}
|
||||
<span className={`${item.pinned ? 'text-white' : 'text-[#4D4D4D]'}`}>
|
||||
{item.content}
|
||||
</span>
|
||||
@@ -276,9 +287,9 @@ export default function Content() {
|
||||
<div className='ml-2 w-[65px] text-right'>
|
||||
<span
|
||||
className='cursor-pointer text-xs text-[#225BA9] sm:text-sm'
|
||||
onClick={() => popupRef.current.open(item)}
|
||||
onClick={() => popupRef.current?.open(item)}
|
||||
>
|
||||
查看详情
|
||||
{t('viewDetails')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -292,26 +303,30 @@ export default function Content() {
|
||||
{/* 我的订阅 Card */}
|
||||
<Card className='rounded-[20px] border border-[#D9D9D9] p-6 shadow-[0px_0px_52.6px_1px_rgba(15,44,83,0.05)]'>
|
||||
<div className='flex items-center justify-between sm:mb-4'>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>我的订阅</h3>
|
||||
<h3 className='text-base font-medium text-[#666666] sm:text-xl'>
|
||||
{t('mySubscription')}
|
||||
</h3>
|
||||
<Link
|
||||
href={'/document'}
|
||||
className='border-0 bg-transparent p-0 text-sm font-semibold text-[#225BA9] shadow-none outline-0 hover:bg-transparent sm:font-normal'
|
||||
>
|
||||
新手教程
|
||||
{t('beginnerTutorial')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{userSubscribe?.[0] && data.protocol ? (
|
||||
<div className='space-y-2 sm:space-y-4'>
|
||||
<p className='text-xs font-light text-[#666666] sm:text-sm sm:font-normal'>
|
||||
复制订阅链接或点击二维码按钮扫码
|
||||
{t('copySubscriptionLinkOrScanQrCode')}
|
||||
</p>
|
||||
|
||||
{/* 统计信息 */}
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] p-4'>
|
||||
<div className='grid grid-cols-3 gap-4 text-center'>
|
||||
<div>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-xs'>总流量</p>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-xs'>
|
||||
{t('totalTraffic')}
|
||||
</p>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-lg'>
|
||||
<Display
|
||||
type='traffic'
|
||||
@@ -430,7 +445,9 @@ export default function Content() {
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className='w-auto rounded-xl p-4' align='end'>
|
||||
<div className='flex flex-col items-center gap-2'>
|
||||
<p className='text-muted-foreground text-center text-xs'>扫描码订阅</p>
|
||||
<p className='text-muted-foreground text-center text-xs'>
|
||||
{t('scanCodeToSubscribe')}
|
||||
</p>
|
||||
<QRCodeCanvas
|
||||
value={userSubscribeProtocolCurrent}
|
||||
size={120}
|
||||
@@ -466,7 +483,7 @@ export default function Content() {
|
||||
<AlertDialogAction
|
||||
onClick={async () => {
|
||||
await resetUserSubscribeToken({
|
||||
user_subscribe_id: userSubscribe?.[0]?.id,
|
||||
user_subscribe_id: userSubscribe?.[0]?.id || 0,
|
||||
});
|
||||
await refetch();
|
||||
toast.success(t('resetSuccess'));
|
||||
|
||||
Reference in New Issue
Block a user