feat(douyu): 工作台默认空白账号,导入/移除通过 localStorage 持久化,刷新不再加载全部账号
This commit is contained in:
@@ -169,11 +169,18 @@ def task_types(current: User = Depends(require_permission("douyu:task"))):
|
||||
@router.get("/accounts", response_model=list[DouyuTaskAccountOut])
|
||||
def list_task_accounts(
|
||||
search: str = Query(""),
|
||||
ids: str = Query(""),
|
||||
db: Session = Depends(get_db),
|
||||
current: User = Depends(get_current_user),
|
||||
):
|
||||
"""查看可执行斗鱼任务的账号(必须有成功 Cookie)。"""
|
||||
"""查看可执行斗鱼任务的账号(必须有成功 Cookie)。
|
||||
|
||||
ids 为逗号分隔的账号 ID,用于工作台按已导入账号过滤;为空时返回全部。
|
||||
"""
|
||||
query = _visible_task_accounts_query(db, current)
|
||||
id_list = [int(x) for x in ids.split(",") if x.strip().isdigit()]
|
||||
if id_list:
|
||||
query = query.filter(Account.id.in_(id_list))
|
||||
search_text = (search or "").strip()
|
||||
if search_text:
|
||||
pattern = f"%{search_text}%"
|
||||
|
||||
@@ -11,7 +11,7 @@ import type {
|
||||
|
||||
export const douyuApi = {
|
||||
taskTypes: () => api.get<Record<string, string>, Record<string, string>>('/douyu/task-types'),
|
||||
listAccounts: (params?: { search?: string }) =>
|
||||
listAccounts: (params?: { search?: string; ids?: string }) =>
|
||||
api.get<DouyuTaskAccountItem[], DouyuTaskAccountItem[]>('/douyu/accounts', { params }),
|
||||
getConfig: () => api.get<DouyuConfig, DouyuConfig>('/douyu/config'),
|
||||
updateConfig: (data: Partial<DouyuConfig>) => api.put<DouyuConfig, DouyuConfig>('/douyu/config', data),
|
||||
|
||||
@@ -117,6 +117,7 @@ const ESPORTS_TASK_TYPES = new Set([
|
||||
const DOUYU_GOLD_AMOUNT_STORAGE_KEY = 'douyu_task_gold_amount';
|
||||
const DOUYU_GIFT_COUNT_STORAGE_KEY = 'douyu_task_gift_count';
|
||||
const DOUYU_LAYOUT_MODE_STORAGE_KEY = 'douyu_task_layout_mode';
|
||||
const DOUYU_WORKBENCH_IDS_STORAGE_KEY = (kind: HandbookKind) => `douyu_task_workbench_ids_${kind}`;
|
||||
const CONFIRM_FAIL_TIP_SECONDS = 6;
|
||||
|
||||
function resultText(result: Record<string, unknown> | null | undefined, key: string): string {
|
||||
@@ -272,6 +273,12 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
const quickActions = isEsportsHandbook ? ESPORTS_QUICK_ACTIONS : ELITE_QUICK_ACTIONS;
|
||||
const { can } = usePermissions();
|
||||
const [accounts, setAccounts] = useState<DouyuTaskAccountItem[]>([]);
|
||||
// 工作台已导入账号 ID(localStorage 持久化,默认空白,用户手动导入/移除)
|
||||
const [workbenchIds, setWorkbenchIds] = useState<number[]>(() => {
|
||||
const raw = localStorage.getItem(DOUYU_WORKBENCH_IDS_STORAGE_KEY(handbook));
|
||||
if (!raw) return [];
|
||||
return raw.split(',').map(Number).filter(Number.isInteger).filter((id) => id >= 1);
|
||||
});
|
||||
const [selectedIds, setSelectedIds] = useState<number[]>([]);
|
||||
const [goods, setGoods] = useState<DouyuGoodsItem[]>([]);
|
||||
const [tasks, setTasks] = useState<DouyuTaskItem[]>([]);
|
||||
@@ -450,13 +457,21 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
setLoading(true);
|
||||
try {
|
||||
const [accResult, goodsResult, taskResult, cfgResult, typeResult] = await Promise.allSettled([
|
||||
douyuApi.listAccounts(),
|
||||
workbenchIds.length > 0 ? douyuApi.listAccounts({ ids: workbenchIds.join(',') }) : Promise.resolve([]),
|
||||
isEsportsHandbook ? douyuApi.listEsportsGoods() : douyuApi.listGoods(),
|
||||
douyuApi.listTasks(),
|
||||
canConfig ? douyuApi.getConfig() : Promise.resolve(null),
|
||||
douyuApi.taskTypes(),
|
||||
]);
|
||||
if (accResult.status === 'fulfilled') setAccounts(accResult.value);
|
||||
if (accResult.status === 'fulfilled') {
|
||||
setAccounts(accResult.value);
|
||||
// 账号被删除等场景下清理已失效的工作台 ID,避免请求残留空 ID
|
||||
if (workbenchIds.length > 0) {
|
||||
const validIds = accResult.value.map((a) => a.id);
|
||||
const next = workbenchIds.filter((id) => validIds.includes(id));
|
||||
if (next.length !== workbenchIds.length) setWorkbenchIds(next);
|
||||
}
|
||||
}
|
||||
if (goodsResult.status === 'fulfilled') setGoods(goodsResult.value);
|
||||
if (taskResult.status === 'fulfilled') {
|
||||
setTasks(taskResult.value);
|
||||
@@ -489,7 +504,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [canConfig, isEsportsHandbook]);
|
||||
}, [canConfig, isEsportsHandbook, workbenchIds]);
|
||||
|
||||
const loadTasks = useCallback(async () => {
|
||||
try {
|
||||
@@ -510,6 +525,14 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
localStorage.setItem(DOUYU_LAYOUT_MODE_STORAGE_KEY, layoutMode);
|
||||
}, [layoutMode]);
|
||||
|
||||
// 工作台账号集合持久化:移除账号后刷新不再出现
|
||||
useEffect(() => {
|
||||
localStorage.setItem(
|
||||
DOUYU_WORKBENCH_IDS_STORAGE_KEY(handbook),
|
||||
workbenchIds.length ? workbenchIds.join(',') : '',
|
||||
);
|
||||
}, [handbook, workbenchIds]);
|
||||
|
||||
// 监听账号表格区域高度变化,动态计算 scroll.y 实现表体内部滚动
|
||||
useEffect(() => {
|
||||
const node = accountTableAreaRef.current;
|
||||
@@ -810,16 +833,18 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
const loadImportPool = useCallback(async () => {
|
||||
setImportLoading(true);
|
||||
try {
|
||||
// 候选池 = 账号库全量,过滤已导入工作台的账号
|
||||
const result = await douyuApi.listAccounts({ search: importSearch });
|
||||
setImportPool(result.filter((a) => !accounts.find((x) => x.id === a.id)));
|
||||
setImportPool(result.filter((a) => !workbenchIds.includes(a.id)));
|
||||
} finally {
|
||||
setImportLoading(false);
|
||||
}
|
||||
}, [importSearch, accounts]);
|
||||
}, [importSearch, workbenchIds]);
|
||||
useEffect(() => { if (importOpen) void loadImportPool(); }, [importOpen, loadImportPool]);
|
||||
|
||||
const importAccounts = (ids: number[]) => {
|
||||
const toImport = importPool.filter((a) => ids.includes(a.id));
|
||||
setWorkbenchIds((prev) => [...new Set([...prev, ...toImport.map((a) => a.id)])]);
|
||||
setAccounts((prev) => {
|
||||
const existing = new Set(prev.map((a) => a.id));
|
||||
return [...prev, ...toImport.filter((a) => !existing.has(a.id))];
|
||||
@@ -831,8 +856,10 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
|
||||
const removeSelected = () => {
|
||||
const sel = new Set(selectedIds);
|
||||
setWorkbenchIds((prev) => prev.filter((id) => !sel.has(id)));
|
||||
setAccounts((prev) => prev.filter((a) => !sel.has(a.id)));
|
||||
setSelectedIds([]);
|
||||
message.success(`已移出 ${sel.size} 个账号`);
|
||||
};
|
||||
|
||||
// ---- Context menu ----
|
||||
@@ -1524,6 +1551,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
size="small"
|
||||
className="douyu-task-record-table"
|
||||
loading={loading}
|
||||
locale={{ emptyText: '工作台暂无账号,点击右上角「导入账号」添加' }}
|
||||
rowSelection={{
|
||||
selectedRowKeys: selectedIds,
|
||||
onChange: (keys) => setSelectedIds(keys.map(Number)),
|
||||
@@ -1746,7 +1774,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
},
|
||||
]}
|
||||
pagination={{ pageSize: 10 }}
|
||||
locale={{ emptyText: '没有可导入的账号(操作台已包含所有账号)' }}
|
||||
locale={{ emptyText: '没有可导入的账号' }}
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user