✨ style(Account UX): resilient binding layout, copyable popovers, pastel header, and custom pay colors
- AccountManagement.js - Prevent action button from shifting when account IDs are long by adding gap, min-w-0, and flex-shrink-0; keep buttons in a fixed position. - Add copyable Popover for account identifiers (email/GitHub/OIDC/Telegram/LinuxDO) using Typography.Paragraph with copyable; reveal full text on hover. - Ensure ellipsis works by rendering the popover trigger as `block max-w-full truncate`. - Import Popover and wire up `renderAccountInfo` across all binding rows. - UserInfoHeader.js - Apply unified `with-pastel-balls` background to match PricingVendorIntro. - Remove legacy absolute-positioned circles and top gradient bar to avoid visual overlap. - RechargeCard.jsx - Colorize non-Alipay/WeChat/Stripe payment icons using backend `pay_methods[].color`; fallback to `var(--semi-color-text-2)`. - Add `showClear` to the redemption code input for quicker clearing. Notes: - No linter errors introduced. - i18n strings and behavior remain unchanged except for improved UX and visual consistency.
This commit is contained in:
@@ -26,7 +26,8 @@ import {
|
||||
Typography,
|
||||
Avatar,
|
||||
Tabs,
|
||||
TabPane
|
||||
TabPane,
|
||||
Popover
|
||||
} from '@douyinfe/semi-ui';
|
||||
import {
|
||||
IconMail,
|
||||
@@ -58,6 +59,30 @@ const AccountManagement = ({
|
||||
setShowChangePasswordModal,
|
||||
setShowAccountDeleteModal
|
||||
}) => {
|
||||
const renderAccountInfo = (accountId, label) => {
|
||||
if (!accountId || accountId === '') {
|
||||
return <span className="text-gray-500">{t('未绑定')}</span>;
|
||||
}
|
||||
|
||||
const popContent = (
|
||||
<div className="text-xs p-2">
|
||||
<Typography.Paragraph copyable={{ content: accountId }}>
|
||||
{accountId}
|
||||
</Typography.Paragraph>
|
||||
{label ? (
|
||||
<div className="mt-1 text-[11px] text-gray-500">{label}</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover content={popContent} position="top" trigger="hover">
|
||||
<span className="block max-w-full truncate text-gray-600 hover:text-blue-600 cursor-pointer">
|
||||
{accountId}
|
||||
</span>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<Card className="!rounded-2xl">
|
||||
{/* 卡片头部 */}
|
||||
@@ -71,7 +96,7 @@ const AccountManagement = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Tabs type="line" defaultActiveKey="binding">
|
||||
<Tabs type="card" defaultActiveKey="binding">
|
||||
{/* 账户绑定 Tab */}
|
||||
<TabPane
|
||||
tab={
|
||||
@@ -86,39 +111,38 @@ const AccountManagement = ({
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
{/* 邮箱绑定 */}
|
||||
<Card className="!rounded-xl">
|
||||
<div className="flex items-center justify-between">
|
||||
<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">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex items-center flex-1 min-w-0">
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3 flex-shrink-0">
|
||||
<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>
|
||||
<div className="text-sm text-gray-500 truncate">
|
||||
{userState.user && userState.user.email !== ''
|
||||
? userState.user.email
|
||||
: t('未绑定')}
|
||||
{renderAccountInfo(userState.user?.email, t('邮箱地址'))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
theme="outline"
|
||||
size="small"
|
||||
onClick={() => setShowEmailBindModal(true)}
|
||||
className="!rounded-lg"
|
||||
>
|
||||
{userState.user && userState.user.email !== ''
|
||||
? t('修改绑定')
|
||||
: t('绑定')}
|
||||
</Button>
|
||||
<div className="flex-shrink-0">
|
||||
<Button
|
||||
type="primary"
|
||||
theme="outline"
|
||||
size="small"
|
||||
onClick={() => setShowEmailBindModal(true)}
|
||||
>
|
||||
{userState.user && userState.user.email !== ''
|
||||
? t('修改绑定')
|
||||
: t('绑定')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* 微信绑定 */}
|
||||
<Card className="!rounded-xl">
|
||||
<div className="flex items-center justify-between">
|
||||
<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">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex items-center flex-1 min-w-0">
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3 flex-shrink-0">
|
||||
<SiWechat size={20} className="text-slate-600 dark:text-slate-300" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
@@ -130,110 +154,107 @@ const AccountManagement = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
theme="outline"
|
||||
size="small"
|
||||
disabled={!status.wechat_login}
|
||||
onClick={() => setShowWeChatBindModal(true)}
|
||||
className="!rounded-lg"
|
||||
>
|
||||
{userState.user && userState.user.wechat_id !== ''
|
||||
? t('修改绑定')
|
||||
: status.wechat_login
|
||||
? t('绑定')
|
||||
: t('未启用')}
|
||||
</Button>
|
||||
<div className="flex-shrink-0">
|
||||
<Button
|
||||
type="primary"
|
||||
theme="outline"
|
||||
size="small"
|
||||
disabled={!status.wechat_login}
|
||||
onClick={() => setShowWeChatBindModal(true)}
|
||||
>
|
||||
{userState.user && userState.user.wechat_id !== ''
|
||||
? t('修改绑定')
|
||||
: status.wechat_login
|
||||
? t('绑定')
|
||||
: t('未启用')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* GitHub绑定 */}
|
||||
<Card className="!rounded-xl">
|
||||
<div className="flex items-center justify-between">
|
||||
<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">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex items-center flex-1 min-w-0">
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3 flex-shrink-0">
|
||||
<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>
|
||||
<div className="text-sm text-gray-500 truncate">
|
||||
{userState.user && userState.user.github_id !== ''
|
||||
? userState.user.github_id
|
||||
: t('未绑定')}
|
||||
{renderAccountInfo(userState.user?.github_id, t('GitHub ID'))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
theme="outline"
|
||||
size="small"
|
||||
onClick={() => onGitHubOAuthClicked(status.github_client_id)}
|
||||
disabled={
|
||||
(userState.user && userState.user.github_id !== '') ||
|
||||
!status.github_oauth
|
||||
}
|
||||
className="!rounded-lg"
|
||||
>
|
||||
{status.github_oauth ? t('绑定') : t('未启用')}
|
||||
</Button>
|
||||
<div className="flex-shrink-0">
|
||||
<Button
|
||||
type="primary"
|
||||
theme="outline"
|
||||
size="small"
|
||||
onClick={() => onGitHubOAuthClicked(status.github_client_id)}
|
||||
disabled={
|
||||
(userState.user && userState.user.github_id !== '') ||
|
||||
!status.github_oauth
|
||||
}
|
||||
>
|
||||
{status.github_oauth ? t('绑定') : t('未启用')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* OIDC绑定 */}
|
||||
<Card className="!rounded-xl">
|
||||
<div className="flex items-center justify-between">
|
||||
<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">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex items-center flex-1 min-w-0">
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3 flex-shrink-0">
|
||||
<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>
|
||||
<div className="text-sm text-gray-500 truncate">
|
||||
{userState.user && userState.user.oidc_id !== ''
|
||||
? userState.user.oidc_id
|
||||
: t('未绑定')}
|
||||
{renderAccountInfo(userState.user?.oidc_id, t('OIDC ID'))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
theme="outline"
|
||||
size="small"
|
||||
onClick={() => onOIDCClicked(
|
||||
status.oidc_authorization_endpoint,
|
||||
status.oidc_client_id,
|
||||
)}
|
||||
disabled={
|
||||
(userState.user && userState.user.oidc_id !== '') ||
|
||||
!status.oidc_enabled
|
||||
}
|
||||
className="!rounded-lg"
|
||||
>
|
||||
{status.oidc_enabled ? t('绑定') : t('未启用')}
|
||||
</Button>
|
||||
<div className="flex-shrink-0">
|
||||
<Button
|
||||
type="primary"
|
||||
theme="outline"
|
||||
size="small"
|
||||
onClick={() => onOIDCClicked(
|
||||
status.oidc_authorization_endpoint,
|
||||
status.oidc_client_id,
|
||||
)}
|
||||
disabled={
|
||||
(userState.user && userState.user.oidc_id !== '') ||
|
||||
!status.oidc_enabled
|
||||
}
|
||||
>
|
||||
{status.oidc_enabled ? t('绑定') : t('未启用')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Telegram绑定 */}
|
||||
<Card className="!rounded-xl">
|
||||
<div className="flex items-center justify-between">
|
||||
<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">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex items-center flex-1 min-w-0">
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3 flex-shrink-0">
|
||||
<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>
|
||||
<div className="text-sm text-gray-500 truncate">
|
||||
{userState.user && userState.user.telegram_id !== ''
|
||||
? userState.user.telegram_id
|
||||
: t('未绑定')}
|
||||
{renderAccountInfo(userState.user?.telegram_id, t('Telegram ID'))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-shrink-0">
|
||||
{status.telegram_oauth ? (
|
||||
userState.user.telegram_id !== '' ? (
|
||||
<Button disabled={true} size="small" className="!rounded-lg">
|
||||
<Button disabled={true} size="small">
|
||||
{t('已绑定')}
|
||||
</Button>
|
||||
) : (
|
||||
@@ -245,7 +266,7 @@ const AccountManagement = ({
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<Button disabled={true} size="small" className="!rounded-lg">
|
||||
<Button disabled={true} size="small">
|
||||
{t('未启用')}
|
||||
</Button>
|
||||
)}
|
||||
@@ -255,33 +276,32 @@ const AccountManagement = ({
|
||||
|
||||
{/* LinuxDO绑定 */}
|
||||
<Card className="!rounded-xl">
|
||||
<div className="flex items-center justify-between">
|
||||
<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">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex items-center flex-1 min-w-0">
|
||||
<div className="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3 flex-shrink-0">
|
||||
<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>
|
||||
<div className="text-sm text-gray-500 truncate">
|
||||
{userState.user && userState.user.linux_do_id !== ''
|
||||
? userState.user.linux_do_id
|
||||
: t('未绑定')}
|
||||
{renderAccountInfo(userState.user?.linux_do_id, t('LinuxDO ID'))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
theme="outline"
|
||||
size="small"
|
||||
onClick={() => onLinuxDOOAuthClicked(status.linuxdo_client_id)}
|
||||
disabled={
|
||||
(userState.user && userState.user.linux_do_id !== '') ||
|
||||
!status.linuxdo_oauth
|
||||
}
|
||||
className="!rounded-lg"
|
||||
>
|
||||
{status.linuxdo_oauth ? t('绑定') : t('未启用')}
|
||||
</Button>
|
||||
<div className="flex-shrink-0">
|
||||
<Button
|
||||
type="primary"
|
||||
theme="outline"
|
||||
size="small"
|
||||
onClick={() => onLinuxDOOAuthClicked(status.linuxdo_client_id)}
|
||||
disabled={
|
||||
(userState.user && userState.user.linux_do_id !== '') ||
|
||||
!status.linuxdo_oauth
|
||||
}
|
||||
>
|
||||
{status.linuxdo_oauth ? t('绑定') : t('未启用')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
@@ -322,7 +342,6 @@ const AccountManagement = ({
|
||||
value={systemToken}
|
||||
onClick={handleSystemTokenClick}
|
||||
size="large"
|
||||
className="!rounded-lg"
|
||||
prefix={<IconKey />}
|
||||
/>
|
||||
</div>
|
||||
@@ -333,7 +352,7 @@ const AccountManagement = ({
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={generateAccessToken}
|
||||
className="!rounded-lg !bg-slate-600 hover:!bg-slate-700 w-full sm:w-auto"
|
||||
className="!bg-slate-600 hover:!bg-slate-700 w-full sm:w-auto"
|
||||
icon={<IconKey />}
|
||||
>
|
||||
{systemToken ? t('重新生成') : t('生成令牌')}
|
||||
@@ -361,7 +380,7 @@ const AccountManagement = ({
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={() => setShowChangePasswordModal(true)}
|
||||
className="!rounded-lg !bg-slate-600 hover:!bg-slate-700 w-full sm:w-auto"
|
||||
className="!bg-slate-600 hover:!bg-slate-700 w-full sm:w-auto"
|
||||
icon={<IconLock />}
|
||||
>
|
||||
{t('修改密码')}
|
||||
@@ -392,7 +411,7 @@ const AccountManagement = ({
|
||||
type="danger"
|
||||
theme="solid"
|
||||
onClick={() => setShowAccountDeleteModal(true)}
|
||||
className="!rounded-lg w-full sm:w-auto !bg-slate-500 hover:!bg-slate-600"
|
||||
className="w-full sm:w-auto !bg-slate-500 hover:!bg-slate-600"
|
||||
icon={<IconDelete />}
|
||||
>
|
||||
{t('删除账户')}
|
||||
|
||||
@@ -106,7 +106,7 @@ const NotificationSettings = ({
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{() => (
|
||||
<Tabs type="line" defaultActiveKey="notification">
|
||||
<Tabs type="card" defaultActiveKey="notification">
|
||||
{/* 通知配置 Tab */}
|
||||
<TabPane
|
||||
tab={
|
||||
@@ -223,11 +223,11 @@ const NotificationSettings = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 leading-relaxed">
|
||||
<div><strong>type:</strong> 通知类型 (quota_exceed: 额度预警)</div>
|
||||
<div><strong>title:</strong> 通知标题</div>
|
||||
<div><strong>content:</strong> 通知内容,支持 {`{{value}}`} 变量占位符</div>
|
||||
<div><strong>values:</strong> 按顺序替换content中的变量占位符</div>
|
||||
<div><strong>timestamp:</strong> Unix时间戳</div>
|
||||
<div><strong>type:</strong> {t('通知类型 (quota_exceed: 额度预警)')} </div>
|
||||
<div><strong>title:</strong> {t('通知标题')}</div>
|
||||
<div><strong>content:</strong> {t('通知内容,支持 {{value}} 变量占位符')}</div>
|
||||
<div><strong>values:</strong> {t('按顺序替换content中的变量占位符')}</div>
|
||||
<div><strong>timestamp:</strong> {t('Unix时间戳')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form.Slot>
|
||||
|
||||
@@ -19,12 +19,10 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
|
||||
import React from 'react';
|
||||
import { Avatar, Card, Tag, Divider, Typography } from '@douyinfe/semi-ui';
|
||||
import { isRoot, isAdmin, renderQuota } from '../../../../helpers';
|
||||
import { useTheme } from '../../../../context/Theme';
|
||||
import { isRoot, isAdmin, renderQuota, stringToColor } from '../../../../helpers';
|
||||
import { Coins, BarChart2, Users } from 'lucide-react';
|
||||
|
||||
const UserInfoHeader = ({ t, userState }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const getUsername = () => {
|
||||
if (userState.user) {
|
||||
@@ -44,34 +42,19 @@ const UserInfoHeader = ({ t, userState }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="!rounded-2xl !border-0"
|
||||
style={{
|
||||
background: theme === 'dark'
|
||||
? '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-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 text-gray-600 dark:text-gray-300">
|
||||
<Card className="!rounded-2xl with-pastel-balls">
|
||||
<div className="relative 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'
|
||||
className="mr-3 sm:mr-4 shadow-md flex-shrink-0 bg-slate-500 dark:bg-slate-400"
|
||||
className="mr-3 sm:mr-4 shadow-md flex-shrink-0"
|
||||
color={stringToColor(getUsername())}
|
||||
>
|
||||
{getAvatarText()}
|
||||
</Avatar>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-base sm:text-lg font-semibold truncate text-gray-800 dark:text-gray-100">
|
||||
<div className="text-base text-3xl font-semibold truncate text-gray-800 dark:text-gray-100">
|
||||
{getUsername()}
|
||||
</div>
|
||||
<div className="mt-1 flex flex-wrap gap-1 sm:gap-2">
|
||||
@@ -113,7 +96,7 @@ const UserInfoHeader = ({ t, userState }) => {
|
||||
|
||||
{/* 右上角统计信息(Semi UI 卡片) */}
|
||||
<div className="hidden sm:block flex-shrink-0 ml-2">
|
||||
<Card size="small" className="!rounded-xl !border-0 shadow-sm" bodyStyle={{ padding: '8px 12px' }}>
|
||||
<Card size="small" className="!rounded-xl shadow-sm" bodyStyle={{ padding: '8px 12px' }}>
|
||||
<div className="flex items-center gap-3 lg:gap-4">
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<Coins size={16} className="text-slate-600 dark:text-slate-300" />
|
||||
@@ -182,11 +165,9 @@ const UserInfoHeader = ({ t, userState }) => {
|
||||
</div>
|
||||
</Card>
|
||||
</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>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserInfoHeader;
|
||||
export default UserInfoHeader;
|
||||
@@ -54,7 +54,7 @@ const InvitationCard = ({
|
||||
{/* 收益展示区域 */}
|
||||
<div className='space-y-4'>
|
||||
{/* 主要收益卡片 - 待使用收益 */}
|
||||
<Card className='!rounded-xl bg-slate-50 dark:bg-slate-800'>
|
||||
<Card className='!rounded-xl with-pastel-balls'>
|
||||
<div className='flex justify-between items-center mb-3'>
|
||||
<div className="flex items-center">
|
||||
<TrendingUp size={16} className="mr-2 text-slate-600 dark:text-slate-300" />
|
||||
@@ -75,7 +75,6 @@ const InvitationCard = ({
|
||||
<div className='text-2xl sm:text-3xl font-bold text-slate-900 dark:text-slate-100 mb-1'>
|
||||
{renderQuota(userState?.user?.aff_quota || 0)}
|
||||
</div>
|
||||
<div className="text-xs text-slate-500 dark:text-slate-400">{t('可随时划转到账户余额')}</div>
|
||||
</Card>
|
||||
|
||||
{/* 统计数据网格 */}
|
||||
@@ -88,7 +87,6 @@ const InvitationCard = ({
|
||||
<div className='text-xl font-semibold text-slate-900 dark:text-slate-100'>
|
||||
{renderQuota(userState?.user?.aff_history_quota || 0)}
|
||||
</div>
|
||||
<div className="text-xs text-slate-500 dark:text-slate-400 mt-1">{t('累计获得')}</div>
|
||||
</Card>
|
||||
|
||||
<Card className='!rounded-xl bg-slate-50 dark:bg-slate-800'>
|
||||
@@ -99,7 +97,6 @@ const InvitationCard = ({
|
||||
<div className='text-xl font-semibold text-slate-900 dark:text-slate-100 flex items-center'>
|
||||
{userState?.user?.aff_count || 0} {t('人')}
|
||||
</div>
|
||||
<div className="text-xs text-slate-500 dark:text-slate-400 mt-1">{t('成功邀请')}</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -126,7 +123,7 @@ const InvitationCard = ({
|
||||
|
||||
{/* 奖励说明 */}
|
||||
<Card
|
||||
className='!rounded-xl'
|
||||
className='!rounded-xl with-pastel-balls-warm'
|
||||
title={
|
||||
<Text strong className='text-slate-700'>
|
||||
{t('奖励说明')}
|
||||
|
||||
@@ -224,7 +224,7 @@ const RechargeCard = ({
|
||||
) : payMethod.type === 'stripe' ? (
|
||||
<SiStripe size={24} color="#635BFF" />
|
||||
) : (
|
||||
<CreditCard size={24} className='text-slate-500' />
|
||||
<CreditCard size={24} color={payMethod.color || 'var(--semi-color-text-2)'} />
|
||||
)}
|
||||
</div>
|
||||
<div className='text-sm font-medium text-slate-700 dark:text-slate-200'>{payMethod.name}</div>
|
||||
@@ -269,6 +269,7 @@ const RechargeCard = ({
|
||||
onChange={(value) => setRedemptionCode(value)}
|
||||
className='!rounded-lg'
|
||||
prefix={<IconGift />}
|
||||
showClear
|
||||
/>
|
||||
|
||||
<div className='flex flex-col sm:flex-row gap-2'>
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
Card,
|
||||
Skeleton,
|
||||
} from '@douyinfe/semi-ui';
|
||||
import { SiAlipay, SiWechat } from 'react-icons/si';
|
||||
import { SiAlipay, SiWechat, SiStripe } from 'react-icons/si';
|
||||
import { CreditCard } from 'lucide-react';
|
||||
|
||||
const { Text } = Typography;
|
||||
@@ -86,11 +86,13 @@ const PaymentConfirmModal = ({
|
||||
return (
|
||||
<>
|
||||
{payMethod.type === 'zfb' ? (
|
||||
<SiAlipay className='mr-2' size={16} />
|
||||
<SiAlipay className='mr-2' size={16} color="#1677FF" />
|
||||
) : payMethod.type === 'wx' ? (
|
||||
<SiWechat className='mr-2' size={16} />
|
||||
<SiWechat className='mr-2' size={16} color="#07C160" />
|
||||
) : payMethod.type === 'stripe' ? (
|
||||
<SiStripe className='mr-2' size={16} color="#635BFF" />
|
||||
) : (
|
||||
<CreditCard className='mr-2' size={16} />
|
||||
<CreditCard className='mr-2' size={16} color={payMethod.color || 'var(--semi-color-text-2)'} />
|
||||
)}
|
||||
<Text className='text-slate-900 dark:text-slate-100'>{payMethod.name}</Text>
|
||||
</>
|
||||
@@ -100,21 +102,21 @@ const PaymentConfirmModal = ({
|
||||
if (payWay === 'zfb') {
|
||||
return (
|
||||
<>
|
||||
<SiAlipay className='mr-2' size={16} />
|
||||
<SiAlipay className='mr-2' size={16} color="#1677FF" />
|
||||
<Text className='text-slate-900 dark:text-slate-100'>{t('支付宝')}</Text>
|
||||
</>
|
||||
);
|
||||
} else if (payWay === 'stripe') {
|
||||
return (
|
||||
<>
|
||||
<CreditCard className='mr-2' size={16} />
|
||||
<SiStripe className='mr-2' size={16} color="#635BFF" />
|
||||
<Text className='text-slate-900 dark:text-slate-100'>Stripe</Text>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<SiWechat className='mr-2' size={16} />
|
||||
<SiWechat className='mr-2' size={16} color="#07C160" />
|
||||
<Text className='text-slate-900 dark:text-slate-100'>{t('微信')}</Text>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -853,13 +853,11 @@
|
||||
"支付宝": "Alipay",
|
||||
"待使用收益": "Proceeds to be used",
|
||||
"邀请人数": "Number of people invited",
|
||||
"可随时划转到账户余额": "Can be transferred to the account balance at any time",
|
||||
"成功邀请": "Successfully invited",
|
||||
"累计获得": "Accumulated",
|
||||
"兑换码充值": "Redemption code recharge",
|
||||
"奖励说明": "Reward description",
|
||||
"人": "",
|
||||
"选择支付方式": "Select payment method",
|
||||
"处理中": "Processing",
|
||||
"账户充值": "Account recharge",
|
||||
"多种充值方式,安全便捷": "Multiple recharge methods, safe and convenient",
|
||||
"支付方式": "Payment method",
|
||||
|
||||
@@ -668,6 +668,59 @@ html.dark .with-pastel-balls::before {
|
||||
mix-blend-mode: screen;
|
||||
}
|
||||
|
||||
/* ==================== 卡片马卡龙模糊球(温暖色系) ==================== */
|
||||
.with-pastel-balls-warm {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
/* 温暖色系变量(明亮模式) */
|
||||
--pb1: #ffe4b5;
|
||||
/* 桃杏 */
|
||||
--pb2: #d4ffdd;
|
||||
/* 薄荷绿 */
|
||||
--pb3: #ffecb3;
|
||||
/* 浅金 */
|
||||
--pb4: #e8f5e8;
|
||||
/* 淡绿 */
|
||||
--pb-opacity: 0.55;
|
||||
}
|
||||
|
||||
.with-pastel-balls-warm::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
background:
|
||||
radial-gradient(circle at -5% -10%, var(--pb1) 0%, transparent 60%),
|
||||
radial-gradient(circle at 105% -10%, var(--pb2) 0%, transparent 55%),
|
||||
radial-gradient(circle at 5% 110%, var(--pb3) 0%, transparent 55%),
|
||||
radial-gradient(circle at 105% 110%, var(--pb4) 0%, transparent 50%);
|
||||
opacity: var(--pb-opacity);
|
||||
}
|
||||
|
||||
.with-pastel-balls-warm>* {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 暗黑模式下更柔和的色彩和透明度 */
|
||||
html.dark .with-pastel-balls-warm {
|
||||
--pb1: #ffe4b5;
|
||||
/* 桃杏 */
|
||||
--pb2: #d4ffdd;
|
||||
/* 薄荷绿 */
|
||||
--pb3: #ffecb3;
|
||||
/* 浅金 */
|
||||
--pb4: #e8f5e8;
|
||||
/* 淡绿 */
|
||||
--pb-opacity: 0.36;
|
||||
}
|
||||
|
||||
/* 暗黑模式下用更柔和的混合模式 */
|
||||
html.dark .with-pastel-balls-warm::before {
|
||||
mix-blend-mode: screen;
|
||||
}
|
||||
|
||||
/* ==================== 表格卡片滚动设置 ==================== */
|
||||
.table-scroll-card {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user