"use client"; import { CopyOutlined, DeleteOutlined, EditOutlined, EyeOutlined, PlusOutlined, ReloadOutlined, SearchOutlined } from "@ant-design/icons"; import { ProTable, type ProColumns } from "@ant-design/pro-components"; import { Button, Card, Col, Flex, Form, Image, Input, Modal, Row, Select, Space, Tag, Tooltip, Typography } from "antd"; import { useEffect, useState } from "react"; import { useCopyText } from "@/hooks/use-copy-text"; import type { AdminAsset } from "@/services/api/admin"; import { useAdminAssets } from "./use-admin-assets"; type AssetFormValues = Partial & { tagText?: string }; const typeOptions = [ { label: "全部类型", value: "" }, { label: "文本", value: "text" }, { label: "图片", value: "image" }, ]; const editTypeOptions = typeOptions.slice(1); export default function AdminAssetsPage() { const { assets, tags, keyword, kind, tag, page, pageSize, total, isLoading, searchAssets, changeKind, changeTag, changePage, changePageSize, resetFilters, refreshAssets, saveAsset: saveAdminAsset, deleteAsset } = useAdminAssets(); const copyText = useCopyText(); const [form] = Form.useForm(); const [keywordText, setKeywordText] = useState(keyword); const [editingAsset, setEditingAsset] = useState | null>(null); const [detailAsset, setDetailAsset] = useState(null); const [deletingAsset, setDeletingAsset] = useState(null); const formType = Form.useWatch("type", form) || editingAsset?.type || "text"; const tagOptions = tags.map((item) => ({ label: item, value: item })); useEffect(() => { if (editingAsset) form.setFieldsValue({ ...editingAsset, tagText: editingAsset.tags?.join(", ") || "" }); }, [editingAsset, form]); useEffect(() => setKeywordText(keyword), [keyword]); const saveAsset = async () => { const value = await form.validateFields(); const nextType = value.type || "text"; await saveAdminAsset({ ...editingAsset, ...value, type: nextType, coverUrl: value.coverUrl || (nextType === "image" ? value.url : ""), tags: (value.tagText || "") .split(",") .map((item) => item.trim()) .filter(Boolean), }); setEditingAsset(null); }; const columns: ProColumns[] = [ { title: "封面", dataIndex: "coverUrl", width: 88, render: (_, item) => {item.title}, }, { title: "标题", dataIndex: "title", width: 260, render: (_, item) => ( setDetailAsset(item)}> {item.title} ), }, { title: "类型", dataIndex: "type", width: 84, render: (_, item) => {item.type === "image" ? "图片" : "文本"}, }, { title: "标签", dataIndex: "tags", width: 180, render: (_, item) => ( {(item.tags || []).slice(0, 3).map((tag) => ( {tag} ))} ), }, { title: "分类", dataIndex: "category", width: 120, render: (_, item) => {item.category || "未标注"}, }, { title: "操作", key: "actions", width: 112, align: "right", render: (_, item) => ( rowKey="id" columns={columns} dataSource={assets} loading={isLoading} search={false} defaultSize="middle" tableLayout="fixed" cardProps={{ variant: "borderless" }} headerTitle={ 素材列表 {total} 条 } options={{ density: true, setting: true, reload: () => void refreshAssets() }} toolBarRender={() => [ , ]} pagination={{ current: page, pageSize, total, showSizeChanger: true, pageSizeOptions: [10, 20, 50, 100], showTotal: (value) => `共 ${value} 条`, onChange: (nextPage, nextPageSize) => (nextPageSize !== pageSize ? changePageSize(nextPageSize) : changePage(nextPage)), }} /> setEditingAsset(null)} onOk={() => void saveAsset()} okText="保存" cancelText="取消" destroyOnHidden>
{formType === "image" ? ( ) : ( )}
setDetailAsset(null)} footer={}> {detailAsset ? ( {detailAsset.title} {detailAsset.title} {detailAsset.type === "image" ? "图片" : "文本"} {detailAsset.category ? {detailAsset.category} : null} {(detailAsset.tags || []).map((tag) => ( {tag} ))} {detailAsset.description ? ( {detailAsset.description} ) : null} ) : null} setDeletingAsset(null)} onOk={async () => { if (!deletingAsset) return; await deleteAsset(deletingAsset.id); setDeletingAsset(null); }} okText="删除" okButtonProps={{ danger: true }} cancelText="取消" > 确定删除「{deletingAsset?.title}」吗?删除后会从服务器素材库中移除。 ); }