From aa978a808e91a32406c660b138236f1d73aa3f84 Mon Sep 17 00:00:00 2001 From: yml Date: Thu, 12 Nov 2026 19:38:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(weibo):=20=E5=B7=A5=E4=BD=9C=E5=8F=B0?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E5=90=8E=E8=87=AA=E5=8A=A8=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7=E8=B5=84=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/frontend/src/pages/WeiboAccountsPage.tsx | 92 ++++++++++++++++++-- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/web/frontend/src/pages/WeiboAccountsPage.tsx b/web/frontend/src/pages/WeiboAccountsPage.tsx index 7fa2de3..ad31970 100644 --- a/web/frontend/src/pages/WeiboAccountsPage.tsx +++ b/web/frontend/src/pages/WeiboAccountsPage.tsx @@ -121,6 +121,11 @@ interface BatchRechargeEntry { creditError: string; } +interface ImportRefreshTarget { + id: number; + label: string; +} + function readMallCache(accountId: number): WeiboMallListResult | null { try { const raw = localStorage.getItem(WEIBO_MALL_CACHE_KEY); @@ -332,6 +337,39 @@ export default function WeiboAccountsPage({ void loadKnownTags(); }, [loadKnownTags]); + const refreshImportedAccounts = async (targets: ImportRefreshTarget[]) => { + const uniqueTargets = Array.from( + new Map(targets.map((target) => [target.id, target])).values(), + ); + let refreshed = 0; + const failures: string[] = []; + await runWithConcurrency(uniqueTargets, 3, async (target) => { + try { + await weiboApi.refreshAccount(target.id); + refreshed += 1; + } catch (error) { + failures.push(`${target.label}:${getErrorMessage(error)}`); + } + }); + return { + total: uniqueTargets.length, + refreshed, + failures, + }; + }; + + const importedRefreshMessage = ( + result: Awaited>, + ) => { + if (result.total === 0) return ''; + if (result.failures.length === 0) { + return `,已自动刷新 ${result.refreshed}/${result.total} 个账号`; + } + return `,已刷新 ${result.refreshed}/${result.total} 个,失败 ${result.failures.length} 个:${result.failures + .slice(0, 3) + .join(';')}`; + }; + const handleImport = async () => { const values = await form.validateFields(); setImporting(true); @@ -344,11 +382,20 @@ export default function WeiboAccountsPage({ setImportErrors(result.errors); setImportDuplicates(result.duplicates); let workbenchError = ''; + let refreshResult: Awaited< + ReturnType + > | null = null; if (isWorkbench && result.accounts.length > 0) { try { await weiboApi.addWorkbenchAccounts( result.accounts.map((account) => account.id), ); + refreshResult = await refreshImportedAccounts( + result.accounts.map((account) => ({ + id: account.id, + label: account.nickname || account.uid, + })), + ); } catch (error) { workbenchError = getErrorMessage(error); } @@ -358,8 +405,14 @@ export default function WeiboAccountsPage({ message.warning( `${result.message},但加入当前工作台失败:${workbenchError}`, ); + } else if (refreshResult?.failures.length) { + message.warning( + `${result.message}${importedRefreshMessage(refreshResult)}`, + ); } else { - message.success(result.message); + message.success( + `${result.message}${refreshResult ? importedRefreshMessage(refreshResult) : ''}`, + ); } await loadAccounts(); await loadKnownTags(); @@ -430,6 +483,18 @@ export default function WeiboAccountsPage({ text, isSuperAdmin && forceAddOccupied, ); + const refreshResult = await refreshImportedAccounts( + result.items + .filter( + (item) => + item.account_id !== null && + ['added', 'forced_added', 'already_added'].includes(item.status), + ) + .map((item) => ({ + id: item.account_id as number, + label: item.nickname || item.uid || `账号 ${item.account_id}`, + })), + ); setBatchImportResult(result); await loadAccounts(); await loadKnownTags(); @@ -439,11 +504,15 @@ export default function WeiboAccountsPage({ : ''; if (result.failed > 0) { message.warning( - `批量导入完成:新增 ${result.added} 个${forceAddSummary},已存在 ${result.already_added} 个,失败 ${result.failed} 个`, + `批量导入完成:新增 ${result.added} 个${forceAddSummary},已存在 ${result.already_added} 个,失败 ${result.failed} 个${importedRefreshMessage(refreshResult)}`, + ); + } else if (refreshResult.failures.length > 0) { + message.warning( + `批量导入完成:新增 ${result.added} 个${forceAddSummary},已存在 ${result.already_added} 个${importedRefreshMessage(refreshResult)}`, ); } else { message.success( - `批量导入完成:新增 ${result.added} 个${forceAddSummary},已存在 ${result.already_added} 个`, + `批量导入完成:新增 ${result.added} 个${forceAddSummary},已存在 ${result.already_added} 个${importedRefreshMessage(refreshResult)}`, ); } } catch (error) { @@ -461,10 +530,23 @@ export default function WeiboAccountsPage({ setPoolLoading(true); try { await weiboApi.addWorkbenchAccounts(poolSelectedIds); + const refreshResult = await refreshImportedAccounts( + poolItems + .filter((item) => poolSelectedIds.includes(item.id)) + .map((item) => ({ + id: item.id, + label: item.nickname || item.uid, + })), + ); setPoolOpen(false); setPoolSelectedIds([]); await loadAccounts(); - message.success(`已导入 ${poolSelectedIds.length} 个账号到工作台`); + const successMessage = `已导入 ${poolSelectedIds.length} 个账号到工作台${importedRefreshMessage(refreshResult)}`; + if (refreshResult.failures.length > 0) { + message.warning(successMessage); + } else { + message.success(successMessage); + } } catch (error) { message.error(getErrorMessage(error)); } finally { @@ -2607,7 +2689,7 @@ export default function WeiboAccountsPage({ type="info" showIcon title="支持多行、空格、逗号分隔" - description="优先按 UID 精确匹配;也支持微博用户名和角色名。重名时请改用 UID。" + description="优先按 UID 精确匹配;也支持微博用户名和角色名。重名时请改用 UID。导入成功后会立即刷新角色绑定和微豆余额。" /> {isSuperAdmin && (