斗鱼客服导入账号 支持tag

This commit is contained in:
yml2213
2026-08-06 13:20:12 +08:00
parent 335f5cf57b
commit 25880e91a7
4 changed files with 33 additions and 11 deletions
+1
View File
@@ -25,3 +25,4 @@ web/frontend/node_modules/
web/frontend/dist/
data/web.db
.DS_Store
.reasonix/
+5 -1
View File
@@ -239,6 +239,7 @@ def task_types(current: User = Depends(require_permission("douyu:task"))):
@router.get("/accounts")
def list_task_accounts(
search: str = Query(""),
tag: str = Query(""),
ids: str = Query(""),
page: int | None = Query(None, ge=1),
page_size: int = Query(50, ge=1, le=200),
@@ -247,12 +248,15 @@ def list_task_accounts(
):
"""查看可执行斗鱼任务的账号(必须有成功 Cookie)。
ids 为逗号分隔的账号 ID,用于工作台按已导入账号过滤;为空时返回全部。
tag 按账号标签精确筛选;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))
tag_text = (tag or "").strip()
if tag_text:
query = query.filter(Account.tag == tag_text)
search_text = (search or "").strip()
if search_text:
pattern = f"%{search_text}%"
+2 -2
View File
@@ -13,9 +13,9 @@ import type {
export const douyuApi = {
taskTypes: () => api.get<Record<string, string>, Record<string, string>>('/douyu/task-types'),
listAccounts: (params?: { search?: string; ids?: string }) =>
listAccounts: (params?: { search?: string; tag?: string; ids?: string }) =>
api.get<DouyuTaskAccountItem[], DouyuTaskAccountItem[]>('/douyu/accounts', { params }),
listAccountsPaged: (params: PageParams & { ids?: string }) =>
listAccountsPaged: (params: PageParams & { tag?: string; ids?: string }) =>
api.get<PaginatedResponse<DouyuTaskAccountItem>, PaginatedResponse<DouyuTaskAccountItem>>('/douyu/accounts', { params }),
getConfig: () => api.get<DouyuConfig, DouyuConfig>('/douyu/config'),
updateConfig: (data: Partial<DouyuConfig>) => api.put<DouyuConfig, DouyuConfig>('/douyu/config', data),
+25 -8
View File
@@ -9,6 +9,7 @@ import {
SearchOutlined, SettingOutlined, ShoppingOutlined, StopOutlined,
} from '@ant-design/icons';
import {
accountApi,
douyuApi,
type DouyuConfig,
type DouyuGoodsItem,
@@ -307,6 +308,8 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
const [importOpen, setImportOpen] = useState(false);
const [importPool, setImportPool] = useState<DouyuTaskAccountItem[]>([]);
const [importSearch, setImportSearch] = useState('');
const [importTag, setImportTag] = useState('');
const [importTags, setImportTags] = useState<string[]>([]);
const [importSelectedIds, setImportSelectedIds] = useState<number[]>([]);
const [importLoading, setImportLoading] = useState(false);
@@ -838,14 +841,18 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
const loadImportPool = useCallback(async () => {
setImportLoading(true);
try {
// 候选池 = 账号库全量,过滤已导入工作台的账号
const result = await douyuApi.listAccounts({ search: importSearch });
// 候选池 = 账号库按搜索/标签过滤,剔除已导入工作台的账号
const result = await douyuApi.listAccounts({ search: importSearch, tag: importTag || undefined });
setImportPool(result.filter((a) => !workbenchIds.includes(a.id)));
} finally {
setImportLoading(false);
}
}, [importSearch, workbenchIds]);
}, [importSearch, importTag, workbenchIds]);
useEffect(() => { if (importOpen) void loadImportPool(); }, [importOpen, loadImportPool]);
useEffect(() => {
if (!importOpen) return;
accountApi.listTags().then(setImportTags).catch(() => {});
}, [importOpen]);
const importAccounts = (ids: number[]) => {
const toImport = importPool.filter((a) => ids.includes(a.id));
@@ -1746,11 +1753,20 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
width={700}
>
<Space style={{ marginBottom: 12, width: '100%', justifyContent: 'space-between' }}>
<Input
placeholder="搜索账号/昵称" prefix={<SearchOutlined />}
value={importSearch} onChange={(e) => setImportSearch(e.target.value)}
style={{ width: 250 }}
/>
<Space>
<Input
placeholder="搜索账号/昵称" prefix={<SearchOutlined />}
value={importSearch} onChange={(e) => setImportSearch(e.target.value)}
style={{ width: 220 }}
/>
<Select
placeholder="按标签筛选" allowClear showSearch
value={importTag || undefined}
onChange={(value?: string) => setImportTag(value || '')}
style={{ width: 160 }}
options={importTags.map((t) => ({ value: t, label: t }))}
/>
</Space>
<Space>
<Button onClick={() => importAccounts(importPool.map((a) => a.id))}>
({importPool.length})
@@ -1767,6 +1783,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
columns={[
{ title: '昵称', dataIndex: 'nickname', render: (_, r) => r.nickname || r.username },
{ title: 'UID', dataIndex: 'uid' },
{ title: '标签', dataIndex: 'tag', width: 110, render: (v: string) => (v ? <Tag color="blue">{v}</Tag> : '-') },
{
title: '游戏名',
dataIndex: isEsportsHandbook ? 'esports_game_name' : 'game_name',