优化客服CK重登流程
This commit is contained in:
@@ -26,6 +26,10 @@ export const cookieApi = {
|
||||
api.post<{ batch_id: string; count: number; skipped: number; success: boolean }, { batch_id: string; count: number; skipped: number; success: boolean }>('/cookies/relogin', { ids }),
|
||||
reloginOperations: (ids: number[]) =>
|
||||
api.post<{ batch_id: string; count: number; skipped: number; success: boolean }, { batch_id: string; count: number; skipped: number; success: boolean }>('/cookies/operations/relogin', { ids }),
|
||||
reloginInvalidOperations: (params?: { search?: string; tag?: string }) =>
|
||||
api.post<{ batch_id: string; count: number; skipped: number; success: boolean }, { batch_id: string; count: number; skipped: number; success: boolean }>('/cookies/operations/relogin-invalid', null, { params }),
|
||||
stopOperationRelogin: (batchId: string) =>
|
||||
api.post<MessageResponse, MessageResponse>(`/cookies/operations/relogin/${batchId}/stop`),
|
||||
loginTasks: (batchId: string) =>
|
||||
api.get<LoginTaskItem[], LoginTaskItem[]>('/login/tasks', { params: { batch_id: batchId } }),
|
||||
delete: (id: number) => api.delete<MessageResponse, MessageResponse>(`/cookies/${id}`),
|
||||
|
||||
@@ -280,6 +280,9 @@ export interface CookieOperationItem {
|
||||
ck_check_status: string;
|
||||
ck_checked_at: string | null;
|
||||
created_at: string | null;
|
||||
relogin_status: '' | 'relogin_pending' | 'relogin_running' | 'relogin_failed';
|
||||
relogin_message: string;
|
||||
relogin_batch_id: string;
|
||||
}
|
||||
|
||||
export interface CookieOperationCheckResult {
|
||||
|
||||
@@ -22,6 +22,10 @@ const ACTION_OPTIONS = [
|
||||
{ value: 'recharge:huya:create', label: '虎牙创建充值批次' },
|
||||
{ value: 'recharge:huya:stop', label: '虎牙停止充值批次' },
|
||||
{ value: 'recharge:huya:config', label: '虎牙充值配置' },
|
||||
{ value: 'cookie:check', label: '检测账号 CK' },
|
||||
{ value: 'cookie:relogin', label: '创建 CK 重登批次' },
|
||||
{ value: 'cookie:relogin_invalid', label: '批量重登失效 CK' },
|
||||
{ value: 'cookie:relogin_stop', label: '停止 CK 重登批次' },
|
||||
];
|
||||
|
||||
const ACTION_LABELS = new Map(ACTION_OPTIONS.map((item) => [item.value, item.label]));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { Button, Input, Popconfirm, Select, Space, Table, Tag, Typography } from 'antd';
|
||||
import { message } from '../utils/antdMessage';
|
||||
import { LoadingOutlined, ReloadOutlined, SearchOutlined } from '@ant-design/icons';
|
||||
import { LoadingOutlined, ReloadOutlined, SearchOutlined, StopOutlined } from '@ant-design/icons';
|
||||
import { cookieApi, type CookieOperationCheckResult, type CookieOperationItem } from '../api/modules';
|
||||
import { formatTime } from '../utils/time';
|
||||
import { getErrorMessage } from '../utils/error';
|
||||
@@ -59,6 +59,20 @@ export default function CookieOperationsPage() {
|
||||
void loadItems();
|
||||
}, [loadItems]);
|
||||
|
||||
const hasActiveRelogin = items.some((item) => (
|
||||
item.relogin_status === 'relogin_pending' || item.relogin_status === 'relogin_running'
|
||||
));
|
||||
const activeReloginBatchIds = Array.from(new Set(items
|
||||
.filter((item) => item.relogin_status === 'relogin_pending' || item.relogin_status === 'relogin_running')
|
||||
.map((item) => item.relogin_batch_id)
|
||||
.filter(Boolean)));
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasActiveRelogin) return;
|
||||
const timer = window.setInterval(() => void loadItems(), 2000);
|
||||
return () => window.clearInterval(timer);
|
||||
}, [hasActiveRelogin, loadItems]);
|
||||
|
||||
useEffect(() => {
|
||||
cookieApi.listOperationTags().then(setTags).catch(() => {
|
||||
// 标签加载失败不影响 CK 检测与重登。
|
||||
@@ -108,8 +122,41 @@ export default function CookieOperationsPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleReloginInvalid = async () => {
|
||||
try {
|
||||
const response = await cookieApi.reloginInvalidOperations({
|
||||
search: search.trim() || undefined,
|
||||
tag: tagFilter || undefined,
|
||||
});
|
||||
const skipped = response.skipped ? `,${response.skipped} 条因缺少登录凭据跳过` : '';
|
||||
message.success(`已开始重登 ${response.count} 个失效账号${skipped}`);
|
||||
setSelectedRowKeys([]);
|
||||
void loadItems();
|
||||
} catch (error: unknown) {
|
||||
message.error(getErrorMessage(error));
|
||||
}
|
||||
};
|
||||
|
||||
const handleStopRelogin = async () => {
|
||||
if (activeReloginBatchIds.length === 0) return;
|
||||
try {
|
||||
await Promise.all(activeReloginBatchIds.map((batchId) => cookieApi.stopOperationRelogin(batchId)));
|
||||
message.success('已发送停止信号');
|
||||
void loadItems();
|
||||
} catch (error: unknown) {
|
||||
message.error(getErrorMessage(error));
|
||||
}
|
||||
};
|
||||
|
||||
const resultFor = (item: CookieOperationItem) => checkResults.get(item.id);
|
||||
const selectedIds = selectedRowKeys.map((key) => Number(key));
|
||||
const reloginStatus = (item: CookieOperationItem) => {
|
||||
if (item.relogin_status === 'relogin_pending') return <Tag color="processing">重登排队中</Tag>;
|
||||
if (item.relogin_status === 'relogin_running') return <Tag color="processing" icon={<LoadingOutlined />}>重登中</Tag>;
|
||||
if (item.relogin_status === 'relogin_failed') return <Tag color="error">重登失败</Tag>;
|
||||
if (item.relogin_message.startsWith('重新登录成功')) return <Tag color="success">重登成功</Tag>;
|
||||
return <Text type="secondary">-</Text>;
|
||||
};
|
||||
const columns = [
|
||||
{ title: '账号', dataIndex: 'account_username', ellipsis: true },
|
||||
{
|
||||
@@ -137,6 +184,20 @@ export default function CookieOperationsPage() {
|
||||
return checkedAt ? formatTime(checkedAt) : <Text type="secondary">-</Text>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '重登状态',
|
||||
width: 130,
|
||||
render: (_: unknown, item: CookieOperationItem) => (
|
||||
<Space direction="vertical" size={0}>
|
||||
{reloginStatus(item)}
|
||||
{item.relogin_status === 'relogin_failed' && item.relogin_message ? (
|
||||
<Text type="secondary" ellipsis style={{ maxWidth: 180, fontSize: 12 }} title={item.relogin_message}>
|
||||
{item.relogin_message}
|
||||
</Text>
|
||||
) : null}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 190,
|
||||
@@ -145,7 +206,7 @@ export default function CookieOperationsPage() {
|
||||
<Button
|
||||
size="small"
|
||||
loading={checkingIds.has(item.id)}
|
||||
disabled={checkingIds.has(item.id)}
|
||||
disabled={checkingIds.has(item.id) || item.relogin_status === 'relogin_pending' || item.relogin_status === 'relogin_running'}
|
||||
onClick={() => void handleCheck([item.id])}
|
||||
>
|
||||
检测
|
||||
@@ -155,7 +216,7 @@ export default function CookieOperationsPage() {
|
||||
size="small"
|
||||
icon={<ReloadOutlined />}
|
||||
loading={reloginIds.has(item.id)}
|
||||
disabled={reloginIds.has(item.id)}
|
||||
disabled={reloginIds.has(item.id) || item.relogin_status === 'relogin_pending' || item.relogin_status === 'relogin_running'}
|
||||
>
|
||||
重登
|
||||
</Button>
|
||||
@@ -182,6 +243,19 @@ export default function CookieOperationsPage() {
|
||||
重登选中 {selectedIds.length > 0 ? `(${selectedIds.length})` : ''}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Popconfirm
|
||||
title="将重新登录当前筛选范围内所有已检测为无效的账号,并在成功后替换旧 CK,确认继续?"
|
||||
onConfirm={() => void handleReloginInvalid()}
|
||||
>
|
||||
<Button icon={<ReloadOutlined />}>
|
||||
批量重登失效账号
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
{activeReloginBatchIds.length > 0 ? (
|
||||
<Popconfirm title="确认停止当前重登任务?旧 CK 会保留。" onConfirm={() => void handleStopRelogin()}>
|
||||
<Button danger icon={<StopOutlined />}>停止重登</Button>
|
||||
</Popconfirm>
|
||||
) : null}
|
||||
</Space>
|
||||
</div>
|
||||
<Space wrap style={{ marginBottom: 12 }}>
|
||||
|
||||
Reference in New Issue
Block a user