fix(ui): 竞品分析素材流程改 Drawer、日期筛选取 DatePicker、选择素材按钮降级并区分已选中态(走查 P2-#13)

This commit is contained in:
2026-09-28 07:35:39 +08:00
parent a30e99a160
commit 1a46ec0231
+91 -65
View File
@@ -1,9 +1,10 @@
// 竞品分析:作品列表对齐 ant-design-pro card-list——antd Row/Col 响应式栅格 + Card 原样组合;
// 作品详情改走 Drawer;素材三步处理与仿写流程内联卡片原样保留;筛选自动刷新、手动翻页不变。
// 作品详情与素材处理均走 Drawer;日期筛选用 antd DatePicker;筛选自动刷新、手动翻页不变。
// 平台筛选已随 migration 038(platform 收敛 douyin)移除。
import { useEffect, useState } from 'react';
import { CommentOutlined, LikeOutlined, ShareAltOutlined } from '@ant-design/icons';
import { Alert, App, Button, Card, Col, Drawer, Empty, Flex, Input, InputNumber, Modal, Row, Select, Space, Spin, Table, Tag, Typography } from 'antd';
import { Alert, App, Button, Card, Col, DatePicker, Drawer, Empty, Flex, Input, InputNumber, Modal, Row, Select, Space, Spin, Table, Tag, Typography } from 'antd';
import type { Dayjs } from 'dayjs';
import { creatorAction, creatorGet, creatorUpdate, getList } from '@/services/api';
import { conflictMessage, dateTime } from '@/utils/helpers';
@@ -25,8 +26,8 @@ interface Filters {
minComments?: number;
minShares?: number;
publishedAtStatus?: string;
publishedAfter?: string;
publishedBefore?: string;
publishedAfter?: Dayjs;
publishedBefore?: Dayjs;
}
function statusTag(status?: string) {
@@ -224,8 +225,20 @@ export default function Page() {
onChange={(value) => setFilters((f) => ({ ...f, publishedAtStatus: value }))}
options={publishedAtStatusOptions}
/>
<Input type="date" style={{ width: 160 }} value={filters.publishedAfter} onChange={(e) => setFilters((f) => ({ ...f, publishedAfter: e.target.value }))} />
<Input type="date" style={{ width: 160 }} value={filters.publishedBefore} onChange={(e) => setFilters((f) => ({ ...f, publishedBefore: e.target.value }))} />
<DatePicker
style={{ width: 160 }}
placeholder="发布开始日期"
value={filters.publishedAfter}
onChange={(value) => setFilters((f) => ({ ...f, publishedAfter: value ?? undefined }))}
allowClear
/>
<DatePicker
style={{ width: 160 }}
placeholder="发布结束日期"
value={filters.publishedBefore}
onChange={(value) => setFilters((f) => ({ ...f, publishedBefore: value ?? undefined }))}
allowClear
/>
</Space>
</Card>
<Card title="作品与指标">
@@ -255,8 +268,13 @@ export default function Page() {
<Button key="detail" type="link" size="small" onClick={() => openWorkDetail(work.id)} disabled={workDetailPending}>
详情
</Button>,
<Button key="select" type="primary" size="small" onClick={() => selectMaterial(work.id)}>
选择素材
<Button
key="select"
type={material?.work_id === work.id ? 'primary' : 'default'}
size="small"
onClick={() => selectMaterial(work.id)}
>
{material?.work_id === work.id ? '编辑素材' : '选择素材'}
</Button>,
...(work.original_url ? [<Typography.Link key="origin" href={work.original_url} target="_blank">原文</Typography.Link>] : []),
]}
@@ -306,65 +324,73 @@ export default function Page() {
</Flex>
) : null}
</Card>
<Drawer
open={Boolean(material)}
onClose={() => setMaterial(null)}
size="large"
title="素材处理"
destroyOnHidden
>
{material ? (
<Card size="small" title="素材处理">
<Typography.Paragraph type="secondary" style={{ marginTop: 0 }}>每一步都保留真实状态;失败不会被显示为成功。</Typography.Paragraph>
<Flex vertical gap={12}>
<div>
<Button type="primary" onClick={processMaterial} loading={materialPending || material.download_status === 'running'}>
开始处理素材
</Button>
</div>
<Space wrap>
{stepTag(material.download_status, `下载:${material.download_status}`)}
{stepTag(material.audio_status, `音轨:${material.audio_status}`)}
{stepTag(material.transcription_status, `转写:${material.transcription_status}`)}
</Space>
{material.failure_reason ? (
<Alert type="error" showIcon title={`失败步骤:${material.failed_step || '未记录'};${material.failure_reason}`} />
) : null}
<div>
<Typography.Text strong>仿写要求</Typography.Text>
<Typography.Paragraph type="secondary" style={{ fontSize: 12, marginBottom: 4 }}>必须先确认要求,才允许保存可编辑结果。</Typography.Paragraph>
<Input.TextArea
rows={3}
value={rewriteRequirement}
onChange={(event) => setRewriteRequirement(event.target.value)}
disabled={Boolean(material.rewrite_confirmed_at) || materialPending}
/>
</div>
{material.rewrite_confirmed_at ? (
<>
<Flex gap={8} align="center">
<Button onClick={generateRewrite} disabled={materialPending}>
生成仿写草稿
</Button>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>生成结果不会自动发布,保存前必须人工复核。</Typography.Text>
</Flex>
<div>
<Typography.Text>可编辑标题</Typography.Text>
<Input value={rewriteTitle} onChange={(event) => setRewriteTitle(event.target.value)} style={{ marginTop: 4 }} />
</div>
<div>
<Typography.Text>可编辑口播</Typography.Text>
<Input.TextArea rows={5} value={rewriteScript} onChange={(event) => setRewriteScript(event.target.value)} style={{ marginTop: 4 }} />
</div>
<div>
<Button type="primary" onClick={saveRewrite} disabled={materialPending}>
保存仿写结果
</Button>
</div>
</>
) : (
<div>
<Button type="primary" onClick={confirmRewrite} disabled={materialPending || !materialReadyForConfirm}>
确认仿写要求
</Button>
</div>
)}
</Flex>
</Card>
<Flex vertical gap={12}>
<Typography.Paragraph type="secondary" style={{ marginTop: 0 }}>每一步都保留真实状态;失败不会被显示为成功。</Typography.Paragraph>
<Flex vertical gap={12}>
<div>
<Button type="primary" onClick={processMaterial} loading={materialPending || material.download_status === 'running'}>
开始处理素材
</Button>
</div>
<Space wrap>
{stepTag(material.download_status, `下载:${material.download_status}`)}
{stepTag(material.audio_status, `音轨:${material.audio_status}`)}
{stepTag(material.transcription_status, `转写:${material.transcription_status}`)}
</Space>
{material.failure_reason ? (
<Alert type="error" showIcon title={`失败步骤:${material.failed_step || '未记录'};${material.failure_reason}`} />
) : null}
<div>
<Typography.Text strong>仿写要求</Typography.Text>
<Typography.Paragraph type="secondary" style={{ fontSize: 12, marginBottom: 4 }}>必须先确认要求,才允许保存可编辑结果。</Typography.Paragraph>
<Input.TextArea
rows={3}
value={rewriteRequirement}
onChange={(event) => setRewriteRequirement(event.target.value)}
disabled={Boolean(material.rewrite_confirmed_at) || materialPending}
/>
</div>
{material.rewrite_confirmed_at ? (
<>
<Flex gap={8} align="center">
<Button onClick={generateRewrite} disabled={materialPending}>
生成仿写草稿
</Button>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>生成结果不会自动发布,保存前必须人工复核。</Typography.Text>
</Flex>
<div>
<Typography.Text>可编辑标题</Typography.Text>
<Input value={rewriteTitle} onChange={(event) => setRewriteTitle(event.target.value)} style={{ marginTop: 4 }} />
</div>
<div>
<Typography.Text>可编辑口播</Typography.Text>
<Input.TextArea rows={5} value={rewriteScript} onChange={(event) => setRewriteScript(event.target.value)} style={{ marginTop: 4 }} />
</div>
<div>
<Button type="primary" onClick={saveRewrite} disabled={materialPending}>
保存仿写结果
</Button>
</div>
</>
) : (
<div>
<Button type="primary" onClick={confirmRewrite} disabled={materialPending || !materialReadyForConfirm}>
确认仿写要求
</Button>
</div>
)}
</Flex>
</Flex>
) : null}
</Drawer>
</Flex>
<Drawer open={Boolean(workDetail)} onClose={() => setWorkDetail(null)} size="large" title="作品详情">
{workDetail ? (