修复 antd 弃用警告

This commit is contained in:
yml2213
2026-07-24 12:48:02 +08:00
parent a13dde57dd
commit 6840728da6
17 changed files with 225 additions and 138 deletions
+5 -1
View File
@@ -1,10 +1,11 @@
import { lazy, Suspense, useState, useCallback, type ReactNode } from 'react'; import { lazy, Suspense, useState, useCallback, type ReactNode } from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { ConfigProvider, Spin, theme } from 'antd'; import { App as AntdApp, ConfigProvider, Spin, theme } from 'antd';
import zhCN from 'antd/locale/zh_CN'; import zhCN from 'antd/locale/zh_CN';
import { getUser } from './store/auth'; import { getUser } from './store/auth';
import { ThemeProvider } from './store/theme'; import { ThemeProvider } from './store/theme';
import { useTheme } from './store/useTheme'; import { useTheme } from './store/useTheme';
import AntdMessageBridge from './utils/AntdMessageBridge';
const LoginPage = lazy(() => import('./pages/LoginPage')); const LoginPage = lazy(() => import('./pages/LoginPage'));
const MainLayout = lazy(() => import('./layouts/MainLayout')); const MainLayout = lazy(() => import('./layouts/MainLayout'));
@@ -51,6 +52,8 @@ function AppContent() {
}, },
}} }}
> >
<AntdApp>
<AntdMessageBridge />
<BrowserRouter> <BrowserRouter>
<Routes> <Routes>
<Route path="/login" element={lazyRoute(<LoginPage onLogin={refreshAuth} />)} /> <Route path="/login" element={lazyRoute(<LoginPage onLogin={refreshAuth} />)} />
@@ -79,6 +82,7 @@ function AppContent() {
<Route path="*" element={<Navigate to="/" replace />} /> <Route path="*" element={<Navigate to="/" replace />} />
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>
</AntdApp>
</ConfigProvider> </ConfigProvider>
); );
} }
+1 -1
View File
@@ -193,7 +193,7 @@ export default function MainLayout({ onLogout }: { onLogout?: () => void }) {
)} )}
{collapsed ? ( {collapsed ? (
<> <>
<Space direction="vertical" style={{ width: '100%' }}> <Space orientation="vertical" style={{ width: '100%' }}>
<Dropdown <Dropdown
menu={{ items: THEME_OPTIONS.map(o => ({ key: o.key, label: o.label, icon: o.icon, onClick: () => setMode(o.key) })) }} menu={{ items: THEME_OPTIONS.map(o => ({ key: o.key, label: o.label, icon: o.icon, onClick: () => setMode(o.key) })) }}
trigger={['click']} trigger={['click']}
+11 -6
View File
@@ -1,7 +1,8 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { import {
Button, Card, Col, Input, InputNumber, message, Popconfirm, Row, Space, Statistic, Switch, Table, Tag, Typography, Button, Card, Col, Input, InputNumber, Popconfirm, Row, Space, Statistic, Switch, Table, Tag, Typography,
} from 'antd'; } from 'antd';
import { message } from '../utils/antdMessage';
import type { TableProps } from 'antd'; import type { TableProps } from 'antd';
import { DownloadOutlined, PlayCircleOutlined, ReloadOutlined, StopOutlined } from '@ant-design/icons'; import { DownloadOutlined, PlayCircleOutlined, ReloadOutlined, StopOutlined } from '@ant-design/icons';
import { accountCheckApi, type AccountCheckBatch, type AccountCheckItem } from '../api/modules'; import { accountCheckApi, type AccountCheckBatch, type AccountCheckItem } from '../api/modules';
@@ -163,7 +164,7 @@ export default function AccountCheckPage() {
return () => window.clearInterval(timer); return () => window.clearInterval(timer);
}, [batchId, isRunning, refreshBatch]); }, [batchId, isRunning, refreshBatch]);
const statusCounts = batch?.status_counts || {}; const statusCounts = useMemo(() => batch?.status_counts || {}, [batch?.status_counts]);
const categoryStats = useMemo(() => [ const categoryStats = useMemo(() => [
{ title: '已注销', value: statusCounts.account_cancelled || 0 }, { title: '已注销', value: statusCounts.account_cancelled || 0 },
{ title: '密码错误', value: statusCounts.password_wrong || 0 }, { title: '密码错误', value: statusCounts.password_wrong || 0 },
@@ -247,11 +248,11 @@ export default function AccountCheckPage() {
]; ];
return ( return (
<Space direction="vertical" size={16} style={{ width: '100%' }}> <Space orientation="vertical" size={16} style={{ width: '100%' }}>
<Title level={3} style={{ margin: 0 }}></Title> <Title level={3} style={{ margin: 0 }}></Title>
<Card title="导入账号"> <Card title="导入账号">
<Space direction="vertical" size={12} style={{ width: '100%' }}> <Space orientation="vertical" size={12} style={{ width: '100%' }}>
<TextArea <TextArea
rows={9} rows={9}
value={text} value={text}
@@ -273,6 +274,7 @@ export default function AccountCheckPage() {
</Col> </Col>
<Col xs={8} md={4}> <Col xs={8} md={4}>
<Text type="secondary"></Text> <Text type="secondary"></Text>
<Space.Compact style={{ width: '100%' }}>
<InputNumber <InputNumber
min={0} min={0}
max={3600} max={3600}
@@ -280,21 +282,24 @@ export default function AccountCheckPage() {
value={maxTotalTime} value={maxTotalTime}
onChange={(value) => setMaxTotalTime(Number(value ?? 0))} onChange={(value) => setMaxTotalTime(Number(value ?? 0))}
disabled={isRunning} disabled={isRunning}
addonAfter="秒"
style={{ width: '100%' }} style={{ width: '100%' }}
/> />
<Button disabled></Button>
</Space.Compact>
</Col> </Col>
<Col xs={8} md={4}> <Col xs={8} md={4}>
<Text type="secondary"></Text> <Text type="secondary"></Text>
<Space.Compact style={{ width: '100%' }}>
<InputNumber <InputNumber
min={0} min={0}
max={50} max={50}
value={maxLoginRetries} value={maxLoginRetries}
onChange={(value) => setMaxLoginRetries(Number(value ?? 0))} onChange={(value) => setMaxLoginRetries(Number(value ?? 0))}
disabled={isRunning} disabled={isRunning}
addonAfter="次"
style={{ width: '100%' }} style={{ width: '100%' }}
/> />
<Button disabled></Button>
</Space.Compact>
</Col> </Col>
<Col xs={12} md={4}> <Col xs={12} md={4}>
<Text type="secondary"></Text> <Text type="secondary"></Text>
+2 -1
View File
@@ -1,8 +1,9 @@
import { useEffect, useState, useMemo, useCallback } from 'react'; import { useEffect, useState, useMemo, useCallback } from 'react';
import { import {
Table, Button, Modal, Input, Select, message, Popconfirm, Typography, Tag, Space, Table, Button, Modal, Input, Select, Popconfirm, Typography, Tag, Space,
Row, Col, Card, Statistic, Row, Col, Card, Statistic,
} from 'antd'; } from 'antd';
import { message } from '../utils/antdMessage';
import type { TableProps } from 'antd'; import type { TableProps } from 'antd';
import { ImportOutlined, DeleteOutlined, TagOutlined, FilterOutlined } from '@ant-design/icons'; import { ImportOutlined, DeleteOutlined, TagOutlined, FilterOutlined } from '@ant-design/icons';
import { accountApi, userApi, type AccountItem, type UserInfo } from '../api/modules'; import { accountApi, userApi, type AccountItem, type UserInfo } from '../api/modules';
+2 -1
View File
@@ -1,8 +1,9 @@
import { useEffect, useState, useMemo } from 'react'; import { useEffect, useState, useMemo } from 'react';
import { import {
Card, Table, Button, Select, Input, Tag, Row, Col, Statistic, Card, Table, Button, Select, Input, Tag, Row, Col, Statistic,
message, Space, Tabs, Typography, Badge, theme, Space, Tabs, Typography, Badge, theme,
} from 'antd'; } from 'antd';
import { message } from '../utils/antdMessage';
import { import {
UserOutlined, CheckCircleOutlined, TeamOutlined, UserOutlined, CheckCircleOutlined, TeamOutlined,
SwapOutlined, ClearOutlined, UsergroupAddOutlined, SwapOutlined, ClearOutlined, UsergroupAddOutlined,
+2 -1
View File
@@ -1,5 +1,6 @@
import { useEffect, useState, useCallback } from 'react'; import { useEffect, useState, useCallback } from 'react';
import { Table, Button, Card, Row, Col, Statistic, message, Tag, Popconfirm, Space, Typography, Input, theme, Dropdown } from 'antd'; import { Table, Button, Card, Row, Col, Statistic, Tag, Popconfirm, Space, Typography, Input, theme, Dropdown } from 'antd';
import { message } from '../utils/antdMessage';
import { DownloadOutlined, DeleteOutlined, CopyOutlined, SearchOutlined } from '@ant-design/icons'; import { DownloadOutlined, DeleteOutlined, CopyOutlined, SearchOutlined } from '@ant-design/icons';
import { cookieApi, type CookieItem } from '../api/modules'; import { cookieApi, type CookieItem } from '../api/modules';
import { usePermissions } from '../hooks/usePermissions'; import { usePermissions } from '../hooks/usePermissions';
+7 -6
View File
@@ -1,7 +1,8 @@
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { import {
Button, Card, Col, Input, message, Modal, Popconfirm, Row, Select, Space, Statistic, Table, Tag, Typography, Button, Card, Col, Input, Modal, Popconfirm, Row, Select, Space, Statistic, Table, Tag, Typography,
} from 'antd'; } from 'antd';
import { message } from '../utils/antdMessage';
import type { TableProps } from 'antd'; import type { TableProps } from 'antd';
import { DeleteOutlined, FilterOutlined, ImportOutlined, LoginOutlined, MobileOutlined, ReloadOutlined, SearchOutlined, TagOutlined } from '@ant-design/icons'; import { DeleteOutlined, FilterOutlined, ImportOutlined, LoginOutlined, MobileOutlined, ReloadOutlined, SearchOutlined, TagOutlined } from '@ant-design/icons';
import { import {
@@ -376,7 +377,7 @@ export default function HuyaAccountsPage() {
title: '虎牙账号', title: '虎牙账号',
width: 180, width: 180,
render: (_: unknown, record) => ( render: (_: unknown, record) => (
<Space direction="vertical" size={0}> <Space orientation="vertical" size={0}>
<Text strong>{record.nickname || record.username || record.uid || '-'}</Text> <Text strong>{record.nickname || record.username || record.uid || '-'}</Text>
<Text type="secondary" style={{ fontSize: 12 }}> <Text type="secondary" style={{ fontSize: 12 }}>
UID {record.uid || record.yyuid || '-'} UID {record.uid || record.yyuid || '-'}
@@ -440,7 +441,7 @@ export default function HuyaAccountsPage() {
width: 160, width: 160,
ellipsis: true, ellipsis: true,
render: (value: string, record) => value ? ( render: (value: string, record) => value ? (
<Space direction="vertical" size={0}> <Space orientation="vertical" size={0}>
<Text>{value}</Text> <Text>{value}</Text>
{record.game_channel ? ( {record.game_channel ? (
<Text type="secondary" style={{ fontSize: 12 }}>{record.game_channel}</Text> <Text type="secondary" style={{ fontSize: 12 }}>{record.game_channel}</Text>
@@ -659,7 +660,7 @@ export default function HuyaAccountsPage() {
confirmLoading={importing} confirmLoading={importing}
width={720} width={720}
> >
<Space direction="vertical" style={{ width: '100%' }} size={12}> <Space orientation="vertical" style={{ width: '100%' }} size={12}>
<Input <Input
placeholder="标签,可选" placeholder="标签,可选"
value={importTag} value={importTag}
@@ -711,7 +712,7 @@ export default function HuyaAccountsPage() {
closable={!passwordImporting} closable={!passwordImporting}
width={720} width={720}
> >
<Space direction="vertical" style={{ width: '100%' }} size={12}> <Space orientation="vertical" style={{ width: '100%' }} size={12}>
<TextArea <TextArea
rows={10} rows={10}
value={passwordImportText} value={passwordImportText}
@@ -757,7 +758,7 @@ export default function HuyaAccountsPage() {
closable={!(smsSending || smsLogging)} closable={!(smsSending || smsLogging)}
width={520} width={520}
> >
<Space direction="vertical" style={{ width: '100%' }} size={12}> <Space orientation="vertical" style={{ width: '100%' }} size={12}>
<Input <Input
value={smsPhone} value={smsPhone}
onChange={(e) => setSmsPhone(e.target.value)} onChange={(e) => setSmsPhone(e.target.value)}
@@ -1,7 +1,8 @@
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { import {
Badge, Button, Card, Col, Input, message, Row, Select, Space, Statistic, Table, Tabs, Tag, theme, Typography, Badge, Button, Card, Col, Input, Row, Select, Space, Statistic, Table, Tabs, Tag, theme, Typography,
} from 'antd'; } from 'antd';
import { message } from '../utils/antdMessage';
import { import {
CheckCircleOutlined, ClearOutlined, SwapOutlined, TeamOutlined, UsergroupAddOutlined, UserOutlined, CheckCircleOutlined, ClearOutlined, SwapOutlined, TeamOutlined, UsergroupAddOutlined, UserOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
@@ -178,7 +179,7 @@ export default function HuyaAssignmentsPage() {
{ {
title: '虎牙账号', title: '虎牙账号',
render: (_: unknown, record: HuyaAccountItem) => ( render: (_: unknown, record: HuyaAccountItem) => (
<Space direction="vertical" size={0}> <Space orientation="vertical" size={0}>
<Text strong>{accountName(record)}</Text> <Text strong>{accountName(record)}</Text>
<Text type="secondary" style={{ fontSize: 12 }}>UID {record.uid || record.yyuid || '-'}</Text> <Text type="secondary" style={{ fontSize: 12 }}>UID {record.uid || record.yyuid || '-'}</Text>
</Space> </Space>
+2 -1
View File
@@ -1,7 +1,8 @@
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { import {
Button, Card, Col, Dropdown, Input, message, Popconfirm, Row, Space, Statistic, Table, Tag, theme, Typography, Button, Card, Col, Dropdown, Input, Popconfirm, Row, Space, Statistic, Table, Tag, theme, Typography,
} from 'antd'; } from 'antd';
import { message } from '../utils/antdMessage';
import { CopyOutlined, DeleteOutlined, DownloadOutlined, SearchOutlined } from '@ant-design/icons'; import { CopyOutlined, DeleteOutlined, DownloadOutlined, SearchOutlined } from '@ant-design/icons';
import { huyaApi, type HuyaCookieItem } from '../api/modules'; import { huyaApi, type HuyaCookieItem } from '../api/modules';
import { usePermissions } from '../hooks/usePermissions'; import { usePermissions } from '../hooks/usePermissions';
+4 -3
View File
@@ -1,7 +1,8 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { import {
Button, Card, Col, Input, InputNumber, message, Row, Segmented, Space, Statistic, Switch, Table, Tag, Typography, Button, Card, Col, Input, InputNumber, Row, Segmented, Space, Statistic, Switch, Table, Tag, Typography,
} from 'antd'; } from 'antd';
import { message } from '../utils/antdMessage';
import type { TableProps } from 'antd'; import type { TableProps } from 'antd';
import { import {
DownloadOutlined, PlayCircleOutlined, RedoOutlined, ReloadOutlined, StopOutlined, DownloadOutlined, PlayCircleOutlined, RedoOutlined, ReloadOutlined, StopOutlined,
@@ -584,11 +585,11 @@ export default function HuyaRegisterPage() {
]; ];
return ( return (
<Space direction="vertical" size={16} style={{ width: '100%' }}> <Space orientation="vertical" size={16} style={{ width: '100%' }}>
<Title level={3} style={{ margin: 0 }}></Title> <Title level={3} style={{ margin: 0 }}></Title>
<Card title="手机号池"> <Card title="手机号池">
<Space direction="vertical" size={12} style={{ width: '100%' }}> <Space orientation="vertical" size={12} style={{ width: '100%' }}>
<TextArea <TextArea
rows={9} rows={9}
value={text} value={text}
+27 -20
View File
@@ -1,7 +1,8 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { import {
Button, Card, Col, DatePicker, Dropdown, Form, Input, InputNumber, message, Modal, QRCode, Radio, Row, Select, Space, Table, Tag, Tooltip, Typography, theme, Button, Card, Col, DatePicker, Dropdown, Form, Input, InputNumber, Modal, QRCode, Radio, Row, Select, Space, Table, Tag, Tooltip, Typography, theme,
} from 'antd'; } from 'antd';
import { message } from '../utils/antdMessage';
import type { MenuProps, TableProps } from 'antd'; import type { MenuProps, TableProps } from 'antd';
import type { Dayjs } from 'dayjs'; import type { Dayjs } from 'dayjs';
import type { MouseEvent as ReactMouseEvent } from 'react'; import type { MouseEvent as ReactMouseEvent } from 'react';
@@ -1164,7 +1165,7 @@ export default function HuyaTasksPage() {
title: '虎牙 CK', title: '虎牙 CK',
width: 250, width: 250,
render: (_: unknown, record) => ( render: (_: unknown, record) => (
<Space direction="vertical" size={1} style={{ width: '100%' }}> <Space orientation="vertical" size={1} style={{ width: '100%' }}>
<Space size={6} wrap> <Space size={6} wrap>
<Text strong>{accountDisplayName(record)}</Text> <Text strong>{accountDisplayName(record)}</Text>
{record.tag ? <Tag color={tagColorMap[record.tag]}>{record.tag}</Tag> : null} {record.tag ? <Tag color={tagColorMap[record.tag]}>{record.tag}</Tag> : null}
@@ -1191,7 +1192,7 @@ export default function HuyaTasksPage() {
width: 170, width: 170,
ellipsis: true, ellipsis: true,
render: (value: string, record) => value ? ( render: (value: string, record) => value ? (
<Space direction="vertical" size={0}> <Space orientation="vertical" size={0}>
<Text>{value}</Text> <Text>{value}</Text>
{record.game_channel ? <Text type="secondary" style={{ fontSize: 12 }}>{record.game_channel}</Text> : null} {record.game_channel ? <Text type="secondary" style={{ fontSize: 12 }}>{record.game_channel}</Text> : null}
</Space> </Space>
@@ -1214,7 +1215,7 @@ export default function HuyaTasksPage() {
const product = taskProductText(task); const product = taskProductText(task);
if (!task || !product) return <Text type="secondary">-</Text>; if (!task || !product) return <Text type="secondary">-</Text>;
return ( return (
<Space direction="vertical" size={1}> <Space orientation="vertical" size={1}>
<Text ellipsis style={{ maxWidth: 170 }}>{product}</Text> <Text ellipsis style={{ maxWidth: 170 }}>{product}</Text>
<Tag color={STATUS_COLORS[task.status] || 'default'} style={{ width: 'fit-content' }}> <Tag color={STATUS_COLORS[task.status] || 'default'} style={{ width: 'fit-content' }}>
{taskTypes[task.task_type] || task.task_type} {taskTypes[task.task_type] || task.task_type}
@@ -1250,7 +1251,7 @@ export default function HuyaTasksPage() {
const latest = latestTaskByAccount.get(record.id); const latest = latestTaskByAccount.get(record.id);
if (!latest) return <Text type="secondary"></Text>; if (!latest) return <Text type="secondary"></Text>;
return ( return (
<Space direction="vertical" size={2} style={{ width: '100%' }}> <Space orientation="vertical" size={2} style={{ width: '100%' }}>
<Text ellipsis style={{ maxWidth: 238 }}> <Text ellipsis style={{ maxWidth: 238 }}>
{taskTypes[latest.task_type] || latest.task_type}{latest.message || '-'} {taskTypes[latest.task_type] || latest.task_type}{latest.message || '-'}
</Text> </Text>
@@ -1294,7 +1295,7 @@ export default function HuyaTasksPage() {
title: '虎牙 CK', title: '虎牙 CK',
width: 230, width: 230,
render: (_: unknown, record) => ( render: (_: unknown, record) => (
<Space direction="vertical" size={1}> <Space orientation="vertical" size={1}>
<Space size={6} wrap> <Space size={6} wrap>
<Text strong>{accountDisplayName(record)}</Text> <Text strong>{accountDisplayName(record)}</Text>
{record.tag ? <Tag color={tagColorMap[record.tag]}>{record.tag}</Tag> : null} {record.tag ? <Tag color={tagColorMap[record.tag]}>{record.tag}</Tag> : null}
@@ -1315,7 +1316,7 @@ export default function HuyaTasksPage() {
dataIndex: 'game_name', dataIndex: 'game_name',
ellipsis: true, ellipsis: true,
render: (value: string, record) => value ? ( render: (value: string, record) => value ? (
<Space direction="vertical" size={0}> <Space orientation="vertical" size={0}>
<Text>{value}</Text> <Text>{value}</Text>
{record.game_channel ? <Text type="secondary" style={{ fontSize: 12 }}>{record.game_channel}</Text> : null} {record.game_channel ? <Text type="secondary" style={{ fontSize: 12 }}>{record.game_channel}</Text> : null}
</Space> </Space>
@@ -1482,7 +1483,7 @@ export default function HuyaTasksPage() {
{accountContextMenu.accountIds.length > 1 ? '右键批量动作' : '右键账号动作'} {accountContextMenu.accountIds.length > 1 ? '右键批量动作' : '右键账号动作'}
</Text> </Text>
</div> </div>
<Space direction="vertical" size={2} style={{ width: '100%' }}> <Space orientation="vertical" size={2} style={{ width: '100%' }}>
{QUICK_ACTIONS.map((item) => ( {QUICK_ACTIONS.map((item) => (
<Button <Button
key={item.key} key={item.key}
@@ -1626,17 +1627,19 @@ export default function HuyaTasksPage() {
</div> </div>
<div style={{ minHeight: 0, overflowY: 'auto', overflowX: 'hidden' }}> <div style={{ minHeight: 0, overflowY: 'auto', overflowX: 'hidden' }}>
<Space direction="vertical" size={12} style={{ width: '100%' }}> <Space orientation="vertical" size={12} style={{ width: '100%' }}>
<Card size="small" title="批量动作" extra={<Tag color={selectedIds.length ? 'blue' : 'default'}>{selectedAccountText}</Tag>}> <Card size="small" title="批量动作" extra={<Tag color={selectedIds.length ? 'blue' : 'default'}>{selectedAccountText}</Tag>}>
<Space direction="vertical" size={10} style={{ width: '100%' }}> <Space orientation="vertical" size={10} style={{ width: '100%' }}>
<Space.Compact style={{ width: '100%' }}>
<Button disabled></Button>
<InputNumber <InputNumber
min={1} min={1}
max={10} max={10}
value={concurrency} value={concurrency}
onChange={(value) => setConcurrency(value || 1)} onChange={(value) => setConcurrency(value || 1)}
addonBefore="并发"
style={{ width: '100%' }} style={{ width: '100%' }}
/> />
</Space.Compact>
<Select <Select
value={selectedTaskType} value={selectedTaskType}
onChange={setSelectedTaskType} onChange={setSelectedTaskType}
@@ -1685,7 +1688,7 @@ export default function HuyaTasksPage() {
</Button> </Button>
)} )}
> >
<Space direction="vertical" size={10} style={{ width: '100%' }}> <Space orientation="vertical" size={10} style={{ width: '100%' }}>
{goodsCategories.length > 0 ? ( {goodsCategories.length > 0 ? (
<Select <Select
value={selectedGoodsCategory} value={selectedGoodsCategory}
@@ -1707,12 +1710,14 @@ export default function HuyaTasksPage() {
style={{ width: '100%' }} style={{ width: '100%' }}
filterOption={(input, option) => String(option?.label || '').toLowerCase().includes(input.toLowerCase())} filterOption={(input, option) => String(option?.label || '').toLowerCase().includes(input.toLowerCase())}
/> />
<Space.Compact style={{ width: '100%' }}>
<Button disabled>PID</Button>
<Input <Input
addonBefore="PID"
value={selectedExchangeGoodsId} value={selectedExchangeGoodsId}
onChange={(event) => setSelectedExchangeGoodsId(event.target.value.trim())} onChange={(event) => setSelectedExchangeGoodsId(event.target.value.trim())}
placeholder="商品 PID" placeholder="商品 PID"
/> />
</Space.Compact>
<DatePicker <DatePicker
showTime showTime
allowClear allowClear
@@ -1747,7 +1752,7 @@ export default function HuyaTasksPage() {
</Button> </Button>
)} )}
> >
<Space direction="vertical" size={10} style={{ width: '100%' }}> <Space orientation="vertical" size={10} style={{ width: '100%' }}>
<Select <Select
showSearch showSearch
allowClear allowClear
@@ -1758,14 +1763,16 @@ export default function HuyaTasksPage() {
style={{ width: '100%' }} style={{ width: '100%' }}
filterOption={(input, option) => String(option?.label || '').toLowerCase().includes(input.toLowerCase())} filterOption={(input, option) => String(option?.label || '').toLowerCase().includes(input.toLowerCase())}
/> />
<Space.Compact style={{ width: '100%' }}>
<InputNumber <InputNumber
min={1} min={1}
max={999} max={999}
value={rechargeCount} value={rechargeCount}
onChange={(value) => setRechargeCount(value || 1)} onChange={(value) => setRechargeCount(value || 1)}
addonAfter="份"
style={{ width: '100%' }} style={{ width: '100%' }}
/> />
<Button disabled></Button>
</Space.Compact>
<Radio.Group value={rechargePayChannel} onChange={(event) => setRechargePayChannel(event.target.value)}> <Radio.Group value={rechargePayChannel} onChange={(event) => setRechargePayChannel(event.target.value)}>
<Radio value="Weixin"></Radio> <Radio value="Weixin"></Radio>
<Radio value="Zfb"></Radio> <Radio value="Zfb"></Radio>
@@ -1862,7 +1869,7 @@ export default function HuyaTasksPage() {
]} ]}
width={860} width={860}
> >
<Space direction="vertical" size={10} style={{ width: '100%' }}> <Space orientation="vertical" size={10} style={{ width: '100%' }}>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}> <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
<Input.Search <Input.Search
allowClear allowClear
@@ -1919,7 +1926,7 @@ export default function HuyaTasksPage() {
footer={null} footer={null}
width={760} width={760}
> >
<Space direction="vertical" size={10} style={{ width: '100%' }}> <Space orientation="vertical" size={10} style={{ width: '100%' }}>
<Text type="secondary"> <Text type="secondary">
{exchangeRecordsAccountName}{exchangeRecordsResult?.sid ? ` / SID ${String(exchangeRecordsResult.sid)}` : ''} {exchangeRecordsAccountName}{exchangeRecordsResult?.sid ? ` / SID ${String(exchangeRecordsResult.sid)}` : ''}
</Text> </Text>
@@ -1944,7 +1951,7 @@ export default function HuyaTasksPage() {
> >
{qrTask && ( {qrTask && (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12, padding: '8px 0 12px' }}> <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12, padding: '8px 0 12px' }}>
<Space direction="vertical" size={4} style={{ width: '100%', textAlign: 'center' }}> <Space orientation="vertical" size={4} style={{ width: '100%', textAlign: 'center' }}>
<Text strong>{qrAccountName}</Text> <Text strong>{qrAccountName}</Text>
<Tag <Tag
color={qrBindReady ? 'gold' : qrBindPhase === 'role_timeout' || qrQueryFinished ? 'orange' : 'processing'} color={qrBindReady ? 'gold' : qrBindPhase === 'role_timeout' || qrQueryFinished ? 'orange' : 'processing'}
@@ -1979,7 +1986,7 @@ export default function HuyaTasksPage() {
<Text type="secondary"></Text> <Text type="secondary"></Text>
)} )}
{qrRoleLine ? ( {qrRoleLine ? (
<Space direction="vertical" size={2} style={{ width: '100%', textAlign: 'center' }}> <Space orientation="vertical" size={2} style={{ width: '100%', textAlign: 'center' }}>
{qrGameTitle ? <Text type="secondary">{qrGameTitle}</Text> : null} {qrGameTitle ? <Text type="secondary">{qrGameTitle}</Text> : null}
<Text strong>{qrRoleLine}</Text> <Text strong>{qrRoleLine}</Text>
</Space> </Space>
@@ -2017,7 +2024,7 @@ export default function HuyaTasksPage() {
> >
{payTask && ( {payTask && (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12, padding: '8px 0 12px' }}> <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12, padding: '8px 0 12px' }}>
<Space direction="vertical" size={2} style={{ width: '100%', textAlign: 'center' }}> <Space orientation="vertical" size={2} style={{ width: '100%', textAlign: 'center' }}>
<Text strong>{payProductName || '充值商品'}</Text> <Text strong>{payProductName || '充值商品'}</Text>
<Text type="secondary"> <Text type="secondary">
{payChannelLabel || '支付'}{payAmountText ? ` / ${payAmountText}` : ''}{payAccountName ? ` / ${payAccountName}` : ''} {payChannelLabel || '支付'}{payAmountText ? ` / ${payAmountText}` : ''}{payAccountName ? ` / ${payAccountName}` : ''}
+2 -1
View File
@@ -1,5 +1,6 @@
import { useState } from 'react'; import { useState } from 'react';
import { Card, Form, Input, Button, message, Typography } from 'antd'; import { Card, Form, Input, Button, Typography } from 'antd';
import { message } from '../utils/antdMessage';
import { LockOutlined, UserOutlined } from '@ant-design/icons'; import { LockOutlined, UserOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { authApi } from '../api/modules'; import { authApi } from '../api/modules';
+11 -4
View File
@@ -1,7 +1,8 @@
import { useEffect, useState, useMemo, useCallback } from 'react'; import { useEffect, useState, useMemo, useCallback } from 'react';
import { import {
Table, Button, Select, message, Tag, Space, InputNumber, Tooltip, Popconfirm, theme, Modal, Form, Table, Button, Select, Tag, Space, InputNumber, Tooltip, Popconfirm, theme, Modal, Form,
} from 'antd'; } from 'antd';
import { message } from '../utils/antdMessage';
import { import {
PlayCircleOutlined, StopOutlined, FilterOutlined, ReloadOutlined, DeleteOutlined, PlayCircleOutlined, StopOutlined, FilterOutlined, ReloadOutlined, DeleteOutlined,
SettingOutlined, SafetyCertificateOutlined, SettingOutlined, SafetyCertificateOutlined,
@@ -503,19 +504,22 @@ export default function LoginTasksPage() {
label="并发数" label="并发数"
tooltip="同时登录的账号数。1 为顺序执行,最多 10。" tooltip="同时登录的账号数。1 为顺序执行,最多 10。"
> >
<Space.Compact>
<InputNumber <InputNumber
min={1} min={1}
max={10} max={10}
value={concurrency} value={concurrency}
onChange={(v) => setConcurrency(v || 1)} onChange={(v) => setConcurrency(v || 1)}
style={{ width: 120 }} style={{ width: 120 }}
addonAfter="个"
/> />
<Button disabled></Button>
</Space.Compact>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="单账号超时" label="单账号超时"
tooltip="单个账号登录的总时长上限,超时则放弃。0 表示不限。" tooltip="单个账号登录的总时长上限,超时则放弃。0 表示不限。"
> >
<Space.Compact>
<InputNumber <InputNumber
min={0} min={0}
max={3600} max={3600}
@@ -523,23 +527,26 @@ export default function LoginTasksPage() {
value={maxTotalTime} value={maxTotalTime}
onChange={(v) => setMaxTotalTime(v ?? 0)} onChange={(v) => setMaxTotalTime(v ?? 0)}
style={{ width: 120 }} style={{ width: 120 }}
addonAfter="秒"
placeholder="0=不限" placeholder="0=不限"
/> />
<Button disabled></Button>
</Space.Compact>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="登录整体重试次数" label="登录整体重试次数"
tooltip="单个账号最多重试多少轮(每轮换新代理)。0 表示无限重试直到成功或超时。" tooltip="单个账号最多重试多少轮(每轮换新代理)。0 表示无限重试直到成功或超时。"
> >
<Space.Compact>
<InputNumber <InputNumber
min={0} min={0}
max={50} max={50}
value={maxLoginRetries} value={maxLoginRetries}
onChange={(v) => setMaxLoginRetries(v ?? 0)} onChange={(v) => setMaxLoginRetries(v ?? 0)}
style={{ width: 120 }} style={{ width: 120 }}
addonAfter="次"
placeholder="0=无限" placeholder="0=无限"
/> />
<Button disabled></Button>
</Space.Compact>
</Form.Item> </Form.Item>
</Form> </Form>
</Modal> </Modal>
+2 -1
View File
@@ -1,5 +1,6 @@
import { useEffect, useState, useCallback } from 'react'; import { useEffect, useState, useCallback } from 'react';
import { Form, Input, Switch, Button, Card, Select, message, Row, Col } from 'antd'; import { Form, Input, Switch, Button, Card, Select, Row, Col } from 'antd';
import { message } from '../utils/antdMessage';
import { proxyApi, type ProxyConfig, type PlatformInfo } from '../api/modules'; import { proxyApi, type ProxyConfig, type PlatformInfo } from '../api/modules';
import RealtimeLogPanel from '../components/RealtimeLogPanel'; import RealtimeLogPanel from '../components/RealtimeLogPanel';
import { useWebSocketLogs } from '../hooks/useWebSocketLogs'; import { useWebSocketLogs } from '../hooks/useWebSocketLogs';
+2 -1
View File
@@ -1,8 +1,9 @@
import { useEffect, useState, useCallback } from 'react'; import { useEffect, useState, useCallback } from 'react';
import { import {
Table, Button, Modal, Form, Input, Select, Tag, Popconfirm, message, Space, Table, Button, Modal, Form, Input, Select, Tag, Popconfirm, Space,
Checkbox, Divider, Alert, Tooltip, Checkbox, Divider, Alert, Tooltip,
} from 'antd'; } from 'antd';
import { message } from '../utils/antdMessage';
import { PlusOutlined, EditOutlined, DeleteOutlined, SafetyOutlined } from '@ant-design/icons'; import { PlusOutlined, EditOutlined, DeleteOutlined, SafetyOutlined } from '@ant-design/icons';
import { userApi, type UserInfo } from '../api/modules'; import { userApi, type UserInfo } from '../api/modules';
import { usePermissions } from '../hooks/usePermissions'; import { usePermissions } from '../hooks/usePermissions';
@@ -0,0 +1,16 @@
import { useEffect } from 'react';
import { App as AntdApp } from 'antd';
import { setAntdMessageApi } from './antdMessage';
export default function AntdMessageBridge() {
const { message } = AntdApp.useApp();
useEffect(() => {
setAntdMessageApi(message);
return () => {
setAntdMessageApi(null);
};
}, [message]);
return null;
}
+38
View File
@@ -0,0 +1,38 @@
import type { Key } from 'react';
import type {
ArgsProps,
JointContent,
MessageInstance,
MessageType,
TypeOpen,
} from 'antd/es/message/interface';
let messageApi: MessageInstance | null = null;
const noopMessage = Object.assign(() => undefined, {
then: (
onfulfilled?: ((value: boolean) => unknown) | null,
onrejected?: ((reason: unknown) => unknown) | null,
) => Promise.resolve(true).then(onfulfilled ?? undefined, onrejected ?? undefined),
}) as MessageType;
function createTypeOpen(type: 'info' | 'success' | 'error' | 'warning' | 'loading'): TypeOpen {
return (content: JointContent, duration?: number | VoidFunction, onClose?: VoidFunction) => {
if (!messageApi) return noopMessage;
return messageApi[type](content, duration, onClose);
};
}
export function setAntdMessageApi(api: MessageInstance | null) {
messageApi = api;
}
export const message = {
info: createTypeOpen('info'),
success: createTypeOpen('success'),
error: createTypeOpen('error'),
warning: createTypeOpen('warning'),
loading: createTypeOpen('loading'),
open: (args: ArgsProps) => messageApi?.open(args) ?? noopMessage,
destroy: (key?: Key) => messageApi?.destroy(key),
} satisfies MessageInstance;