import { Button, Card, Empty, Form, Space, Spin, message, theme } from "antd"; import NodeMenu from "./NodeMenu"; import { api, usePost } from "@nice/client"; import { ObjectType, postDetailSelect, PostDto, PostType, Prisma, RolePerms, Taxonomy, } from "@nice/common"; import TermSelect from "../../models/term/term-select"; import DepartmentSelect from "../../models/department/department-select"; import { useEffect, useMemo, useRef, useState } from "react"; import toast from "react-hot-toast"; import { MindElixirInstance } from "mind-elixir"; import MindElixir from "mind-elixir"; import { useTusUpload } from "@web/src/hooks/useTusUpload"; import { useNavigate } from "react-router-dom"; import { useAuth } from "@web/src/providers/auth-provider"; const MIND_OPTIONS = { direction: MindElixir.SIDE, draggable: true, contextMenu: true, toolBar: true, nodeMenu: true, keypress: true, locale: "zh_CN" as const, theme: { name: "Latte", palette: [ "#dd7878", "#ea76cb", "#8839ef", "#e64553", "#fe640b", "#df8e1d", "#40a02b", "#209fb5", "#1e66f5", "#7287fd", ], cssVar: { "--main-color": "#444446", "--main-bgcolor": "#ffffff", "--color": "#777777", "--bgcolor": "#f6f6f6", "--panel-color": "#444446", "--panel-bgcolor": "#ffffff", "--panel-border-color": "#eaeaea", }, }, }; export default function MindEditor({ id }: { id?: string }) { const containerRef = useRef(null); const [instance, setInstance] = useState(null); const { isAuthenticated, user, hasSomePermissions } = useAuth(); const { data: post, isLoading }: { data: PostDto; isLoading: boolean } = api.post.findFirst.useQuery({ where: { id, }, select: postDetailSelect, }); const canEdit: boolean = useMemo(() => { //登录了且是作者、超管、无id新建模式 const isAuth = isAuthenticated && user?.id == post?.author.id return !Boolean(id) || isAuth || hasSomePermissions(RolePerms.MANAGE_ANY_POST); }, [user]) const navigate = useNavigate(); const { create, update } = usePost(); const { data: taxonomies } = api.taxonomy.getAll.useQuery({ type: ObjectType.COURSE, }); const { handleFileUpload } = useTusUpload(); const [form] = Form.useForm(); useEffect(() => { if (post && form && instance && id) { console.log(post); instance.refresh((post as any).meta); const deptIds = (post?.depts || [])?.map((dept) => dept.id); const formData = { title: post.title, deptIds: deptIds, }; post.terms?.forEach((term) => { formData[term.taxonomyId] = term.id; // 假设 taxonomyName 是您在 Form.Item 中使用的 name }); form.setFieldsValue(formData); } }, [post, form, instance, id]); useEffect(() => { if (!containerRef.current) return; const mind = new MindElixir({ ...MIND_OPTIONS, el: containerRef.current, before:{ beginEdit(){ return canEdit } }, draggable: canEdit, // 禁用拖拽 contextMenu: canEdit, // 禁用右键菜单 toolBar: canEdit, // 禁用工具栏 nodeMenu: canEdit, // 禁用节点右键菜单 keypress: canEdit, // 禁用键盘快捷键 }); mind.init(MindElixir.new("新学习路径")); containerRef.current.hidden = true; setInstance(mind); }, [canEdit]); useEffect(() => { if ((!id || post) && instance) { containerRef.current.hidden = false; instance.toCenter(); instance.refresh((post as any)?.meta); } }, [id, post, instance]); const handleSave = async () => { if (!instance) return; const values = form.getFieldsValue(); const imgBlob = await instance?.exportPng(); handleFileUpload( imgBlob, async (result) => { const termIds = taxonomies .map((tax) => values[tax.id]) .filter((id) => id); const deptIds = (values?.deptIds || []) as string[]; const { theme, ...data } = instance.getData(); try { if (post && id) { const params: Prisma.PostUpdateArgs = { where: { id, }, data: { title: data.nodeData.topic, meta: { ...data, thumbnail: result.compressedUrl, }, terms: { set: termIds.map((id) => ({ id })), }, depts: { set: deptIds.map((id) => ({ id })), }, updatedAt: new Date(), }, }; await update.mutateAsync(params); toast.success("更新成功"); } else { const params: Prisma.PostCreateInput = { type: PostType.PATH, title: data.nodeData.topic, meta: { ...data, thumbnail: result.compressedUrl }, terms: { connect: termIds.map((id) => ({ id })), }, depts: { connect: deptIds.map((id) => ({ id })), }, updatedAt: new Date(), }; const res = await create.mutateAsync({ data: params }); navigate(`/path/editor/${res.id}`, { replace: true }); toast.success("创建成功"); } } catch (error) { toast.error("保存失败"); throw error; } console.log(result); }, (error) => { }, `mind-thumb-${new Date().toString()}` ); }; useEffect(()=>{ containerRef.current.style.height = `${Math.floor(window.innerHeight/1.25)}px` },[]) return (
{canEdit && taxonomies && (
{taxonomies.map((tax, index) => ( ))}
)}
e.preventDefault()}/> {canEdit && instance && } {isLoading && (
)} {!post && id && !isLoading && (
)}
); }