fix(douyu): 优化和平小店绑定逻辑

This commit is contained in:
yml2213
2026-08-06 18:48:29 +08:00
parent 86459a1bd0
commit c05c0e044e
4 changed files with 2308 additions and 71 deletions
+81 -42
View File
@@ -86,6 +86,7 @@ const ESPORTS_QUICK_ACTIONS = [
const PEACE_QUICK_ACTIONS = [
{ key: 'get_xpd_bind_qr', icon: <QrcodeOutlined /> },
{ key: 'query_xpd_bind_info', icon: <SearchOutlined /> },
{ key: 'confirm_xpd_bind', icon: <CheckCircleOutlined /> },
{ key: 'query_xpd_role', icon: <SearchOutlined /> },
{ key: 'refresh_xpd_goods', icon: <ReloadOutlined /> },
{ key: 'query_xpd_balance', icon: <SearchOutlined /> },
@@ -126,6 +127,7 @@ const ESPORTS_TASK_TYPES = new Set([
const PEACE_TASK_TYPES = new Set([
'get_xpd_bind_qr',
'query_xpd_bind_info',
'confirm_xpd_bind',
'query_xpd_role',
'refresh_xpd_goods',
'query_xpd_balance',
@@ -164,7 +166,13 @@ function taskQrUrl(task: DouyuTaskItem | null | undefined): string {
}
function bindReadyForConfirm(task: DouyuTaskItem | null | undefined): boolean {
if (!task || task.task_type !== 'get_bind_qr') return false;
if (!task) return false;
if (task.task_type === 'get_xpd_bind_qr') {
if (resultFlag(task.result, 'xpd_bound') || resultFlag(task.result, 'bind_confirmed')) return false;
// 轮询识别到角色后停在待确认(xpd_pending_confirm),有角色名即可确认绑定
return Boolean(resultText(task.result, 'role_name'));
}
if (task.task_type !== 'get_bind_qr') return false;
if (task.result?.bind_ready_for_confirm === true) return true;
const roleName = resultText(task.result, 'role_name');
if (!roleName) return false;
@@ -389,6 +397,26 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
return map;
}, [tasks]);
const latestXpdQueryTaskByAccount = useMemo(() => {
const map = new Map<number, DouyuTaskItem>();
for (const task of tasks) {
if (!['query_xpd_bind_info', 'query_xpd_role'].includes(task.task_type)) continue;
const previous = map.get(task.account_id);
if (!previous || task.id > previous.id) map.set(task.account_id, task);
}
return map;
}, [tasks]);
const latestConfirmXpdBindTaskByAccount = useMemo(() => {
const map = new Map<number, DouyuTaskItem>();
for (const task of tasks) {
if (task.task_type !== 'confirm_xpd_bind') continue;
const previous = map.get(task.account_id);
if (!previous || task.id > previous.id) map.set(task.account_id, task);
}
return map;
}, [tasks]);
const latestConfirmBindFailureByAccount = useMemo(() => {
const map = new Map<number, DouyuTaskItem>();
for (const task of tasks) {
@@ -1033,15 +1061,23 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
const qrUrl = resultText(qrResult, 'url');
const qrBindPhase = resultText(qrResult, 'bind_phase');
const qrAutoPolling = qrTask?.status === 'running' && qrResult?.bind_polling === true;
const isXpdBindTask = qrTask?.task_type === 'get_xpd_bind_qr';
const qrQueryTask = qrTask
? latestQueryGameTaskByAccount.get(qrTask.account_id) || null
? (isXpdBindTask
? (latestXpdQueryTaskByAccount.get(qrTask.account_id) || null)
: (latestQueryGameTaskByAccount.get(qrTask.account_id) || null))
: null;
const qrQueryResult = qrTask && qrQueryTask && qrQueryTask.id > qrTask.id ? qrQueryTask.result : null;
const qrQueryRunning = Boolean(qrQueryTask && qrTask && qrQueryTask.id > qrTask.id && qrQueryTask.status === 'running');
const qrXpdConfirmTask = isXpdBindTask && qrTask
? (latestConfirmXpdBindTaskByAccount.get(qrTask.account_id) || null)
: null;
const qrXpdBound = Boolean(qrXpdConfirmTask && qrXpdConfirmTask.status === 'success');
const qrXpdConfirmRunning = Boolean(qrXpdConfirmTask && ['planned', 'pending', 'running'].includes(qrXpdConfirmTask.status));
const qrQueryRoleName = resultText(qrQueryResult, 'role_name');
const qrQueryPendingRoleName = resultText(qrQueryResult, 'pending_role_name');
const qrQueryIsBoundAct = resultFlag(qrQueryResult, 'is_bound_act') || resultFlag(qrQueryResult, 'bind_confirmed');
const qrQueryPending = Boolean(
const qrQueryPending = !isXpdBindTask && Boolean(
qrQueryResult
&& (
qrQueryPendingRoleName
@@ -1054,12 +1090,10 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
)
),
);
const isXpdBindTask = qrTask?.task_type === 'get_xpd_bind_qr';
const qrXpdBound = Boolean(isXpdBindTask && resultFlag(qrResult, 'xpd_bound'));
const qrBindReady = bindReadyForConfirm(qrTask) || qrQueryPending || qrXpdBound;
const qrBindReady = (bindReadyForConfirm(qrTask) || qrQueryPending) && !qrXpdBound;
const qrRoleSourceResult = qrQueryPending
? qrQueryResult
: (bindReadyForConfirm(qrTask) || qrXpdBound ? qrResult : null);
: ((bindReadyForConfirm(qrTask) || qrXpdBound) ? qrResult : null);
// 待确认角色优先用 pending_* 字段(已绑定角色之外的扫码新角色)
const qrRoleName = resultText(qrRoleSourceResult, 'pending_role_name') || resultText(qrRoleSourceResult, 'role_name');
const qrAreaName = resultText(qrRoleSourceResult, 'pending_area_name') || resultText(qrRoleSourceResult, 'area_name');
@@ -1098,17 +1132,23 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
? [qrPlatName, qrAreaName, qrRoleName].filter(Boolean).join(' - ')
: '';
const qrBindSummary = resultText(qrResult, 'bind_summary') || resultText(qrQueryResult, 'bind_summary');
const qrStatusText = qrBindReady
? (isXpdBindTask ? '绑定成功' : '已识别角色,待确认')
: (isXpdBindTask && qrTask?.status === 'failed')
? '未检测到绑定'
: (isXpdBindTask && qrTask?.status === 'running')
? '等待扫码绑定'
: qrQueryRunning
? '查询角色中'
: qrQueryTask && qrQueryTask.id > (qrTask?.id || 0) && qrQueryTask.status === 'success' && qrQueryIsBoundAct
? '查询结果:仍是当前绑定角色'
: bindPhaseText(qrBindPhase, qrAutoPolling);
const qrStatusText = qrXpdBound
? '绑定成功'
: (isXpdBindTask && qrBindReady)
? '已识别角色,待确认'
: (isXpdBindTask && qrTask?.status === 'failed')
? '未检测到绑定'
: (isXpdBindTask && qrTask?.status === 'running')
? '等待扫码绑定'
: qrXpdConfirmRunning
? '正在确认绑定'
: qrBindReady
? '已识别角色,待确认'
: qrQueryRunning
? '查询角色中'
: qrQueryTask && qrQueryTask.id > (qrTask?.id || 0) && qrQueryTask.status === 'success' && qrQueryIsBoundAct
? '查询结果:仍是当前绑定角色'
: bindPhaseText(qrBindPhase, qrAutoPolling);
const qrAccountName = qrTask
? (qrTask.account_nickname || qrTask.account_username || qrTask.account_uid || `#${qrTask.account_id}`)
: '';
@@ -1121,7 +1161,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
const accountId = qrTask.account_id;
const taskId = qrTask.id;
closeQrTask(taskId);
void startTask('confirm_bind', [accountId]);
void startTask(isXpdBindTask ? 'confirm_xpd_bind' : 'confirm_bind', [accountId]);
};
const queryQrRole = () => {
@@ -1130,7 +1170,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
message.info('正在自动识别角色,请稍候');
return;
}
void startTask('query_game_name', [qrTask.account_id]);
void startTask(isXpdBindTask ? 'query_xpd_bind_info' : 'query_game_name', [qrTask.account_id]);
};
// Account table
@@ -1463,6 +1503,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
<Space direction="vertical" style={{ width: '100%' }} size={6}>
{renderActionButton('get_xpd_bind_qr', 'primary')}
{renderActionButton('query_xpd_bind_info', 'primary')}
{renderActionButton('confirm_xpd_bind', 'primary')}
{renderActionButton('query_xpd_role', 'primary')}
{renderActionButton('query_xpd_balance', 'primary')}
{renderActionButton('refresh_xpd_goods')}
@@ -2081,7 +2122,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
<Text type="secondary" style={{ marginBottom: 12, display: 'block' }}>{qrAccountName}</Text>
)}
<Space direction="vertical" align="center" size={12}>
<Tag color={qrBindReady ? 'gold' : qrBindPhase === 'role_timeout' ? 'orange' : 'processing'}>
<Tag color={qrXpdBound ? 'success' : qrBindReady ? 'gold' : qrBindPhase === 'role_timeout' ? 'orange' : 'processing'}>
{qrStatusText}
</Tag>
{qrUrl ? (
@@ -2096,7 +2137,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
<Text type="secondary"></Text>
)}
<QrActions wrapRef={qrCanvasWrapRef} url={qrUrl} disabled={!qrUrl} />
{qrBindReady ? (
{qrBindReady || qrXpdBound ? (
<>
<Tag color="gold" style={{ fontSize: 16, padding: '6px 16px' }}>
{qrRoleName}
@@ -2125,26 +2166,24 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
: {qrQueryTask.message}
</Text>
) : null}
{!isXpdBindTask && (
<Space>
<Button
icon={<SearchOutlined />}
onClick={queryQrRole}
loading={qrQueryRunning}
disabled={qrAutoPolling}
>
{qrAutoPolling ? '自动识别中' : '查询角色'}
</Button>
<Button
type="primary"
icon={<CheckCircleOutlined />}
onClick={confirmQrBind}
disabled={!qrBindReady}
>
</Button>
</Space>
)}
<Space>
<Button
icon={<SearchOutlined />}
onClick={queryQrRole}
loading={qrQueryRunning}
disabled={qrAutoPolling}
>
{qrAutoPolling ? '自动识别中' : '查询角色'}
</Button>
<Button
type="primary"
icon={<CheckCircleOutlined />}
onClick={confirmQrBind}
disabled={!qrBindReady}
>
</Button>
</Space>
</Space>
</div>
)}