import { createFileRoute } from '@tanstack/react-router' import { PERM, requirePermission } from '@/auth/permissions' import { useState } from 'react' import type { ColumnDef } from '@tanstack/react-table' import type { StudioArticle } from '@/api/types' import { fetchArticles } from '@/api/modules/studio' import { useListPage } from '@/lib/list-page' import { ArticlePreviewSheet } from '@/features/studio/article-preview-sheet' 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' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' export const Route = createFileRoute('/_authed/studio/articles')({ beforeLoad: () => requirePermission(PERM.STUDIO_READ), component: ArticlesPage, }) const STATUSES = ['planned', 'drafting', 'drafted', 'published', 'scheduled'] as const function ArticlesPage() { const [status, setStatus] = useState('all') const [detail, setDetail] = useState(null) const [preview, setPreview] = useState(null) const list = useListPage( 'studio-articles', fetchArticles, status === 'all' ? {} : { status }, ) const columns: ColumnDef[] = [ { header: '文章', cell: ({ row }) => (
{row.original.title ?? '(未命名)'}
系列第 {row.original.article_number} 篇
), }, { header: '状态', cell: ({ row }) => }, { header: 'Dimzou', cell: ({ row }) => row.original.dimzou_publication_id ? ( doc #{row.original.dimzou_document_id} · pub #{row.original.dimzou_publication_id} ) : row.original.dimzou_document_id ? ( 草稿 doc #{row.original.dimzou_document_id} ) : ( 未建稿 ), }, { header: '更新时间', cell: ({ row }) => new Date(row.original.updated_at).toLocaleString('zh-CN'), }, { header: '操作', cell: ({ row }) => (
), }, ] return (
全部状态 {STATUSES.map((s) => ( ))} } /> !open && setDetail(null)} title={detail?.title ?? '文章详情'} description={detail?.summary ?? undefined} fields={[ { label: 'ID', value: {detail?.id} }, { label: '状态', value: detail && }, { label: '系列内序号', value: detail?.article_number }, { label: '标签', value: detail?.tags?.join('、') }, { label: 'SEO 关键词', value: detail?.seo_keywords?.join('、') }, { label: 'CTA', value: detail?.cta }, { label: '起草模型', value: detail?.drafting_model ? [detail.drafting_model.provider, detail.drafting_model.model] .filter(Boolean) .join(' / ') || '—' : '—', }, { label: '封面提示词', value: detail?.cover_image_prompt }, { label: 'Dimzou 文档', value: detail?.dimzou_document_id ? `#${detail.dimzou_document_id}` : '未建稿', }, { label: 'Dimzou 发布', value: detail?.dimzou_publication_id ? `#${detail.dimzou_publication_id}` : '未发布', }, ]} jsonBlocks={[ { label: '要点 key_takeaways', value: detail?.key_takeaways }, { label: '大纲 outline', value: detail?.outline }, { label: '起草模型 drafting_model', value: detail?.drafting_model }, { label: '计划 plan', value: detail?.plan }, { label: '发布排期', value: detail?.publish_schedule }, ]} /> !open && setPreview(null)} />
) }