✨ feat: add dark mode detection and styling enhancements to PersonalSetting and TopUp components
This commit is contained in:
@@ -104,6 +104,33 @@ const PersonalSetting = () => {
|
||||
});
|
||||
const [modelsLoading, setModelsLoading] = useState(true);
|
||||
const [showWebhookDocs, setShowWebhookDocs] = useState(true);
|
||||
const [isDarkMode, setIsDarkMode] = useState(false);
|
||||
|
||||
// 检测暗色模式
|
||||
useEffect(() => {
|
||||
const checkDarkMode = () => {
|
||||
const isDark = document.documentElement.classList.contains('dark') ||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
setIsDarkMode(isDark);
|
||||
};
|
||||
|
||||
checkDarkMode();
|
||||
|
||||
// 监听主题变化
|
||||
const observer = new MutationObserver(checkDarkMode);
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class']
|
||||
});
|
||||
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
mediaQuery.addListener(checkDarkMode);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
mediaQuery.removeListener(checkDarkMode);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
let status = localStorage.getItem('status');
|
||||
@@ -384,107 +411,81 @@ const PersonalSetting = () => {
|
||||
<Card className="!rounded-2xl shadow-lg border-0">
|
||||
{/* 顶部用户信息区域 */}
|
||||
<Card
|
||||
className="!rounded-2xl !border-0 !shadow-2xl overflow-hidden"
|
||||
className="!rounded-2xl !border-0 !shadow-lg overflow-hidden"
|
||||
style={{
|
||||
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 25%, #a855f7 50%, #c084fc 75%, #d8b4fe 100%)',
|
||||
background: isDarkMode
|
||||
? 'linear-gradient(135deg, #1e293b 0%, #334155 50%, #475569 100%)'
|
||||
: 'linear-gradient(135deg, #f8fafc 0%, #e2e8f0 50%, #cbd5e1 100%)',
|
||||
position: 'relative'
|
||||
}}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
>
|
||||
{/* 装饰性背景元素 */}
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<div className="absolute -top-10 -right-10 w-40 h-40 bg-white opacity-5 rounded-full"></div>
|
||||
<div className="absolute -bottom-16 -left-16 w-48 h-48 bg-white opacity-3 rounded-full"></div>
|
||||
<div className="absolute top-1/2 right-1/4 w-24 h-24 bg-yellow-400 opacity-10 rounded-full"></div>
|
||||
<div className="absolute -top-10 -right-10 w-40 h-40 bg-slate-400 dark:bg-slate-500 opacity-5 rounded-full"></div>
|
||||
<div className="absolute -bottom-16 -left-16 w-48 h-48 bg-slate-300 dark:bg-slate-400 opacity-8 rounded-full"></div>
|
||||
<div className="absolute top-1/2 right-1/4 w-24 h-24 bg-slate-400 dark:bg-slate-500 opacity-6 rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<div className="relative p-4 sm:p-6 md:p-8" style={{ color: 'white' }}>
|
||||
<div className="relative p-4 sm:p-6 md:p-8 text-gray-600 dark:text-gray-300">
|
||||
<div className="flex justify-between items-start mb-4 sm:mb-6">
|
||||
<div className="flex items-center flex-1 min-w-0">
|
||||
<Avatar
|
||||
size='large'
|
||||
color={stringToColor(getUsername())}
|
||||
border={{ motion: true }}
|
||||
contentMotion={true}
|
||||
className="mr-3 sm:mr-4 shadow-lg flex-shrink-0"
|
||||
className="mr-3 sm:mr-4 shadow-md flex-shrink-0 bg-slate-500 dark:bg-slate-400"
|
||||
>
|
||||
{getAvatarText()}
|
||||
</Avatar>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-base sm:text-lg font-semibold truncate" style={{ color: 'white' }}>
|
||||
<div className="text-base sm:text-lg font-semibold truncate text-gray-800 dark:text-gray-100">
|
||||
{getUsername()}
|
||||
</div>
|
||||
<div className="mt-1 flex flex-wrap gap-1 sm:gap-2">
|
||||
{isRoot() ? (
|
||||
<Tag
|
||||
color='red'
|
||||
size='small'
|
||||
style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
||||
color: '#dc2626',
|
||||
fontWeight: '600'
|
||||
}}
|
||||
className="!rounded-full"
|
||||
className="!rounded-full bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300 border border-gray-200 dark:border-gray-600"
|
||||
style={{ fontWeight: '500' }}
|
||||
>
|
||||
{t('超级管理员')}
|
||||
</Tag>
|
||||
) : isAdmin() ? (
|
||||
<Tag
|
||||
color='orange'
|
||||
size='small'
|
||||
style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
||||
color: '#ea580c',
|
||||
fontWeight: '600'
|
||||
}}
|
||||
className="!rounded-full"
|
||||
className="!rounded-full bg-gray-50 dark:bg-gray-700 text-gray-600 dark:text-gray-300 border border-gray-200 dark:border-gray-600"
|
||||
style={{ fontWeight: '500' }}
|
||||
>
|
||||
{t('管理员')}
|
||||
</Tag>
|
||||
) : (
|
||||
<Tag
|
||||
color='blue'
|
||||
size='small'
|
||||
style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
||||
color: '#2563eb',
|
||||
fontWeight: '600'
|
||||
}}
|
||||
className="!rounded-full"
|
||||
className="!rounded-full bg-slate-50 dark:bg-slate-700 text-slate-600 dark:text-slate-300 border border-slate-200 dark:border-slate-600"
|
||||
style={{ fontWeight: '500' }}
|
||||
>
|
||||
{t('普通用户')}
|
||||
</Tag>
|
||||
)}
|
||||
<Tag
|
||||
color='green'
|
||||
size='small'
|
||||
className="!rounded-full"
|
||||
style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
||||
color: '#16a34a',
|
||||
fontWeight: '600'
|
||||
}}
|
||||
className="!rounded-full bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-300 border border-slate-200 dark:border-slate-600"
|
||||
style={{ fontWeight: '500' }}
|
||||
>
|
||||
ID: {userState?.user?.id}
|
||||
</Tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="w-10 h-10 sm:w-12 sm:h-12 rounded-lg flex items-center justify-center shadow-lg flex-shrink-0 ml-2"
|
||||
style={{
|
||||
background: `linear-gradient(135deg, ${stringToColor(getUsername())} 0%, #f59e0b 100%)`
|
||||
}}
|
||||
>
|
||||
<IconUser size="default" style={{ color: 'white' }} />
|
||||
<div className="w-10 h-10 sm:w-12 sm:h-12 rounded-lg flex items-center justify-center shadow-md flex-shrink-0 ml-2 bg-slate-400 dark:bg-slate-500">
|
||||
<IconUser size="default" className="text-white" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4 sm:mb-6">
|
||||
<div className="text-xs sm:text-sm mb-1 sm:mb-2" style={{ color: 'rgba(255, 255, 255, 0.7)' }}>
|
||||
<div className="text-xs sm:text-sm mb-1 sm:mb-2 text-gray-500 dark:text-gray-400">
|
||||
{t('当前余额')}
|
||||
</div>
|
||||
<div className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-wide" style={{ color: 'white' }}>
|
||||
<div className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-wide text-gray-900 dark:text-gray-100">
|
||||
{renderQuota(userState?.user?.quota)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -492,33 +493,33 @@ const PersonalSetting = () => {
|
||||
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-end">
|
||||
<div className="grid grid-cols-3 gap-2 sm:flex sm:space-x-6 lg:space-x-8 mb-3 sm:mb-0">
|
||||
<div className="text-center sm:text-left">
|
||||
<div className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.6)' }}>
|
||||
<div className="text-xs text-gray-400 dark:text-gray-500">
|
||||
{t('历史消耗')}
|
||||
</div>
|
||||
<div className="text-xs sm:text-sm font-medium truncate" style={{ color: 'white' }}>
|
||||
<div className="text-xs sm:text-sm font-medium truncate text-gray-600 dark:text-gray-300">
|
||||
{renderQuota(userState?.user?.used_quota)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center sm:text-left">
|
||||
<div className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.6)' }}>
|
||||
<div className="text-xs text-gray-400 dark:text-gray-500">
|
||||
{t('请求次数')}
|
||||
</div>
|
||||
<div className="text-xs sm:text-sm font-medium truncate" style={{ color: 'white' }}>
|
||||
<div className="text-xs sm:text-sm font-medium truncate text-gray-600 dark:text-gray-300">
|
||||
{userState.user?.request_count || 0}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center sm:text-left">
|
||||
<div className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.6)' }}>
|
||||
<div className="text-xs text-gray-400 dark:text-gray-500">
|
||||
{t('用户分组')}
|
||||
</div>
|
||||
<div className="text-xs sm:text-sm font-medium truncate" style={{ color: 'white' }}>
|
||||
<div className="text-xs sm:text-sm font-medium truncate text-gray-600 dark:text-gray-300">
|
||||
{userState?.user?.group || t('默认')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-yellow-400 via-orange-400 to-red-400" style={{ opacity: 0.6 }}></div>
|
||||
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-slate-300 via-slate-400 to-slate-500 dark:from-slate-600 dark:via-slate-500 dark:to-slate-400 opacity-40"></div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -537,10 +538,10 @@ const PersonalSetting = () => {
|
||||
>
|
||||
<div className="gap-6 py-4">
|
||||
{/* 可用模型部分 */}
|
||||
<div className="bg-gray-50 rounded-xl">
|
||||
<div className="bg-gray-50 dark:bg-gray-800 rounded-xl">
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="w-10 h-10 rounded-full bg-purple-50 flex items-center justify-center mr-3">
|
||||
<Settings size={20} className="text-purple-500" />
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3">
|
||||
<Settings size={20} className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Title heading={6} className="mb-0">{t('模型列表')}</Typography.Title>
|
||||
@@ -629,7 +630,7 @@ const PersonalSetting = () => {
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-lg p-3">
|
||||
<div className="bg-white dark:bg-gray-700 rounded-lg p-3">
|
||||
{(() => {
|
||||
// 根据当前选中的分类过滤模型
|
||||
const categories = getModelCategories(t);
|
||||
@@ -736,9 +737,9 @@ const PersonalSetting = () => {
|
||||
shadows='hover'
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center flex-1">
|
||||
<div className="w-10 h-10 rounded-full bg-red-50 flex items-center justify-center mr-3">
|
||||
<IconMail size="default" className="text-red-500" />
|
||||
<div className="flex items-center flex-1">
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3">
|
||||
<IconMail size="default" className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-medium text-gray-900">{t('邮箱')}</div>
|
||||
@@ -771,8 +772,8 @@ const PersonalSetting = () => {
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center flex-1">
|
||||
<div className="w-10 h-10 rounded-full bg-green-50 flex items-center justify-center mr-3">
|
||||
<SiWechat size={20} className="text-green-500" />
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3">
|
||||
<SiWechat size={20} className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-medium text-gray-900">{t('微信')}</div>
|
||||
@@ -808,8 +809,8 @@ const PersonalSetting = () => {
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center flex-1">
|
||||
<div className="w-10 h-10 rounded-full bg-gray-100 flex items-center justify-center mr-3">
|
||||
<IconGithubLogo size="default" className="text-gray-700" />
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3">
|
||||
<IconGithubLogo size="default" className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-medium text-gray-900">{t('GitHub')}</div>
|
||||
@@ -844,8 +845,8 @@ const PersonalSetting = () => {
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center flex-1">
|
||||
<div className="w-10 h-10 rounded-full bg-indigo-50 flex items-center justify-center mr-3">
|
||||
<IconShield size="default" className="text-indigo-500" />
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3">
|
||||
<IconShield size="default" className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-medium text-gray-900">{t('OIDC')}</div>
|
||||
@@ -883,8 +884,8 @@ const PersonalSetting = () => {
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center flex-1">
|
||||
<div className="w-10 h-10 rounded-full bg-blue-50 flex items-center justify-center mr-3">
|
||||
<SiTelegram size={20} className="text-blue-500" />
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3">
|
||||
<SiTelegram size={20} className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-medium text-gray-900">{t('Telegram')}</div>
|
||||
@@ -926,8 +927,8 @@ const PersonalSetting = () => {
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center flex-1">
|
||||
<div className="w-10 h-10 rounded-full bg-orange-50 flex items-center justify-center mr-3">
|
||||
<SiLinux size={20} className="text-orange-500" />
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3">
|
||||
<SiLinux size={20} className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-medium text-gray-900">{t('LinuxDO')}</div>
|
||||
@@ -978,8 +979,8 @@ const PersonalSetting = () => {
|
||||
>
|
||||
<div className="flex flex-col sm:flex-row items-start sm:justify-between gap-4">
|
||||
<div className="flex items-start w-full sm:w-auto">
|
||||
<div className="w-12 h-12 rounded-full bg-blue-50 flex items-center justify-center mr-4 flex-shrink-0">
|
||||
<IconKey size="large" className="text-blue-500" />
|
||||
<div className="w-12 h-12 rounded-full bg-slate-100 flex items-center justify-center mr-4 flex-shrink-0">
|
||||
<IconKey size="large" className="text-slate-600" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<Typography.Title heading={6} className="mb-1">
|
||||
@@ -1006,7 +1007,7 @@ const PersonalSetting = () => {
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={generateAccessToken}
|
||||
className="!rounded-lg !bg-blue-500 hover:!bg-blue-600 w-full sm:w-auto"
|
||||
className="!rounded-lg !bg-slate-600 hover:!bg-slate-700 w-full sm:w-auto"
|
||||
icon={<IconKey />}
|
||||
>
|
||||
{systemToken ? t('重新生成') : t('生成令牌')}
|
||||
@@ -1022,8 +1023,8 @@ const PersonalSetting = () => {
|
||||
>
|
||||
<div className="flex flex-col sm:flex-row items-start sm:justify-between gap-4">
|
||||
<div className="flex items-start w-full sm:w-auto">
|
||||
<div className="w-12 h-12 rounded-full bg-orange-50 flex items-center justify-center mr-4 flex-shrink-0">
|
||||
<IconLock size="large" className="text-orange-500" />
|
||||
<div className="w-12 h-12 rounded-full bg-slate-100 flex items-center justify-center mr-4 flex-shrink-0">
|
||||
<IconLock size="large" className="text-slate-600" />
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Title heading={6} className="mb-1">
|
||||
@@ -1038,7 +1039,7 @@ const PersonalSetting = () => {
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={() => setShowChangePasswordModal(true)}
|
||||
className="!rounded-lg !bg-orange-500 hover:!bg-orange-600 w-full sm:w-auto"
|
||||
className="!rounded-lg !bg-slate-600 hover:!bg-slate-700 w-full sm:w-auto"
|
||||
icon={<IconLock />}
|
||||
>
|
||||
{t('修改密码')}
|
||||
@@ -1054,11 +1055,11 @@ const PersonalSetting = () => {
|
||||
>
|
||||
<div className="flex flex-col sm:flex-row items-start sm:justify-between gap-4">
|
||||
<div className="flex items-start w-full sm:w-auto">
|
||||
<div className="w-12 h-12 rounded-full bg-red-50 flex items-center justify-center mr-4 flex-shrink-0">
|
||||
<IconDelete size="large" className="text-red-500" />
|
||||
<div className="w-12 h-12 rounded-full bg-slate-100 flex items-center justify-center mr-4 flex-shrink-0">
|
||||
<IconDelete size="large" className="text-slate-600" />
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Title heading={6} className="mb-1 text-red-600">
|
||||
<Typography.Title heading={6} className="mb-1 text-slate-700">
|
||||
{t('删除账户')}
|
||||
</Typography.Title>
|
||||
<Typography.Text type="tertiary" className="text-sm">
|
||||
@@ -1070,7 +1071,7 @@ const PersonalSetting = () => {
|
||||
type="danger"
|
||||
theme="solid"
|
||||
onClick={() => setShowAccountDeleteModal(true)}
|
||||
className="!rounded-lg w-full sm:w-auto"
|
||||
className="!rounded-lg w-full sm:w-auto !bg-slate-500 hover:!bg-slate-600"
|
||||
icon={<IconDelete />}
|
||||
>
|
||||
{t('删除账户')}
|
||||
@@ -1111,7 +1112,7 @@ const PersonalSetting = () => {
|
||||
>
|
||||
<Radio value='email' className="!p-4 !rounded-lg">
|
||||
<div className="flex items-center">
|
||||
<IconMail className="mr-2 text-blue-500" />
|
||||
<IconMail className="mr-2 text-slate-600" />
|
||||
<div>
|
||||
<div className="font-medium">{t('邮件通知')}</div>
|
||||
<div className="text-sm text-gray-500">{t('通过邮件接收通知')}</div>
|
||||
@@ -1120,7 +1121,7 @@ const PersonalSetting = () => {
|
||||
</Radio>
|
||||
<Radio value='webhook' className="!p-4 !rounded-lg">
|
||||
<div className="flex items-center">
|
||||
<Webhook size={16} className="mr-2 text-green-500" />
|
||||
<Webhook size={16} className="mr-2 text-slate-600" />
|
||||
<div>
|
||||
<div className="font-medium">{t('Webhook通知')}</div>
|
||||
<div className="text-sm text-gray-500">{t('通过HTTP请求接收通知')}</div>
|
||||
@@ -1167,11 +1168,11 @@ const PersonalSetting = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-yellow-50 rounded-xl">
|
||||
<div className="bg-slate-50 rounded-xl">
|
||||
<div className="flex items-center justify-between cursor-pointer" onClick={() => setShowWebhookDocs(!showWebhookDocs)}>
|
||||
<div className="flex items-center">
|
||||
<Globe size={16} className="mr-2 text-yellow-600" />
|
||||
<Typography.Text strong className="text-yellow-800">
|
||||
<Globe size={16} className="mr-2 text-slate-600" />
|
||||
<Typography.Text strong className="text-slate-700">
|
||||
{t('Webhook请求结构')}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
@@ -1254,11 +1255,11 @@ const PersonalSetting = () => {
|
||||
itemKey='price'
|
||||
>
|
||||
<div className="py-4">
|
||||
<div className="bg-white rounded-xl">
|
||||
<div className="flex items-start">
|
||||
<div className="w-10 h-10 rounded-full bg-orange-50 flex items-center justify-center mt-1">
|
||||
<Shield size={20} className="text-orange-500" />
|
||||
</div>
|
||||
<div className="bg-white rounded-xl">
|
||||
<div className="flex items-start">
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 flex items-center justify-center mt-1">
|
||||
<Shield size={20} className="text-slate-600" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
@@ -1292,7 +1293,7 @@ const PersonalSetting = () => {
|
||||
type='primary'
|
||||
onClick={saveNotificationSettings}
|
||||
size="large"
|
||||
className="!rounded-lg !bg-purple-500 hover:!bg-purple-600"
|
||||
className="!rounded-lg !bg-slate-600 hover:!bg-slate-700"
|
||||
icon={<IconSetting />}
|
||||
>
|
||||
{t('保存设置')}
|
||||
@@ -1408,7 +1409,7 @@ const PersonalSetting = () => {
|
||||
theme="solid"
|
||||
size='large'
|
||||
onClick={bindWeChat}
|
||||
className="!rounded-lg w-full !bg-green-500 hover:!bg-green-600"
|
||||
className="!rounded-lg w-full !bg-slate-600 hover:!bg-slate-700"
|
||||
icon={<SiWechat size={16} />}
|
||||
>
|
||||
{t('绑定')}
|
||||
|
||||
@@ -580,7 +580,7 @@ export function renderText(text, limit) {
|
||||
export function renderGroup(group) {
|
||||
if (group === '') {
|
||||
return (
|
||||
<Tag size='large' key='default' color='orange' shape='circle' prefixIcon={<Users size={14} />}>
|
||||
<Tag size='large' key='default' color='orange' shape='circle'>
|
||||
{i18next.t('用户分组')}
|
||||
</Tag>
|
||||
);
|
||||
@@ -603,7 +603,6 @@ export function renderGroup(group) {
|
||||
color={tagColors[group] || stringToColor(group)}
|
||||
key={group}
|
||||
shape='circle'
|
||||
prefixIcon={<Users size={14} />}
|
||||
onClick={async (event) => {
|
||||
event.stopPropagation();
|
||||
if (await copy(group)) {
|
||||
|
||||
@@ -55,6 +55,7 @@ const TopUp = () => {
|
||||
const [amountLoading, setAmountLoading] = useState(false);
|
||||
const [paymentLoading, setPaymentLoading] = useState(false);
|
||||
const [confirmLoading, setConfirmLoading] = useState(false);
|
||||
const [isDarkMode, setIsDarkMode] = useState(false);
|
||||
|
||||
// 邀请相关状态
|
||||
const [affLink, setAffLink] = useState('');
|
||||
@@ -256,6 +257,32 @@ const TopUp = () => {
|
||||
showSuccess(t('邀请链接已复制到剪切板'));
|
||||
};
|
||||
|
||||
// 检测暗色模式
|
||||
useEffect(() => {
|
||||
const checkDarkMode = () => {
|
||||
const isDark = document.documentElement.classList.contains('dark') ||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
setIsDarkMode(isDark);
|
||||
};
|
||||
|
||||
checkDarkMode();
|
||||
|
||||
// 监听主题变化
|
||||
const observer = new MutationObserver(checkDarkMode);
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class']
|
||||
});
|
||||
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
mediaQuery.addListener(checkDarkMode);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
mediaQuery.removeListener(checkDarkMode);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (userState?.user?.id) {
|
||||
setUserDataLoading(false);
|
||||
@@ -398,48 +425,45 @@ const TopUp = () => {
|
||||
<div className="w-full">
|
||||
<Card className="!rounded-2xl shadow-lg border-0">
|
||||
<Card
|
||||
className="!rounded-2xl !border-0 !shadow-2xl overflow-hidden"
|
||||
className="!rounded-2xl !border-0 !shadow-lg overflow-hidden"
|
||||
style={{
|
||||
background: 'linear-gradient(135deg, #1e3a8a 0%, #1e40af 25%, #2563eb 50%, #3b82f6 75%, #60a5fa 100%)',
|
||||
background: isDarkMode
|
||||
? 'linear-gradient(135deg, #1e293b 0%, #334155 50%, #475569 100%)'
|
||||
: 'linear-gradient(135deg, #f8fafc 0%, #e2e8f0 50%, #cbd5e1 100%)',
|
||||
position: 'relative'
|
||||
}}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
>
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<div className="absolute -top-10 -right-10 w-40 h-40 bg-white opacity-5 rounded-full"></div>
|
||||
<div className="absolute -bottom-16 -left-16 w-48 h-48 bg-white opacity-3 rounded-full"></div>
|
||||
<div className="absolute top-1/2 right-1/4 w-24 h-24 bg-yellow-400 opacity-10 rounded-full"></div>
|
||||
<div className="absolute -top-10 -right-10 w-40 h-40 bg-slate-400 opacity-5 rounded-full"></div>
|
||||
<div className="absolute -bottom-16 -left-16 w-48 h-48 bg-slate-300 opacity-8 rounded-full"></div>
|
||||
<div className="absolute top-1/2 right-1/4 w-24 h-24 bg-slate-400 opacity-6 rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<div className="relative p-4 sm:p-6 md:p-8" style={{ color: 'white' }}>
|
||||
<div className="relative p-4 sm:p-6 md:p-8 text-gray-600 dark:text-gray-300">
|
||||
<div className="flex justify-between items-start mb-4 sm:mb-6">
|
||||
<div className="flex-1 min-w-0">
|
||||
{userDataLoading ? (
|
||||
<Skeleton.Title style={{ width: '200px', height: '20px' }} />
|
||||
) : (
|
||||
<div className="text-base sm:text-lg font-semibold truncate" style={{ color: 'white' }}>
|
||||
<div className="text-base sm:text-lg font-semibold truncate text-gray-800 dark:text-gray-100">
|
||||
{t('尊敬的')} {getUsername()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="w-10 h-10 sm:w-12 sm:h-12 rounded-lg flex items-center justify-center shadow-lg flex-shrink-0 ml-2"
|
||||
style={{
|
||||
background: `linear-gradient(135deg, ${stringToColor(getUsername())} 0%, #f59e0b 100%)`
|
||||
}}
|
||||
>
|
||||
<IconCreditCard size="default" style={{ color: 'white' }} />
|
||||
<div className="w-10 h-10 sm:w-12 sm:h-12 rounded-lg flex items-center justify-center shadow-md flex-shrink-0 ml-2 bg-slate-400 dark:bg-slate-500">
|
||||
<IconCreditCard size="default" className="text-white" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4 sm:mb-6">
|
||||
<div className="text-xs sm:text-sm mb-1 sm:mb-2" style={{ color: 'rgba(255, 255, 255, 0.7)' }}>
|
||||
<div className="text-xs sm:text-sm mb-1 sm:mb-2 text-gray-500 dark:text-gray-400">
|
||||
{t('当前余额')}
|
||||
</div>
|
||||
{userDataLoading ? (
|
||||
<Skeleton.Title style={{ width: '180px', height: '32px' }} />
|
||||
) : (
|
||||
<div className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-wide" style={{ color: 'white' }}>
|
||||
<div className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-wide text-gray-900 dark:text-gray-100">
|
||||
{renderQuota(userState?.user?.quota || userQuota)}
|
||||
</div>
|
||||
)}
|
||||
@@ -448,37 +472,37 @@ const TopUp = () => {
|
||||
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-end">
|
||||
<div className="grid grid-cols-3 gap-2 sm:flex sm:space-x-6 lg:space-x-8 mb-3 sm:mb-0">
|
||||
<div className="text-center sm:text-left">
|
||||
<div className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.6)' }}>
|
||||
<div className="text-xs text-gray-400 dark:text-gray-500">
|
||||
{t('历史消耗')}
|
||||
</div>
|
||||
{userDataLoading ? (
|
||||
<Skeleton.Title style={{ width: '60px', height: '14px' }} />
|
||||
) : (
|
||||
<div className="text-xs sm:text-sm font-medium truncate" style={{ color: 'white' }}>
|
||||
<div className="text-xs sm:text-sm font-medium truncate text-gray-600 dark:text-gray-300">
|
||||
{renderQuota(userState?.user?.used_quota || 0)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-center sm:text-left">
|
||||
<div className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.6)' }}>
|
||||
<div className="text-xs text-gray-400 dark:text-gray-500">
|
||||
{t('用户分组')}
|
||||
</div>
|
||||
{userDataLoading ? (
|
||||
<Skeleton.Title style={{ width: '50px', height: '14px' }} />
|
||||
) : (
|
||||
<div className="text-xs sm:text-sm font-medium truncate" style={{ color: 'white' }}>
|
||||
<div className="text-xs sm:text-sm font-medium truncate text-gray-600 dark:text-gray-300">
|
||||
{userState?.user?.group || t('默认')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-center sm:text-left">
|
||||
<div className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.6)' }}>
|
||||
<div className="text-xs text-gray-400 dark:text-gray-500">
|
||||
{t('用户角色')}
|
||||
</div>
|
||||
{userDataLoading ? (
|
||||
<Skeleton.Title style={{ width: '60px', height: '14px' }} />
|
||||
) : (
|
||||
<div className="text-xs sm:text-sm font-medium truncate" style={{ color: 'white' }}>
|
||||
<div className="text-xs sm:text-sm font-medium truncate text-gray-600 dark:text-gray-300">
|
||||
{getUserRole()}
|
||||
</div>
|
||||
)}
|
||||
@@ -489,32 +513,187 @@ const TopUp = () => {
|
||||
{userDataLoading ? (
|
||||
<Skeleton.Title style={{ width: '50px', height: '24px' }} />
|
||||
) : (
|
||||
<div
|
||||
className="px-2 py-1 sm:px-3 rounded-md text-xs sm:text-sm font-medium inline-block"
|
||||
style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
color: 'white',
|
||||
backdropFilter: 'blur(10px)'
|
||||
}}
|
||||
>
|
||||
<div className="px-2 py-1 sm:px-3 rounded-md text-xs sm:text-sm font-medium inline-block bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-300 border border-slate-200 dark:border-slate-600">
|
||||
ID: {userState?.user?.id || '---'}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-yellow-400 via-orange-400 to-red-400" style={{ opacity: 0.6 }}></div>
|
||||
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-slate-300 via-slate-400 to-slate-500 dark:from-slate-600 dark:via-slate-500 dark:to-slate-400 opacity-40"></div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<div className="p-6">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* 邀请信息部分 */}
|
||||
<div>
|
||||
{/* 左侧:在线充值和兑换余额 */}
|
||||
<div className="lg:col-span-2 space-y-8">
|
||||
{/* 在线充值部分 */}
|
||||
<div>
|
||||
<div className="flex items-center mb-6">
|
||||
<div className="w-12 h-12 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-4">
|
||||
<IconPlus size="large" className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div>
|
||||
<Text className="text-xl font-semibold">{t('在线充值')}</Text>
|
||||
<div className="text-gray-500 text-sm">{t('支持多种支付方式')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<div className="flex justify-between mb-2">
|
||||
<Text strong>{t('充值数量')}</Text>
|
||||
{amountLoading ? (
|
||||
<Skeleton.Title style={{ width: '80px', height: '14px' }} />
|
||||
) : (
|
||||
<Text type="tertiary">{t('实付金额:') + ' ' + renderAmount()}</Text>
|
||||
)}
|
||||
</div>
|
||||
<InputNumber
|
||||
disabled={!enableOnlineTopUp}
|
||||
placeholder={
|
||||
t('充值数量,最低 ') + renderQuotaWithAmount(minTopUp)
|
||||
}
|
||||
value={topUpCount}
|
||||
min={minTopUp}
|
||||
max={999999999}
|
||||
step={1}
|
||||
precision={0}
|
||||
onChange={async (value) => {
|
||||
if (value && value >= 1) {
|
||||
setTopUpCount(value);
|
||||
await getAmount(value);
|
||||
}
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
const value = parseInt(e.target.value);
|
||||
if (!value || value < 1) {
|
||||
setTopUpCount(1);
|
||||
getAmount(1);
|
||||
}
|
||||
}}
|
||||
size="large"
|
||||
className="!rounded-lg w-full"
|
||||
prefix={<IconCreditCard />}
|
||||
formatter={(value) => value ? `${value}` : ''}
|
||||
parser={(value) => value ? parseInt(value.replace(/[^\d]/g, '')) : 0}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<Button
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={async () => {
|
||||
preTopUp('zfb');
|
||||
}}
|
||||
size="large"
|
||||
className="!rounded-lg !bg-slate-600 hover:!bg-slate-700 h-14"
|
||||
disabled={!enableOnlineTopUp}
|
||||
loading={paymentLoading}
|
||||
icon={<SiAlipay size={20} />}
|
||||
>
|
||||
<span className="ml-2">{t('支付宝')}</span>
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={async () => {
|
||||
preTopUp('wx');
|
||||
}}
|
||||
size="large"
|
||||
className="!rounded-lg !bg-slate-600 hover:!bg-slate-700 h-14"
|
||||
disabled={!enableOnlineTopUp}
|
||||
loading={paymentLoading}
|
||||
icon={<SiWechat size={20} />}
|
||||
>
|
||||
<span className="ml-2">{t('微信')}</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{!enableOnlineTopUp && (
|
||||
<Banner
|
||||
fullMode={false}
|
||||
type="warning"
|
||||
icon={null}
|
||||
closeIcon={null}
|
||||
className="!rounded-lg"
|
||||
title={
|
||||
<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>
|
||||
{t('在线充值功能未开启')}
|
||||
</div>
|
||||
}
|
||||
description={
|
||||
<div>
|
||||
{t('管理员未开启在线充值功能,请联系管理员开启或使用兑换码充值。')}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 兑换余额部分 */}
|
||||
<div>
|
||||
<div className="flex items-center mb-6">
|
||||
<div className="w-12 h-12 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-4">
|
||||
<IconGift size="large" className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div>
|
||||
<Text className="text-xl font-semibold">{t('兑换余额')}</Text>
|
||||
<div className="text-gray-500 text-sm">{t('使用兑换码充值余额')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Text strong className="block mb-2">{t('兑换码')}</Text>
|
||||
<Input
|
||||
placeholder={t('请输入兑换码')}
|
||||
value={redemptionCode}
|
||||
onChange={(value) => setRedemptionCode(value)}
|
||||
size="large"
|
||||
className="!rounded-lg"
|
||||
prefix={<IconGift />}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-3">
|
||||
{topUpLink && (
|
||||
<Button
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={openTopUpLink}
|
||||
size="large"
|
||||
className="!rounded-lg flex-1"
|
||||
icon={<IconLink />}
|
||||
>
|
||||
{t('获取兑换码')}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
type="warning"
|
||||
theme="solid"
|
||||
onClick={topUp}
|
||||
disabled={isSubmitting}
|
||||
loading={isSubmitting}
|
||||
size="large"
|
||||
className="!rounded-lg flex-1"
|
||||
>
|
||||
{isSubmitting ? t('兑换中...') : t('兑换')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 右侧:邀请信息部分 */}
|
||||
<div className="lg:col-span-1">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex items-center">
|
||||
<div className="w-12 h-12 rounded-full bg-orange-50 flex items-center justify-center mr-4">
|
||||
<IconLink size="large" className="text-orange-500" />
|
||||
<div className="w-12 h-12 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-4">
|
||||
<IconLink size="large" className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -524,7 +703,7 @@ const TopUp = () => {
|
||||
theme="solid"
|
||||
onClick={() => setOpenTransfer(true)}
|
||||
size="small"
|
||||
className="!rounded-lg !bg-blue-500 hover:!bg-blue-600"
|
||||
className="!rounded-lg !bg-slate-600 hover:!bg-slate-700"
|
||||
icon={<IconCreditCard />}
|
||||
>
|
||||
{t('划转')}
|
||||
@@ -536,7 +715,7 @@ const TopUp = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
||||
<div className="grid grid-cols-1 gap-3">
|
||||
<Card
|
||||
className="!rounded-2xl text-center"
|
||||
bodyStyle={{ padding: '16px' }}
|
||||
@@ -546,7 +725,6 @@ const TopUp = () => {
|
||||
<div className="text-gray-900 text-lg font-bold mt-1">
|
||||
{renderQuota(userState?.user?.aff_quota)}
|
||||
</div>
|
||||
|
||||
</Card>
|
||||
<Card
|
||||
className="!rounded-2xl text-center"
|
||||
@@ -583,162 +761,6 @@ const TopUp = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center mb-6">
|
||||
<div className="w-12 h-12 rounded-full bg-green-50 flex items-center justify-center mr-4">
|
||||
<IconGift size="large" className="text-green-500" />
|
||||
</div>
|
||||
<div>
|
||||
<Text className="text-xl font-semibold">{t('兑换余额')}</Text>
|
||||
<div className="text-gray-500 text-sm">{t('使用兑换码充值余额')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Text strong className="block mb-2">{t('兑换码')}</Text>
|
||||
<Input
|
||||
placeholder={t('请输入兑换码')}
|
||||
value={redemptionCode}
|
||||
onChange={(value) => setRedemptionCode(value)}
|
||||
size="large"
|
||||
className="!rounded-lg"
|
||||
prefix={<IconGift />}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-3">
|
||||
{topUpLink && (
|
||||
<Button
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={openTopUpLink}
|
||||
size="large"
|
||||
className="!rounded-lg flex-1"
|
||||
icon={<IconLink />}
|
||||
>
|
||||
{t('获取兑换码')}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
type="warning"
|
||||
theme="solid"
|
||||
onClick={topUp}
|
||||
disabled={isSubmitting}
|
||||
loading={isSubmitting}
|
||||
size="large"
|
||||
className="!rounded-lg flex-1"
|
||||
>
|
||||
{isSubmitting ? t('兑换中...') : t('兑换')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex items-center mb-6">
|
||||
<div className="w-12 h-12 rounded-full bg-blue-50 flex items-center justify-center mr-4">
|
||||
<IconPlus size="large" className="text-blue-500" />
|
||||
</div>
|
||||
<div>
|
||||
<Text className="text-xl font-semibold">{t('在线充值')}</Text>
|
||||
<div className="text-gray-500 text-sm">{t('支持多种支付方式')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<div className="flex justify-between mb-2">
|
||||
<Text strong>{t('充值数量')}</Text>
|
||||
{amountLoading ? (
|
||||
<Skeleton.Title style={{ width: '80px', height: '14px' }} />
|
||||
) : (
|
||||
<Text type="tertiary">{t('实付金额:') + ' ' + renderAmount()}</Text>
|
||||
)}
|
||||
</div>
|
||||
<InputNumber
|
||||
disabled={!enableOnlineTopUp}
|
||||
placeholder={
|
||||
t('充值数量,最低 ') + renderQuotaWithAmount(minTopUp)
|
||||
}
|
||||
value={topUpCount}
|
||||
min={minTopUp}
|
||||
max={999999999}
|
||||
step={1}
|
||||
precision={0}
|
||||
onChange={async (value) => {
|
||||
if (value && value >= 1) {
|
||||
setTopUpCount(value);
|
||||
await getAmount(value);
|
||||
}
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
const value = parseInt(e.target.value);
|
||||
if (!value || value < 1) {
|
||||
setTopUpCount(1);
|
||||
getAmount(1);
|
||||
}
|
||||
}}
|
||||
size="large"
|
||||
className="!rounded-lg w-full"
|
||||
prefix={<IconCreditCard />}
|
||||
formatter={(value) => value ? `${value}` : ''}
|
||||
parser={(value) => value ? parseInt(value.replace(/[^\d]/g, '')) : 0}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<Button
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={async () => {
|
||||
preTopUp('zfb');
|
||||
}}
|
||||
size="large"
|
||||
className="!rounded-lg !bg-blue-500 hover:!bg-blue-600 h-14"
|
||||
disabled={!enableOnlineTopUp}
|
||||
loading={paymentLoading}
|
||||
icon={<SiAlipay size={20} />}
|
||||
>
|
||||
<span className="ml-2">{t('支付宝')}</span>
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={async () => {
|
||||
preTopUp('wx');
|
||||
}}
|
||||
size="large"
|
||||
className="!rounded-lg !bg-green-500 hover:!bg-green-600 h-14"
|
||||
disabled={!enableOnlineTopUp}
|
||||
loading={paymentLoading}
|
||||
icon={<SiWechat size={20} />}
|
||||
>
|
||||
<span className="ml-2">{t('微信')}</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{!enableOnlineTopUp && (
|
||||
<Banner
|
||||
fullMode={false}
|
||||
type="warning"
|
||||
icon={null}
|
||||
closeIcon={null}
|
||||
className="!rounded-lg"
|
||||
title={
|
||||
<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>
|
||||
{t('在线充值功能未开启')}
|
||||
</div>
|
||||
}
|
||||
description={
|
||||
<div>
|
||||
{t('管理员未开启在线充值功能,请联系管理员开启或使用兑换码充值。')}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user