'use client'; import React, { useState, useEffect, useRef } from 'react'; import { Box, Button, Dialog, DialogTitle, DialogContent, DialogActions, CircularProgress, Typography, Divider, Chip, Switch, FormControlLabel, Alert, DialogContentText } from '@mui/material'; import DeleteIcon from '@mui/icons-material/Delete'; import SaveIcon from '@mui/icons-material/Save'; import ReactMarkdown from 'react-markdown'; import { useTranslation } from 'react-i18next'; import 'github-markdown-css/github-markdown-light.css'; export default function MarkdownViewDialog({ open, text, onClose, projectId, onSaveSuccess }) { const { t } = useTranslation(); const [customSplitMode, setCustomSplitMode] = useState(false); const [splitPoints, setSplitPoints] = useState([]); const [selectedText, setSelectedText] = useState(''); const [savedMessage, setSavedMessage] = useState(''); const [confirmDialogOpen, setConfirmDialogOpen] = useState(false); const [saving, setSaving] = useState(false); const [error, setError] = useState(''); const contentRef = useRef(null); const [chunksPreview, setChunksPreview] = useState([]); // 根据分块点计算每个块的字数 const calculateChunksPreview = points => { if (!text || !text.content) return []; const content = text.content; const sortedPoints = [...points].sort((a, b) => a.position - b.position); const chunks = []; let startPos = 0; // 计算每个分块 for (let i = 0; i < sortedPoints.length; i++) { const endPos = sortedPoints[i].position; const chunkContent = content.substring(startPos, endPos); if (chunkContent.trim().length > 0) { chunks.push({ index: i + 1, length: chunkContent.length, preview: chunkContent.substring(0, 20) + (chunkContent.length > 20 ? '...' : '') }); } startPos = endPos; } // 添加最后一个分块 const lastChunkContent = content.substring(startPos); if (lastChunkContent.trim().length > 0) { chunks.push({ index: chunks.length + 1, length: lastChunkContent.length, preview: lastChunkContent.substring(0, 20) + (lastChunkContent.length > 20 ? '...' : '') }); } return chunks; }; // 重置组件状态 useEffect(() => { if (!open) { setSplitPoints([]); setCustomSplitMode(false); setSelectedText(''); setSavedMessage(''); } }, [open]); // 当分块点变化时更新预览 useEffect(() => { if (splitPoints.length > 0 && text?.content) { const preview = calculateChunksPreview(splitPoints); setChunksPreview(preview); } else { setChunksPreview([]); } }, [splitPoints, text?.content]); // 处理用户选择文本事件 const handleTextSelection = () => { if (!customSplitMode) return; const selection = window.getSelection(); if (!selection.toString().trim()) return; // 获取选择的文本内容和位置 const selectedContent = selection.toString(); // 计算选择位置在文档中的偏移量 const range = selection.getRangeAt(0); const preCaretRange = range.cloneRange(); preCaretRange.selectNodeContents(contentRef.current); preCaretRange.setEnd(range.endContainer, range.endOffset); const position = preCaretRange.toString().length; // 添加到分割点列表 const newPoint = { id: Date.now(), position, preview: selectedContent.substring(0, 40) + (selectedContent.length > 40 ? '...' : '') }; setSplitPoints(prev => [...prev, newPoint].sort((a, b) => a.position - b.position)); setSelectedText(''); }; // 删除分割点 const handleDeletePoint = id => { setSplitPoints(prev => prev.filter(point => point.id !== id)); }; // 弹出确认对话框 const handleConfirmSave = () => { setConfirmDialogOpen(true); }; // 取消保存 const handleCancelSave = () => { setConfirmDialogOpen(false); }; // 确认并执行保存 const handleSavePoints = async () => { // 输出调试信息 console.log('保存分块点时的数据:', { projectId, text: text ? { fileId: text.fileId, fileName: text.fileName, contentLength: text.content ? text.content.length : 0 } : null, splitPointsCount: splitPoints.length }); if (!text) { setError(t('textSplit.missingRequiredData') + ': text 为空'); return; } if (!text.fileId) { setError(t('textSplit.missingRequiredData') + ': fileId 不存在'); return; } if (!text.fileName) { setError(t('textSplit.missingRequiredData') + ': fileName 不存在'); return; } if (!text.content) { setError(t('textSplit.missingRequiredData') + ': content 不存在'); return; } if (!projectId) { setError(t('textSplit.missingRequiredData') + ': projectId 不存在'); return; } setConfirmDialogOpen(false); setSaving(true); setError(''); try { // 准备要发送的数据 const customSplitData = { fileId: text.fileId, fileName: text.fileName, content: text.content, splitPoints: splitPoints.map(point => ({ position: point.position, preview: point.preview })) }; // 发送请求到待创建的API接口 const response = await fetch(`/api/projects/${projectId}/custom-split`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(customSplitData) }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || t('textSplit.customSplitFailed')); } // 保存成功 setSavedMessage(t('textSplit.customSplitSuccess')); // 短暂显示成功消息后关闭对话框并刷新列表 setTimeout(() => { setSavedMessage(''); // 关闭对话框 onClose(); // 调用父组件的刷新方法(如果提供了) if (typeof onSaveSuccess === 'function') { onSaveSuccess(); } }, 1500); } catch (err) { console.error('保存自定义分块出错:', err); setError(err.message || t('textSplit.customSplitFailed')); } finally { setSaving(false); } }; return ( {text ? text.fileName : ''} setCustomSplitMode(e.target.checked)} color="primary" /> } label={t('textSplit.customSplitMode')} sx={{ ml: 2 }} /> {customSplitMode && ( {t('textSplit.customSplitInstructions')} {/* 分割点列表 */} {splitPoints.length > 0 && ( {t('textSplit.splitPointsList')} ({splitPoints.length}): {splitPoints.map((point, index) => ( handleDeletePoint(point.id)} deleteIcon={} color="primary" variant="outlined" /> ))} {/* 文本块字数预览 */} {chunksPreview.length > 0 && ( {t('textSplit.chunksPreview')} {chunksPreview.map(chunk => ( ))} )} )} {/* 保存按钮 */} {/* 提示消息 */} {savedMessage && ( {savedMessage} )} {error && ( {error} )} )} {text ? ( {/* 渲染带有分割点标记的内容 */} {customSplitMode && splitPoints.length > 0 ? (
                  {text.content.split('').map((char, index) => {
                    const isSplitPoint = splitPoints.some(point => point.position === index);
                    const splitPointIndex = splitPoints.findIndex(point => point.position === index);

                    if (isSplitPoint) {
                      return (
                        
                          
                            
                              {splitPointIndex + 1}
                            
                          
                          {char}
                        
                      );
                    }
                    return char;
                  })}
                
) : (
{text.content}
)}
) : ( )}
{/* 确认对话框 */} {t('textSplit.confirmCustomSplitTitle')} {t('textSplit.confirmCustomSplitMessage')}
); }