feat: unify account environments and work collection
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
// 指标 GET /creator/works/:id/metrics,评论 GET /creator/comments?work_id=(定时采集由后端调度器维护)。
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Line } from '@ant-design/charts';
|
||||
import { Alert, App, Button, Card, Col, Drawer, Empty, Flex, InputNumber, Row, Space, Spin, Table, Typography } from 'antd';
|
||||
import { Alert, App, Button, Card, Col, Drawer, Empty, Flex, InputNumber, Pagination, Row, Space, Spin, Table, Typography } from 'antd';
|
||||
import {
|
||||
CommentOutlined,
|
||||
EyeOutlined,
|
||||
@@ -104,6 +104,12 @@ function GrowthChart({ metrics }: { metrics: any[] }) {
|
||||
);
|
||||
}
|
||||
|
||||
interface CollectionProgress {
|
||||
work_count: number;
|
||||
aweme_count: number | null;
|
||||
works: { status: string; last_error?: string };
|
||||
}
|
||||
|
||||
interface WorksGalleryProps {
|
||||
/** 不传则不过滤来源(如竞品分析页跨全部竞品);监控/自有账号详情传具体账号 ID。 */
|
||||
sourceId?: string;
|
||||
@@ -116,7 +122,9 @@ interface WorksGalleryProps {
|
||||
export default function WorksGallery({ sourceId, sourceType, emptyHint, extraFilters }: WorksGalleryProps) {
|
||||
const [works, setWorks] = useState<any[]>([]);
|
||||
const [workPage, setWorkPage] = useState(1);
|
||||
const [workPageInfo, setWorkPageInfo] = useState({ total: 0, hasNext: false });
|
||||
const [workPageInfo, setWorkPageInfo] = useState({ total: 0 });
|
||||
const [collectionProgress, setCollectionProgress] = useState<CollectionProgress | null>(null);
|
||||
const [progressError, setProgressError] = useState<any>(null);
|
||||
const [worksPending, setWorksPending] = useState(true);
|
||||
const [worksError, setWorksError] = useState<any>(null);
|
||||
const [minGrowth, setMinGrowth] = useState<number | null>(null);
|
||||
@@ -133,6 +141,16 @@ export default function WorksGallery({ sourceId, sourceType, emptyHint, extraFil
|
||||
const loadWorks = useCallback(async () => {
|
||||
setWorksPending(true);
|
||||
setWorksError(null);
|
||||
setProgressError(null);
|
||||
setCollectionProgress(null);
|
||||
const progressRequest = sourceType === 'owned' && sourceId
|
||||
? creatorGet(`/creator/accounts/${encodeURIComponent(sourceId)}/collection-status`)
|
||||
.then((progress) => setCollectionProgress(progress))
|
||||
.catch((error) => {
|
||||
console.error('读取账号作品采集进度失败', { sourceId, sourceType, error });
|
||||
setProgressError(error);
|
||||
})
|
||||
: Promise.resolve();
|
||||
try {
|
||||
const filters: Record<string, string | number | undefined> = { ...extraFilters };
|
||||
if (sourceId) filters.source_id = sourceId;
|
||||
@@ -144,10 +162,12 @@ export default function WorksGallery({ sourceId, sourceType, emptyHint, extraFil
|
||||
}
|
||||
const result = await getList({ resource: 'creator-works', page: workPage, pageSize: 25, filters });
|
||||
setWorks(result.data);
|
||||
setWorkPageInfo({ total: result.total, hasNext: Boolean(result.hasNext) });
|
||||
setWorkPageInfo({ total: result.total });
|
||||
} catch (loadError) {
|
||||
console.error('读取作品列表失败', { sourceId, sourceType, page: workPage, minGrowth, extraFilters, error: loadError });
|
||||
setWorksError(loadError);
|
||||
} finally {
|
||||
await progressRequest;
|
||||
setWorksPending(false);
|
||||
}
|
||||
}, [sourceId, sourceType, workPage, minGrowth, extraFilters]);
|
||||
@@ -188,6 +208,18 @@ export default function WorksGallery({ sourceId, sourceType, emptyHint, extraFil
|
||||
loadComments(work.id, 1);
|
||||
}
|
||||
|
||||
let progressHint = '采集进度暂不可用';
|
||||
if (collectionProgress) {
|
||||
const { work_count: collected, aweme_count: total, works: checkpoint } = collectionProgress;
|
||||
progressHint = `已采集 ${collected} / 总计 ${total ?? '未知'}`;
|
||||
if (total == null) progressHint += ';抖音作品总数未知,暂无法判断是否完整。';
|
||||
else if (collected < total) progressHint += ';尚未采集完整,当前仅展示已采集作品。';
|
||||
else if (collected > total) progressHint += ';已采集数量与抖音总数不一致,请重新同步确认。';
|
||||
else progressHint += ';当前已采集数量与抖音总数一致。';
|
||||
if (checkpoint.status === 'running') progressHint += ' 正在采集。';
|
||||
if (checkpoint.status === 'failed' || checkpoint.status === 'blocked') progressHint += ` 采集未完成:${checkpoint.last_error || '请查看账号采集状态。'}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card
|
||||
@@ -197,7 +229,12 @@ export default function WorksGallery({ sourceId, sourceType, emptyHint, extraFil
|
||||
}
|
||||
>
|
||||
<Flex justify="space-between" align="center" style={{ marginBottom: 16 }}>
|
||||
<Typography.Text type="secondary">共 {workPageInfo.total} 个作品;作品由系统按采集间隔自动同步。</Typography.Text>
|
||||
<Flex vertical gap={4}>
|
||||
{sourceType === 'owned' ? <Typography.Text>{progressHint}</Typography.Text> : null}
|
||||
<Typography.Text type="secondary">
|
||||
{worksError ? '作品列表暂不可用' : `${minGrowth !== null || extraFilters ? '符合筛选' : sourceType === 'owned' ? '当前列表' : '共'} ${workPageInfo.total} 个作品`};作品由系统按采集间隔自动同步。
|
||||
</Typography.Text>
|
||||
</Flex>
|
||||
<Flex align="center" gap={8}>
|
||||
<FireOutlined style={{ color: 'rgba(0,0,0,0.45)' }} />
|
||||
<Typography.Text type="secondary">24h 点赞增量 ≥</Typography.Text>
|
||||
@@ -214,6 +251,9 @@ export default function WorksGallery({ sourceId, sourceType, emptyHint, extraFil
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
{progressError ? (
|
||||
<Alert type="error" showIcon title={progressError.message} style={{ marginBottom: 16 }} action={<Button size="small" onClick={loadWorks}>重试</Button>} />
|
||||
) : null}
|
||||
{worksError ? (
|
||||
<Alert
|
||||
type="error"
|
||||
@@ -269,14 +309,15 @@ export default function WorksGallery({ sourceId, sourceType, emptyHint, extraFil
|
||||
</Spin>
|
||||
{workPageInfo.total > works.length ? (
|
||||
<Flex justify="flex-end" style={{ marginTop: 12 }}>
|
||||
<Space>
|
||||
<Button size="small" onClick={() => setWorkPage((page) => Math.max(1, page - 1))} disabled={workPage === 1 || worksPending}>
|
||||
上一页
|
||||
</Button>
|
||||
<Button size="small" onClick={() => setWorkPage((page) => page + 1)} disabled={!workPageInfo.hasNext || worksPending}>
|
||||
下一页
|
||||
</Button>
|
||||
</Space>
|
||||
<Pagination
|
||||
current={workPage}
|
||||
pageSize={25}
|
||||
total={workPageInfo.total}
|
||||
showSizeChanger={false}
|
||||
showTotal={(total) => `${sourceType === 'owned' ? '当前列表共' : '共'} ${total} 个作品`}
|
||||
disabled={worksPending}
|
||||
onChange={(page) => setWorkPage(page)}
|
||||
/>
|
||||
</Flex>
|
||||
) : null}
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user