fix(ui): 竞品分析素材流程改 Drawer、日期筛选取 DatePicker、选择素材按钮降级并区分已选中态(走查 P2-#13)
This commit is contained in:
@@ -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 ? (
|
||||
|
||||
Reference in New Issue
Block a user