feat(studio): authors/series/articles/subtopics/briefs/style-presets + agent tokens (show-once)

This commit is contained in:
2026-07-07 22:30:27 +08:00
parent 36df03baad
commit 61cb549e72
14 changed files with 1184 additions and 32 deletions
+76
View File
@@ -0,0 +1,76 @@
import { createFileRoute } from '@tanstack/react-router'
import { useState } from 'react'
import type { ColumnDef } from '@tanstack/react-table'
import type { StudioSeries } from '@/api/types'
import { fetchSeries } from '@/api/modules/studio'
import { useListPage } from '@/lib/list-page'
import { DetailSheet } from '@/features/studio/detail-sheet'
import { DataTable } from '@/components/data-table/data-table'
import { PageHeader } from '@/components/page-header'
import { StatusPill } from '@/components/status-pill'
import { Button } from '@/components/ui/button'
export const Route = createFileRoute('/_authed/studio/series')({
component: SeriesPage,
})
function SeriesPage() {
const [detail, setDetail] = useState<StudioSeries | null>(null)
const list = useListPage('studio-series', fetchSeries)
const columns: ColumnDef<StudioSeries>[] = [
{
header: '系列目标',
cell: ({ row }) => (
<div className="max-w-96 truncate font-medium">{row.original.goal ?? '(未命名系列)'}</div>
),
},
{
header: '计划篇数',
cell: ({ row }) => row.original.target_article_count ?? '—',
},
{ header: '状态', cell: ({ row }) => <StatusPill status={row.original.status} /> },
{
header: '更新时间',
cell: ({ row }) => new Date(row.original.updated_at).toLocaleString('zh-CN'),
},
{
header: '操作',
cell: ({ row }) => (
<Button size="sm" variant="ghost" onClick={() => setDetail(row.original)}>
</Button>
),
},
]
return (
<div>
<PageHeader title="文章系列" description="机器人作者的系列规划(目标 / 读者旅程 / 计划列表)" />
<DataTable
columns={columns}
data={list.rows}
pagination={list.pagination}
loading={list.loading}
onPageChange={list.setPage}
onPageSizeChange={list.setPageSize}
/>
<DetailSheet
open={detail !== null}
onOpenChange={(open) => !open && setDetail(null)}
title={detail?.goal ?? '系列详情'}
fields={[
{ label: 'ID', value: <code className="font-mono text-xs">{detail?.id}</code> },
{ label: '状态', value: detail && <StatusPill status={detail.status} /> },
{ label: '计划篇数', value: detail?.target_article_count },
{ label: '读者旅程', value: detail?.reader_journey },
{
label: '作者',
value: <code className="font-mono text-xs">{detail?.robot_author_id}</code>,
},
]}
jsonBlocks={[{ label: '计划文章列表', value: detail?.planned_articles }]}
/>
</div>
)
}