斗鱼客服导入账号 支持tag
This commit is contained in:
@@ -25,3 +25,4 @@ web/frontend/node_modules/
|
||||
web/frontend/dist/
|
||||
data/web.db
|
||||
.DS_Store
|
||||
.reasonix/
|
||||
|
||||
@@ -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}%"
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user