feat(studio): manage category briefs
This commit is contained in:
@@ -1,9 +1,15 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { PERM, requirePermission } from '@/auth/permissions'
|
||||
import { useCan } from '@/auth/store'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useState } from 'react'
|
||||
import type { ColumnDef } from '@tanstack/react-table'
|
||||
import type { StudioCategoryBrief } from '@/api/types'
|
||||
import { fetchCategoryBriefs } from '@/api/modules/studio'
|
||||
import { deleteCategoryBrief, fetchCategoryBriefs } from '@/api/modules/studio'
|
||||
import { handleApiError } from '@/lib/errors'
|
||||
import { CategoryBriefEditSheet } from '@/features/studio/category-brief-edit-sheet'
|
||||
import { useCategoryOptions } from '@/features/categories/use-categories'
|
||||
import { ConfirmDialog } from '@/components/confirm-dialog'
|
||||
import { useListPage } from '@/lib/list-page'
|
||||
import { DetailSheet } from '@/features/studio/detail-sheet'
|
||||
import { DataTable } from '@/components/data-table/data-table'
|
||||
@@ -16,10 +22,33 @@ export const Route = createFileRoute('/_authed/studio/category-briefs')({
|
||||
})
|
||||
|
||||
function CategoryBriefsPage() {
|
||||
const canManage = useCan(PERM.STUDIO_MANAGE)
|
||||
const queryClient = useQueryClient()
|
||||
const [detail, setDetail] = useState<StudioCategoryBrief | null>(null)
|
||||
const [editing, setEditing] = useState<StudioCategoryBrief | null>(null)
|
||||
const [creating, setCreating] = useState(false)
|
||||
const list = useListPage('studio-category-briefs', fetchCategoryBriefs)
|
||||
const { nameOf } = useCategoryOptions()
|
||||
|
||||
const refresh = () => {
|
||||
void queryClient.invalidateQueries({ queryKey: ['studio-category-briefs'] })
|
||||
void list.query.refetch()
|
||||
}
|
||||
|
||||
const remove = async (brief: StudioCategoryBrief) => {
|
||||
try {
|
||||
await deleteCategoryBrief(brief.id)
|
||||
refresh()
|
||||
} catch (error) {
|
||||
handleApiError(error)
|
||||
}
|
||||
}
|
||||
|
||||
const columns: ColumnDef<StudioCategoryBrief>[] = [
|
||||
{
|
||||
header: '分类',
|
||||
cell: ({ row }) => <span className="font-medium">{nameOf(row.original.category_id)}</span>,
|
||||
},
|
||||
{
|
||||
header: '分类简报',
|
||||
cell: ({ row }) => (
|
||||
@@ -36,16 +65,31 @@ function CategoryBriefsPage() {
|
||||
{
|
||||
header: '操作',
|
||||
cell: ({ row }) => (
|
||||
<Button size="sm" variant="ghost" onClick={() => setDetail(row.original)}>
|
||||
详情
|
||||
</Button>
|
||||
<div className="flex gap-1.5">
|
||||
<Button size="sm" variant="ghost" onClick={() => setDetail(row.original)}>详情</Button>
|
||||
{canManage && <Button size="sm" variant="outline" onClick={() => setEditing(row.original)}>编辑</Button>}
|
||||
{canManage && (
|
||||
<ConfirmDialog
|
||||
trigger={<Button size="sm" variant="destructive">删除</Button>}
|
||||
title="删除分类简报?"
|
||||
description="只删除简报,不会删除分类或相关内容。"
|
||||
confirmLabel="删除"
|
||||
destructive
|
||||
onConfirm={() => remove(row.original)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader title="分类简报" description="Agent 对各分类的内容定位分析(含聚合计数)" />
|
||||
<PageHeader
|
||||
title="分类简报"
|
||||
description="Agent 对各分类的内容定位分析(含聚合计数)"
|
||||
actions={canManage ? <Button onClick={() => setCreating(true)}>新建简报</Button> : undefined}
|
||||
/>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={list.rows}
|
||||
@@ -61,7 +105,7 @@ function CategoryBriefsPage() {
|
||||
fields={[
|
||||
{
|
||||
label: '分类',
|
||||
value: <code className="font-mono text-xs">{detail?.category_id}</code>,
|
||||
value: detail ? nameOf(detail.category_id) : undefined,
|
||||
},
|
||||
{ label: '定位描述', value: detail?.description },
|
||||
{ label: '目标受众', value: detail?.target_audience },
|
||||
@@ -75,6 +119,17 @@ function CategoryBriefsPage() {
|
||||
]}
|
||||
jsonBlocks={[{ label: '内容切入角度', value: detail?.content_angles }]}
|
||||
/>
|
||||
<CategoryBriefEditSheet
|
||||
brief={editing}
|
||||
creating={creating}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setEditing(null)
|
||||
setCreating(false)
|
||||
}
|
||||
}}
|
||||
onSaved={refresh}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user