优化任务操作台交互体验
This commit is contained in:
@@ -50,6 +50,12 @@ const QUICK_ACTIONS = [
|
||||
{ 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> = {
|
||||
planned: 'default',
|
||||
pending: 'default',
|
||||
@@ -106,6 +112,29 @@ const ACCOUNT_STATUS_COLORS: Record<string, string> = {
|
||||
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 {
|
||||
const name = account.nickname || account.username || account.uid || `#${account.id}`;
|
||||
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) {
|
||||
if (typeof window === 'undefined') return { left: x, top: y };
|
||||
return {
|
||||
@@ -405,11 +411,15 @@ export default function HuyaTasksPage() {
|
||||
const nextPool = accountResult.value;
|
||||
const nextPoolById = new Map(nextPool.map((account) => [account.id, account]));
|
||||
setAccountPool(nextPool);
|
||||
setAccounts((prev) => (
|
||||
prev
|
||||
.map((account) => nextPoolById.get(account.id))
|
||||
.filter((account): account is HuyaAccountItem => Boolean(account))
|
||||
));
|
||||
setAccounts((prev) => {
|
||||
const persistedIds = readWorkbenchAccountIds();
|
||||
const sourceIds = prev.length > 0 ? prev.map((account) => account.id) : persistedIds;
|
||||
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)));
|
||||
}
|
||||
if (taskResult.status === 'fulfilled') {
|
||||
@@ -529,14 +539,6 @@ export default function HuyaTasksPage() {
|
||||
};
|
||||
}, [accountContextMenu]);
|
||||
|
||||
const toggleAccountSelection = useCallback((accountId: number) => {
|
||||
setSelectedIds((prev) => (
|
||||
prev.includes(accountId)
|
||||
? prev.filter((id) => id !== accountId)
|
||||
: [...prev, accountId]
|
||||
));
|
||||
}, []);
|
||||
|
||||
const tagColorMap = useMemo(() => {
|
||||
const map: Record<string, string> = {};
|
||||
tags.forEach((tag, index) => {
|
||||
@@ -644,6 +646,11 @@ export default function HuyaTasksPage() {
|
||||
}, [tasks]);
|
||||
const activeBatchId = runningTaskBatchId || (wsConnected ? batchId : null);
|
||||
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(() => {
|
||||
return [...goods].sort((a, b) => (
|
||||
@@ -755,7 +762,7 @@ export default function HuyaTasksPage() {
|
||||
message.warning('请先选择虎牙 CK');
|
||||
return;
|
||||
}
|
||||
if (activeBatchId) {
|
||||
if ((activeBatchId || wsConnected) && !canRunDuringBatch(taskType)) {
|
||||
message.warning('当前已有虎牙批次在运行,请先停止或等待结束');
|
||||
return;
|
||||
}
|
||||
@@ -860,6 +867,7 @@ export default function HuyaTasksPage() {
|
||||
if (account) nextAccounts.push(account);
|
||||
}
|
||||
});
|
||||
saveWorkbenchAccountIds(nextAccounts.map((account) => account.id));
|
||||
return nextAccounts;
|
||||
});
|
||||
setSelectedIds(uniqueIds);
|
||||
@@ -874,12 +882,17 @@ export default function HuyaTasksPage() {
|
||||
return;
|
||||
}
|
||||
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([]);
|
||||
setAccountContextMenu(null);
|
||||
};
|
||||
|
||||
const clearWorkbenchAccounts = () => {
|
||||
saveWorkbenchAccountIds([]);
|
||||
setAccounts([]);
|
||||
setSelectedIds([]);
|
||||
setAccountContextMenu(null);
|
||||
@@ -981,20 +994,12 @@ export default function HuyaTasksPage() {
|
||||
: '';
|
||||
const confirmQrBind = () => {
|
||||
if (!qrTask || !qrBindReady) return;
|
||||
if (batchBusy) {
|
||||
message.warning('当前已有虎牙批次在运行,请先停止或等待结束');
|
||||
return;
|
||||
}
|
||||
const accountId = qrTask.account_id;
|
||||
setQrTask(null);
|
||||
void startTask('confirm_bind', [accountId]);
|
||||
};
|
||||
const queryQrRole = () => {
|
||||
if (!qrTask) return;
|
||||
if (batchBusy) {
|
||||
message.warning('当前已有虎牙批次在运行,请先停止或等待结束');
|
||||
return;
|
||||
}
|
||||
const accountId = qrTask.account_id;
|
||||
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>;
|
||||
};
|
||||
|
||||
const handleAccountRowClick = (record: HuyaAccountItem, event: ReactMouseEvent) => {
|
||||
if (isInteractiveTarget(event.target)) return;
|
||||
setAccountContextMenu(null);
|
||||
toggleAccountSelection(record.id);
|
||||
};
|
||||
|
||||
const handleAccountRowContextMenu = (record: HuyaAccountItem, event: ReactMouseEvent) => {
|
||||
if (isInteractiveTarget(event.target)) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const accountIds = selectedIds.includes(record.id) && selectedIds.length > 0 ? selectedIds : [record.id];
|
||||
@@ -1282,7 +1280,7 @@ export default function HuyaTasksPage() {
|
||||
}}
|
||||
trigger={['click']}
|
||||
>
|
||||
<Button size="small" icon={<MoreOutlined />} disabled={!canTask || batchBusy || wsConnected} />
|
||||
<Button size="small" icon={<MoreOutlined />} disabled={!canTask} />
|
||||
</Dropdown>
|
||||
);
|
||||
},
|
||||
@@ -1491,7 +1489,7 @@ export default function HuyaTasksPage() {
|
||||
size="small"
|
||||
block
|
||||
icon={item.icon}
|
||||
disabled={!canTask || batchBusy || wsConnected}
|
||||
disabled={isTaskActionDisabled(item.key, accountContextMenu.accountIds)}
|
||||
onClick={() => runContextAccountAction(item.key)}
|
||||
style={{ justifyContent: 'flex-start' }}
|
||||
>
|
||||
@@ -1585,10 +1583,9 @@ export default function HuyaTasksPage() {
|
||||
}}
|
||||
rowClassName={(record) => selectedIds.includes(record.id) ? 'ant-table-row-selected' : ''}
|
||||
onRow={(record) => ({
|
||||
onClick: (event) => handleAccountRowClick(record, event),
|
||||
onContextMenu: (event) => handleAccountRowContextMenu(record, event),
|
||||
style: { cursor: 'pointer' },
|
||||
title: '点击选中,右键打开账号动作',
|
||||
style: { cursor: 'context-menu' },
|
||||
title: '右键打开账号动作',
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
@@ -1651,7 +1648,7 @@ export default function HuyaTasksPage() {
|
||||
block
|
||||
icon={<PlayCircleOutlined />}
|
||||
loading={starting}
|
||||
disabled={!canTask || selectedIds.length === 0 || batchBusy || wsConnected}
|
||||
disabled={isTaskActionDisabled(selectedTaskType)}
|
||||
onClick={() => startTask()}
|
||||
>
|
||||
创建任务
|
||||
@@ -1664,7 +1661,7 @@ export default function HuyaTasksPage() {
|
||||
<Button
|
||||
icon={item.icon}
|
||||
onClick={() => startTask(item.key)}
|
||||
disabled={!canTask || selectedIds.length === 0 || batchBusy || wsConnected}
|
||||
disabled={isTaskActionDisabled(item.key)}
|
||||
>
|
||||
{taskTypes[item.key] || item.key}
|
||||
</Button>
|
||||
@@ -1904,17 +1901,6 @@ export default function HuyaTasksPage() {
|
||||
scroll={{ x: 720, y: 360 }}
|
||||
locale={{ emptyText: '没有可导入账号' }}
|
||||
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>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user