优化任务操作台交互体验
This commit is contained in:
@@ -24,7 +24,7 @@ SUPPORTED_DOUYU_TASK_TYPES = {
|
|||||||
"query_game_name": "一键获取游戏名",
|
"query_game_name": "一键获取游戏名",
|
||||||
"query_change_bind_time": "一键查询换绑时间",
|
"query_change_bind_time": "一键查询换绑时间",
|
||||||
"query_limited_goods": "一键查询限兑商品",
|
"query_limited_goods": "一键查询限兑商品",
|
||||||
"query_gold_balance": "一键查询鱼刺余额",
|
"query_gold_balance": "一键查询鱼翅余额",
|
||||||
"refresh_goods": "刷新商品列表",
|
"refresh_goods": "刷新商品列表",
|
||||||
"query_exchange_records": "一键查询兑换记录",
|
"query_exchange_records": "一键查询兑换记录",
|
||||||
"prefetch_csrf_token": "一键获取兑换 CSRF Token",
|
"prefetch_csrf_token": "一键获取兑换 CSRF Token",
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ const QUICK_ACTIONS = [
|
|||||||
{ key: 'donate_elite_gift', icon: <GiftOutlined /> },
|
{ key: 'donate_elite_gift', icon: <GiftOutlined /> },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const BIND_ACTION_KEYS = ['get_bind_qr', 'confirm_bind', 'query_game_name', 'query_change_bind_time'];
|
||||||
|
const QUERY_ACTION_KEYS = ['query_points', 'query_limited_goods', 'query_gold_balance'];
|
||||||
|
|
||||||
const STATUS_COLORS: Record<string, string> = {
|
const STATUS_COLORS: Record<string, string> = {
|
||||||
planned: 'default', pending: 'default', running: 'processing',
|
planned: 'default', pending: 'default', running: 'processing',
|
||||||
success: 'success', failed: 'error', error: 'error', stopped: 'warning',
|
success: 'success', failed: 'error', error: 'error', stopped: 'warning',
|
||||||
@@ -680,6 +683,48 @@ export default function DouyuTasksPage() {
|
|||||||
const payAccountName = payTask
|
const payAccountName = payTask
|
||||||
? (payTask.account_nickname || payTask.account_username || payTask.account_uid || `#${payTask.account_id}`)
|
? (payTask.account_nickname || payTask.account_username || payTask.account_uid || `#${payTask.account_id}`)
|
||||||
: '';
|
: '';
|
||||||
|
const selectedText = selectedIds.length > 0 ? `已选 ${selectedIds.length} 个账号` : '请先勾选账号';
|
||||||
|
const actionByKey = useMemo(() => new Map(QUICK_ACTIONS.map((item) => [item.key, item])), []);
|
||||||
|
const actionDisabled = (taskType: string) => {
|
||||||
|
if (batchBusy || selectedIds.length === 0) return true;
|
||||||
|
if (taskType === 'exchange_goods') return !selectedGoodsId;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
const renderActionButton = (taskType: string, type: 'default' | 'primary' = 'default') => {
|
||||||
|
const item = actionByKey.get(taskType);
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
key={taskType}
|
||||||
|
size="small"
|
||||||
|
block
|
||||||
|
type={type}
|
||||||
|
icon={item?.icon}
|
||||||
|
onClick={() => startTask(taskType)}
|
||||||
|
disabled={actionDisabled(taskType)}
|
||||||
|
style={{ justifyContent: 'flex-start' }}
|
||||||
|
>
|
||||||
|
{taskTypes[taskType] || taskType}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const sectionStyle = {
|
||||||
|
border: '1px solid #f0f0f0',
|
||||||
|
borderRadius: 6,
|
||||||
|
padding: 8,
|
||||||
|
background: '#fff',
|
||||||
|
};
|
||||||
|
const sectionTitleStyle = {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 6,
|
||||||
|
marginBottom: 8,
|
||||||
|
fontWeight: 600,
|
||||||
|
};
|
||||||
|
const actionGridStyle = {
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1fr 1fr',
|
||||||
|
gap: 6,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: '100%', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
|
<div style={{ height: '100%', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
|
||||||
@@ -765,63 +810,113 @@ export default function DouyuTasksPage() {
|
|||||||
|
|
||||||
{/* Right: operations + logs */}
|
{/* Right: operations + logs */}
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, overflow: 'auto' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, overflow: 'auto' }}>
|
||||||
<Card size="small" title="操作" styles={{ body: { padding: 8 } }}>
|
<Card
|
||||||
|
size="small"
|
||||||
|
title="操作"
|
||||||
|
extra={<Tag color={selectedIds.length ? 'blue' : 'default'}>{selectedText}</Tag>}
|
||||||
|
styles={{ body: { padding: 8 } }}
|
||||||
|
>
|
||||||
<Space direction="vertical" style={{ width: '100%' }} size={8}>
|
<Space direction="vertical" style={{ width: '100%' }} size={8}>
|
||||||
<Space style={{ width: '100%', justifyContent: 'space-between' }}>
|
<Space.Compact style={{ width: '100%' }}>
|
||||||
<Text type="secondary">{selectedIds.length > 0 ? `已选 ${selectedIds.length} 个账号` : '点击/右键选择账号'}</Text>
|
<Button size="small" disabled>并发</Button>
|
||||||
<InputNumber size="small" min={1} max={10} value={concurrency} onChange={(v) => setConcurrency(v || 1)} style={{ width: 70 }} addonBefore="并发" />
|
<InputNumber
|
||||||
</Space>
|
size="small"
|
||||||
<Space wrap size={4}>
|
min={1}
|
||||||
{QUICK_ACTIONS.map((item) => (
|
max={10}
|
||||||
<Button
|
value={concurrency}
|
||||||
key={item.key} size="small" icon={item.icon}
|
onChange={(v) => setConcurrency(v || 1)}
|
||||||
onClick={() => startTask(item.key)}
|
style={{ width: '100%' }}
|
||||||
disabled={batchBusy || selectedIds.length === 0}
|
/>
|
||||||
>
|
</Space.Compact>
|
||||||
{taskTypes[item.key] || item.key}
|
|
||||||
</Button>
|
<div style={sectionStyle}>
|
||||||
))}
|
<div style={sectionTitleStyle}>
|
||||||
</Space>
|
<QrcodeOutlined />
|
||||||
<Card size="small" title="兑换" styles={{ body: { padding: 8 } }}>
|
<span>绑定与角色</span>
|
||||||
<Space direction="vertical" style={{ width: '100%' }}>
|
</div>
|
||||||
|
<div style={actionGridStyle}>
|
||||||
|
{BIND_ACTION_KEYS.map((key) => renderActionButton(key))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={sectionStyle}>
|
||||||
|
<div style={sectionTitleStyle}>
|
||||||
|
<SearchOutlined />
|
||||||
|
<span>查询</span>
|
||||||
|
</div>
|
||||||
|
<Space direction="vertical" style={{ width: '100%' }} size={6}>
|
||||||
|
{QUERY_ACTION_KEYS.map((key) => renderActionButton(key))}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={sectionStyle}>
|
||||||
|
<div style={sectionTitleStyle}>
|
||||||
|
<ShoppingOutlined />
|
||||||
|
<span>兑换</span>
|
||||||
|
</div>
|
||||||
|
<Space direction="vertical" style={{ width: '100%' }} size={6}>
|
||||||
<Select
|
<Select
|
||||||
size="small" value={selectedGoodsId || undefined} onChange={setSelectedGoodsId}
|
size="small"
|
||||||
|
value={selectedGoodsId || undefined}
|
||||||
|
onChange={setSelectedGoodsId}
|
||||||
options={goods.map((item) => ({ value: item.commodity_id, label: goodsLabel(item) }))}
|
options={goods.map((item) => ({ value: item.commodity_id, label: goodsLabel(item) }))}
|
||||||
placeholder="选择兑换商品" showSearch optionFilterProp="label"
|
placeholder="选择兑换商品"
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="label"
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
/>
|
/>
|
||||||
<Space>
|
<div style={actionGridStyle}>
|
||||||
<Button size="small" icon={<ReloadOutlined />} onClick={() => startTask('refresh_goods')} disabled={batchBusy || selectedIds.length === 0}>
|
{renderActionButton('refresh_goods')}
|
||||||
刷新商品
|
{renderActionButton('exchange_goods', 'primary')}
|
||||||
</Button>
|
</div>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={sectionStyle}>
|
||||||
|
<div style={sectionTitleStyle}>
|
||||||
|
<CreditCardOutlined />
|
||||||
|
<span>充值与送礼</span>
|
||||||
|
</div>
|
||||||
|
<Space direction="vertical" style={{ width: '100%' }} size={6}>
|
||||||
|
<Space.Compact style={{ width: '100%' }}>
|
||||||
|
<InputNumber
|
||||||
|
size="small"
|
||||||
|
min={1}
|
||||||
|
value={goldAmount}
|
||||||
|
onChange={(v) => setGoldAmount(v || 1)}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
type="primary"
|
icon={<CreditCardOutlined />}
|
||||||
icon={<ShoppingOutlined />}
|
onClick={() => startTask('create_gold_qr')}
|
||||||
onClick={() => startTask('exchange_goods')}
|
disabled={actionDisabled('create_gold_qr')}
|
||||||
disabled={batchBusy || selectedIds.length === 0 || !selectedGoodsId}
|
|
||||||
>
|
>
|
||||||
兑换商品
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
</Space>
|
|
||||||
</Card>
|
|
||||||
<Card size="small" title="充值与送礼" styles={{ body: { padding: 8 } }}>
|
|
||||||
<Space direction="vertical" style={{ width: '100%' }}>
|
|
||||||
<Space>
|
|
||||||
<InputNumber size="small" min={1} value={goldAmount} onChange={(v) => setGoldAmount(v || 1)} style={{ width: 80 }} />
|
|
||||||
<Button size="small" icon={<CreditCardOutlined />} onClick={() => startTask('create_gold_qr')} disabled={batchBusy || selectedIds.length === 0}>
|
|
||||||
充值鱼翅
|
充值鱼翅
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space.Compact>
|
||||||
<Space>
|
<Space.Compact style={{ width: '100%' }}>
|
||||||
<InputNumber size="small" min={1} value={giftCount} onChange={(v) => setGiftCount(v || 1)} style={{ width: 80 }} />
|
<InputNumber
|
||||||
<Button size="small" icon={<GiftOutlined />} onClick={() => startTask('donate_elite_gift')} disabled={batchBusy || selectedIds.length === 0}>
|
size="small"
|
||||||
|
min={1}
|
||||||
|
value={giftCount}
|
||||||
|
onChange={(v) => setGiftCount(v || 1)}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
icon={<GiftOutlined />}
|
||||||
|
onClick={() => startTask('donate_elite_gift')}
|
||||||
|
disabled={actionDisabled('donate_elite_gift')}
|
||||||
|
>
|
||||||
赠送精英令
|
赠送精英令
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space.Compact>
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</div>
|
||||||
|
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||||
|
勾选账号后可批量执行;右键账号行可快速执行单账号动作。
|
||||||
|
</Text>
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ const QUICK_ACTIONS = [
|
|||||||
{ key: 'create_recharge_order', icon: <CreditCardOutlined /> },
|
{ key: 'create_recharge_order', icon: <CreditCardOutlined /> },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const BATCH_COMPATIBLE_TASK_TYPES = new Set(['confirm_bind', 'query_game_name']);
|
||||||
|
|
||||||
|
function canRunDuringBatch(taskType: string): boolean {
|
||||||
|
return BATCH_COMPATIBLE_TASK_TYPES.has(taskType);
|
||||||
|
}
|
||||||
|
|
||||||
const STATUS_COLORS: Record<string, string> = {
|
const STATUS_COLORS: Record<string, string> = {
|
||||||
planned: 'default',
|
planned: 'default',
|
||||||
pending: 'default',
|
pending: 'default',
|
||||||
@@ -106,6 +112,29 @@ const ACCOUNT_STATUS_COLORS: Record<string, string> = {
|
|||||||
recharge_order_created: 'processing',
|
recharge_order_created: 'processing',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const HUYA_WORKBENCH_ACCOUNT_IDS_KEY = 'huya_task_workbench_account_ids';
|
||||||
|
|
||||||
|
function readWorkbenchAccountIds(): number[] {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(HUYA_WORKBENCH_ACCOUNT_IDS_KEY);
|
||||||
|
if (!raw) return [];
|
||||||
|
const values = JSON.parse(raw);
|
||||||
|
if (!Array.isArray(values)) return [];
|
||||||
|
return Array.from(new Set(values.map((value) => Number(value)).filter((value) => Number.isInteger(value) && value > 0)));
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveWorkbenchAccountIds(ids: number[]) {
|
||||||
|
const normalized = Array.from(new Set(ids.filter((id) => Number.isInteger(id) && id > 0)));
|
||||||
|
if (normalized.length === 0) {
|
||||||
|
localStorage.removeItem(HUYA_WORKBENCH_ACCOUNT_IDS_KEY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
localStorage.setItem(HUYA_WORKBENCH_ACCOUNT_IDS_KEY, JSON.stringify(normalized));
|
||||||
|
}
|
||||||
|
|
||||||
function accountLabel(account: HuyaAccountItem): string {
|
function accountLabel(account: HuyaAccountItem): string {
|
||||||
const name = account.nickname || account.username || account.uid || `#${account.id}`;
|
const name = account.nickname || account.username || account.uid || `#${account.id}`;
|
||||||
const tag = account.tag ? ` [${account.tag}]` : '';
|
const tag = account.tag ? ` [${account.tag}]` : '';
|
||||||
@@ -155,29 +184,6 @@ function taskProductText(task: HuyaTaskItem | null | undefined): string {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInteractiveTarget(target: EventTarget | null): boolean {
|
|
||||||
const element = target instanceof HTMLElement ? target : null;
|
|
||||||
if (!element) return false;
|
|
||||||
return Boolean(element.closest([
|
|
||||||
'a',
|
|
||||||
'button',
|
|
||||||
'input',
|
|
||||||
'textarea',
|
|
||||||
'select',
|
|
||||||
'[role="button"]',
|
|
||||||
'[role="menuitem"]',
|
|
||||||
'.ant-btn',
|
|
||||||
'.ant-checkbox',
|
|
||||||
'.ant-checkbox-wrapper',
|
|
||||||
'.ant-dropdown',
|
|
||||||
'.ant-dropdown-menu',
|
|
||||||
'.ant-input',
|
|
||||||
'.ant-picker',
|
|
||||||
'.ant-select',
|
|
||||||
'.ant-table-column-sorter',
|
|
||||||
].join(',')));
|
|
||||||
}
|
|
||||||
|
|
||||||
function contextMenuPosition(x: number, y: number) {
|
function contextMenuPosition(x: number, y: number) {
|
||||||
if (typeof window === 'undefined') return { left: x, top: y };
|
if (typeof window === 'undefined') return { left: x, top: y };
|
||||||
return {
|
return {
|
||||||
@@ -405,11 +411,15 @@ export default function HuyaTasksPage() {
|
|||||||
const nextPool = accountResult.value;
|
const nextPool = accountResult.value;
|
||||||
const nextPoolById = new Map(nextPool.map((account) => [account.id, account]));
|
const nextPoolById = new Map(nextPool.map((account) => [account.id, account]));
|
||||||
setAccountPool(nextPool);
|
setAccountPool(nextPool);
|
||||||
setAccounts((prev) => (
|
setAccounts((prev) => {
|
||||||
prev
|
const persistedIds = readWorkbenchAccountIds();
|
||||||
.map((account) => nextPoolById.get(account.id))
|
const sourceIds = prev.length > 0 ? prev.map((account) => account.id) : persistedIds;
|
||||||
.filter((account): account is HuyaAccountItem => Boolean(account))
|
const nextAccounts = sourceIds
|
||||||
));
|
.map((id) => nextPoolById.get(id))
|
||||||
|
.filter((account): account is HuyaAccountItem => Boolean(account));
|
||||||
|
saveWorkbenchAccountIds(nextAccounts.map((account) => account.id));
|
||||||
|
return nextAccounts;
|
||||||
|
});
|
||||||
setSelectedIds((prev) => prev.filter((id) => nextPoolById.has(id)));
|
setSelectedIds((prev) => prev.filter((id) => nextPoolById.has(id)));
|
||||||
}
|
}
|
||||||
if (taskResult.status === 'fulfilled') {
|
if (taskResult.status === 'fulfilled') {
|
||||||
@@ -529,14 +539,6 @@ export default function HuyaTasksPage() {
|
|||||||
};
|
};
|
||||||
}, [accountContextMenu]);
|
}, [accountContextMenu]);
|
||||||
|
|
||||||
const toggleAccountSelection = useCallback((accountId: number) => {
|
|
||||||
setSelectedIds((prev) => (
|
|
||||||
prev.includes(accountId)
|
|
||||||
? prev.filter((id) => id !== accountId)
|
|
||||||
: [...prev, accountId]
|
|
||||||
));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const tagColorMap = useMemo(() => {
|
const tagColorMap = useMemo(() => {
|
||||||
const map: Record<string, string> = {};
|
const map: Record<string, string> = {};
|
||||||
tags.forEach((tag, index) => {
|
tags.forEach((tag, index) => {
|
||||||
@@ -644,6 +646,11 @@ export default function HuyaTasksPage() {
|
|||||||
}, [tasks]);
|
}, [tasks]);
|
||||||
const activeBatchId = runningTaskBatchId || (wsConnected ? batchId : null);
|
const activeBatchId = runningTaskBatchId || (wsConnected ? batchId : null);
|
||||||
const batchBusy = Boolean(activeBatchId);
|
const batchBusy = Boolean(activeBatchId);
|
||||||
|
const isTaskActionDisabled = useCallback((taskType: string, accountIds = selectedIds) => (
|
||||||
|
!canTask
|
||||||
|
|| accountIds.length === 0
|
||||||
|
|| ((batchBusy || wsConnected) && !canRunDuringBatch(taskType))
|
||||||
|
), [batchBusy, canTask, selectedIds, wsConnected]);
|
||||||
|
|
||||||
const sortedGoods = useMemo(() => {
|
const sortedGoods = useMemo(() => {
|
||||||
return [...goods].sort((a, b) => (
|
return [...goods].sort((a, b) => (
|
||||||
@@ -755,7 +762,7 @@ export default function HuyaTasksPage() {
|
|||||||
message.warning('请先选择虎牙 CK');
|
message.warning('请先选择虎牙 CK');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (activeBatchId) {
|
if ((activeBatchId || wsConnected) && !canRunDuringBatch(taskType)) {
|
||||||
message.warning('当前已有虎牙批次在运行,请先停止或等待结束');
|
message.warning('当前已有虎牙批次在运行,请先停止或等待结束');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -860,6 +867,7 @@ export default function HuyaTasksPage() {
|
|||||||
if (account) nextAccounts.push(account);
|
if (account) nextAccounts.push(account);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
saveWorkbenchAccountIds(nextAccounts.map((account) => account.id));
|
||||||
return nextAccounts;
|
return nextAccounts;
|
||||||
});
|
});
|
||||||
setSelectedIds(uniqueIds);
|
setSelectedIds(uniqueIds);
|
||||||
@@ -874,12 +882,17 @@ export default function HuyaTasksPage() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selected = new Set(selectedIds);
|
const selected = new Set(selectedIds);
|
||||||
setAccounts((prev) => prev.filter((account) => !selected.has(account.id)));
|
setAccounts((prev) => {
|
||||||
|
const nextAccounts = prev.filter((account) => !selected.has(account.id));
|
||||||
|
saveWorkbenchAccountIds(nextAccounts.map((account) => account.id));
|
||||||
|
return nextAccounts;
|
||||||
|
});
|
||||||
setSelectedIds([]);
|
setSelectedIds([]);
|
||||||
setAccountContextMenu(null);
|
setAccountContextMenu(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearWorkbenchAccounts = () => {
|
const clearWorkbenchAccounts = () => {
|
||||||
|
saveWorkbenchAccountIds([]);
|
||||||
setAccounts([]);
|
setAccounts([]);
|
||||||
setSelectedIds([]);
|
setSelectedIds([]);
|
||||||
setAccountContextMenu(null);
|
setAccountContextMenu(null);
|
||||||
@@ -981,20 +994,12 @@ export default function HuyaTasksPage() {
|
|||||||
: '';
|
: '';
|
||||||
const confirmQrBind = () => {
|
const confirmQrBind = () => {
|
||||||
if (!qrTask || !qrBindReady) return;
|
if (!qrTask || !qrBindReady) return;
|
||||||
if (batchBusy) {
|
|
||||||
message.warning('当前已有虎牙批次在运行,请先停止或等待结束');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const accountId = qrTask.account_id;
|
const accountId = qrTask.account_id;
|
||||||
setQrTask(null);
|
setQrTask(null);
|
||||||
void startTask('confirm_bind', [accountId]);
|
void startTask('confirm_bind', [accountId]);
|
||||||
};
|
};
|
||||||
const queryQrRole = () => {
|
const queryQrRole = () => {
|
||||||
if (!qrTask) return;
|
if (!qrTask) return;
|
||||||
if (batchBusy) {
|
|
||||||
message.warning('当前已有虎牙批次在运行,请先停止或等待结束');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const accountId = qrTask.account_id;
|
const accountId = qrTask.account_id;
|
||||||
void startTask('query_game_name', [accountId]);
|
void startTask('query_game_name', [accountId]);
|
||||||
};
|
};
|
||||||
@@ -1134,14 +1139,7 @@ export default function HuyaTasksPage() {
|
|||||||
return value ? <Text code style={{ fontSize: 12 }}>{JSON.stringify(value)}</Text> : <Text type="secondary">-</Text>;
|
return value ? <Text code style={{ fontSize: 12 }}>{JSON.stringify(value)}</Text> : <Text type="secondary">-</Text>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAccountRowClick = (record: HuyaAccountItem, event: ReactMouseEvent) => {
|
|
||||||
if (isInteractiveTarget(event.target)) return;
|
|
||||||
setAccountContextMenu(null);
|
|
||||||
toggleAccountSelection(record.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAccountRowContextMenu = (record: HuyaAccountItem, event: ReactMouseEvent) => {
|
const handleAccountRowContextMenu = (record: HuyaAccountItem, event: ReactMouseEvent) => {
|
||||||
if (isInteractiveTarget(event.target)) return;
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const accountIds = selectedIds.includes(record.id) && selectedIds.length > 0 ? selectedIds : [record.id];
|
const accountIds = selectedIds.includes(record.id) && selectedIds.length > 0 ? selectedIds : [record.id];
|
||||||
@@ -1282,7 +1280,7 @@ export default function HuyaTasksPage() {
|
|||||||
}}
|
}}
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
>
|
>
|
||||||
<Button size="small" icon={<MoreOutlined />} disabled={!canTask || batchBusy || wsConnected} />
|
<Button size="small" icon={<MoreOutlined />} disabled={!canTask} />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -1491,7 +1489,7 @@ export default function HuyaTasksPage() {
|
|||||||
size="small"
|
size="small"
|
||||||
block
|
block
|
||||||
icon={item.icon}
|
icon={item.icon}
|
||||||
disabled={!canTask || batchBusy || wsConnected}
|
disabled={isTaskActionDisabled(item.key, accountContextMenu.accountIds)}
|
||||||
onClick={() => runContextAccountAction(item.key)}
|
onClick={() => runContextAccountAction(item.key)}
|
||||||
style={{ justifyContent: 'flex-start' }}
|
style={{ justifyContent: 'flex-start' }}
|
||||||
>
|
>
|
||||||
@@ -1585,10 +1583,9 @@ export default function HuyaTasksPage() {
|
|||||||
}}
|
}}
|
||||||
rowClassName={(record) => selectedIds.includes(record.id) ? 'ant-table-row-selected' : ''}
|
rowClassName={(record) => selectedIds.includes(record.id) ? 'ant-table-row-selected' : ''}
|
||||||
onRow={(record) => ({
|
onRow={(record) => ({
|
||||||
onClick: (event) => handleAccountRowClick(record, event),
|
|
||||||
onContextMenu: (event) => handleAccountRowContextMenu(record, event),
|
onContextMenu: (event) => handleAccountRowContextMenu(record, event),
|
||||||
style: { cursor: 'pointer' },
|
style: { cursor: 'context-menu' },
|
||||||
title: '点击选中,右键打开账号动作',
|
title: '右键打开账号动作',
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -1651,7 +1648,7 @@ export default function HuyaTasksPage() {
|
|||||||
block
|
block
|
||||||
icon={<PlayCircleOutlined />}
|
icon={<PlayCircleOutlined />}
|
||||||
loading={starting}
|
loading={starting}
|
||||||
disabled={!canTask || selectedIds.length === 0 || batchBusy || wsConnected}
|
disabled={isTaskActionDisabled(selectedTaskType)}
|
||||||
onClick={() => startTask()}
|
onClick={() => startTask()}
|
||||||
>
|
>
|
||||||
创建任务
|
创建任务
|
||||||
@@ -1664,7 +1661,7 @@ export default function HuyaTasksPage() {
|
|||||||
<Button
|
<Button
|
||||||
icon={item.icon}
|
icon={item.icon}
|
||||||
onClick={() => startTask(item.key)}
|
onClick={() => startTask(item.key)}
|
||||||
disabled={!canTask || selectedIds.length === 0 || batchBusy || wsConnected}
|
disabled={isTaskActionDisabled(item.key)}
|
||||||
>
|
>
|
||||||
{taskTypes[item.key] || item.key}
|
{taskTypes[item.key] || item.key}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1904,17 +1901,6 @@ export default function HuyaTasksPage() {
|
|||||||
scroll={{ x: 720, y: 360 }}
|
scroll={{ x: 720, y: 360 }}
|
||||||
locale={{ emptyText: '没有可导入账号' }}
|
locale={{ emptyText: '没有可导入账号' }}
|
||||||
rowClassName={(record) => importSelectedIds.includes(record.id) ? 'ant-table-row-selected' : ''}
|
rowClassName={(record) => importSelectedIds.includes(record.id) ? 'ant-table-row-selected' : ''}
|
||||||
onRow={(record) => ({
|
|
||||||
onClick: (event) => {
|
|
||||||
if (isInteractiveTarget(event.target)) return;
|
|
||||||
setImportSelectedIds((prev) => (
|
|
||||||
prev.includes(record.id)
|
|
||||||
? prev.filter((id) => id !== record.id)
|
|
||||||
: [...prev, record.id]
|
|
||||||
));
|
|
||||||
},
|
|
||||||
style: { cursor: 'pointer' },
|
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
Reference in New Issue
Block a user