优化斗鱼任务操作体验

This commit is contained in:
yml2213
2026-07-25 11:58:30 +08:00
parent 6ca7898520
commit 63962811f8
2 changed files with 113 additions and 13 deletions
+41 -11
View File
@@ -40,6 +40,8 @@ const QUICK_ACTIONS = [
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 DOUYU_GOLD_AMOUNT_STORAGE_KEY = 'douyu_task_gold_amount';
const DOUYU_GIFT_COUNT_STORAGE_KEY = 'douyu_task_gift_count';
const STATUS_COLORS: Record<string, string> = {
planned: 'default', pending: 'default', running: 'processing',
@@ -98,6 +100,12 @@ function hasPaymentQrcode(task: DouyuTaskItem | null | undefined): boolean {
return Boolean(task && ['create_elite_qr', 'create_gold_qr'].includes(task.task_type) && resultText(task.result, 'pay_url'));
}
function paymentArrived(task: DouyuTaskItem | null | undefined): boolean {
if (!task || !['create_elite_qr', 'create_gold_qr'].includes(task.task_type)) return false;
if (task.status !== 'success') return false;
return task.result?.gold_recharged === true || task.result?.elite_opened === true;
}
function bindPhaseText(phase: string, polling: boolean): string {
if (phase === 'role_ready') return '已识别角色,待确认';
if (phase === 'change_waiting') return '换绑冷却中';
@@ -136,6 +144,11 @@ function resultNumber(result: Record<string, unknown> | null | undefined, key: s
return null;
}
function savedPositiveInteger(key: string, fallback = 1): number {
const value = Number(localStorage.getItem(key));
return Number.isInteger(value) && value >= 1 ? value : fallback;
}
export default function DouyuTasksPage() {
const { can } = usePermissions();
const [accounts, setAccounts] = useState<DouyuTaskAccountItem[]>([]);
@@ -148,8 +161,8 @@ export default function DouyuTasksPage() {
const [runningBatchId, setRunningBatchId] = useState('');
const [configOpen, setConfigOpen] = useState(false);
const [concurrency, setConcurrency] = useState(3);
const [goldAmount, setGoldAmount] = useState(1);
const [giftCount, setGiftCount] = useState(1);
const [goldAmount, setGoldAmount] = useState(() => savedPositiveInteger(DOUYU_GOLD_AMOUNT_STORAGE_KEY));
const [giftCount, setGiftCount] = useState(() => savedPositiveInteger(DOUYU_GIFT_COUNT_STORAGE_KEY));
const [selectedGoodsId, setSelectedGoodsId] = useState('');
const [accountSearch, setAccountSearch] = useState('');
@@ -242,6 +255,14 @@ export default function DouyuTasksPage() {
useEffect(() => { loadData(); }, [loadData]);
useEffect(() => {
localStorage.setItem(DOUYU_GOLD_AMOUNT_STORAGE_KEY, String(goldAmount));
}, [goldAmount]);
useEffect(() => {
localStorage.setItem(DOUYU_GIFT_COUNT_STORAGE_KEY, String(giftCount));
}, [giftCount]);
const hasActiveTasks = useMemo(
() => tasks.some((task) => ['pending', 'running', 'planned'].includes(task.status)),
[tasks],
@@ -279,7 +300,7 @@ export default function DouyuTasksPage() {
useEffect(() => {
if (!autoOpenPayReady.current || payTask) return;
const nextPayTask = tasks
.filter((task) => hasPaymentQrcode(task) && !autoOpenedPayTaskIds.current.has(task.id))
.filter((task) => hasPaymentQrcode(task) && !paymentArrived(task) && !autoOpenedPayTaskIds.current.has(task.id))
.sort((a, b) => b.id - a.id)[0];
if (nextPayTask) openPayTask(nextPayTask);
}, [openPayTask, payTask, tasks]);
@@ -294,7 +315,12 @@ export default function DouyuTasksPage() {
useEffect(() => {
if (!payTask) return;
const latest = tasks.find((task) => task.id === payTask.id);
if (latest && latest !== payTask) setPayTask(latest);
if (!latest) return;
if (paymentArrived(latest)) {
setPayTask(null);
return;
}
if (latest !== payTask) setPayTask(latest);
}, [payTask, tasks]);
const batchBusy = Boolean(runningBatchId || logs.connected || hasActiveTasks);
@@ -749,13 +775,14 @@ export default function DouyuTasksPage() {
gap: 12, overflow: 'hidden',
}}>
{/* Left: accounts + tasks */}
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, overflow: 'hidden' }}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, minHeight: 0, overflow: 'hidden' }}>
<Card
size="small" title="账号"
extra={<Tag color="blue"> {selectedIds.length}/{accounts.length}</Tag>}
styles={{ body: { flex: 1, overflow: 'auto', padding: 8 } }}
style={{ flex: '1 1 0', minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}
styles={{ body: { flex: 1, minHeight: 0, overflow: 'hidden', padding: 8, display: 'flex', flexDirection: 'column' } }}
>
<Space style={{ marginBottom: 8, width: '100%', justifyContent: 'space-between' }} wrap>
<Space style={{ marginBottom: 8, width: '100%', justifyContent: 'space-between', flexShrink: 0 }} wrap>
<Space>
<Input
size="small" placeholder="搜索账号/昵称/游戏名" prefix={<SearchOutlined />}
@@ -773,6 +800,7 @@ export default function DouyuTasksPage() {
<Table
rowKey="id"
size="small"
style={{ flex: 1, minHeight: 0 }}
loading={loading}
rowSelection={{
selectedRowKeys: selectedIds,
@@ -781,7 +809,7 @@ export default function DouyuTasksPage() {
columns={accountColumns}
dataSource={filteredAccounts}
pagination={{ pageSize: 15, showSizeChanger: false }}
scroll={{ y: 'calc(100vh - 520px)' }}
scroll={{ y: 'max(180px, calc(100vh - 650px))' }}
onRow={(record) => ({
onContextMenu: (e) => handleRowContextMenu(record, e),
style: { cursor: 'context-menu' },
@@ -798,12 +826,14 @@ export default function DouyuTasksPage() {
<Tag color="error"> {tasks.filter((t) => ['failed', 'error'].includes(t.status)).length}</Tag>
</Space>
}
styles={{ body: { padding: 8 } }}
style={{ flex: '0 0 300px', minHeight: 260, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}
styles={{ body: { flex: 1, minHeight: 0, padding: 8, overflow: 'hidden', display: 'flex', flexDirection: 'column' } }}
>
<Table
rowKey="id" size="small" columns={taskColumns} dataSource={tasks}
loading={loading} pagination={{ pageSize: 10, showSizeChanger: false }}
scroll={{ x: 700 }}
style={{ flex: 1, minHeight: 0 }}
loading={loading} pagination={{ pageSize: 4, showSizeChanger: false, size: 'small' }}
scroll={{ x: 700, y: 150 }}
/>
</Card>
</div>