import React, { useState, useRef, useMemo } from 'react'; import CodeMirror from '@uiw/react-codemirror'; import { markdown, markdownLanguage } from '@codemirror/lang-markdown'; import { EditorView } from '@codemirror/view'; import { Space, Button, Tooltip, Card, Divider, Dropdown, Typography } from 'antd'; import { BoldOutlined, ItalicOutlined, FontSizeOutlined, MessageOutlined, CodeOutlined, LinkOutlined, TableOutlined, PictureOutlined, OrderedListOutlined, UnorderedListOutlined, LineOutlined, EyeOutlined, EditOutlined } from '@ant-design/icons'; import MarkdownRenderer from './MarkdownRenderer'; const { Text } = Typography; const MarkdownEditor = ({ value, onChange, onImageUpload, placeholder = '在这里编写内容...', height = 400, showImageUpload = true }) => { const editorRef = useRef(null); const imageInputRef = useRef(null); const [showPreview, setShowPreview] = useState(false); const editorExtensions = useMemo(() => [ markdown({ base: markdownLanguage }), EditorView.lineWrapping, EditorView.theme({ "&": { fontSize: "14px", border: "1px solid #d9d9d9", borderRadius: "0 0 8px 8px", borderTop: "none", }, ".cm-content": { fontFamily: "var(--ant-font-family-code), monospace", padding: "16px", minHeight: `${height}px`, }, "&.cm-focused": { outline: "none", borderColor: "#1677ff", boxShadow: "0 0 0 2px rgba(22, 119, 255, 0.1)", } }) ], [height]); const insertMarkdown = (before, after = '', placeholder = '') => { if (!editorRef.current?.view) return; const view = editorRef.current.view; const selection = view.state.selection.main; const selectedText = view.state.doc.sliceString(selection.from, selection.to); const text = selectedText || placeholder; const newText = `${before}${text}${after}`; view.dispatch({ changes: { from: selection.from, to: selection.to, insert: newText }, selection: { anchor: selection.from + before.length, head: selection.from + before.length + text.length } }); view.focus(); }; const toolbarActions = { bold: () => insertMarkdown('**', '**', '粗体'), italic: () => insertMarkdown('*', '*', '斜体'), heading: (level) => insertMarkdown('#'.repeat(level) + ' ', '', '标题'), quote: () => insertMarkdown('> ', '', '引用'), code: () => insertMarkdown('`', '`', '代码'), link: () => insertMarkdown('[', '](url)', '链接'), unorderedList: () => insertMarkdown('- ', '', '列表项'), orderedList: () => insertMarkdown('1. ', '', '列表项'), table: () => insertMarkdown('\n| 列1 | 列2 |\n| --- | --- |\n| 单元格 | 单元格 |\n', '', ''), hr: () => insertMarkdown('\n---\n', '', ''), image: () => imageInputRef.current?.click(), }; const headingMenu = { items: [1, 2, 3, 4, 5, 6].map(level => ({ key: level, label: `标题 ${level}`, onClick: () => toolbarActions.heading(level) })) }; return (