加入脑图功能
parent
c7846a9f03
commit
2735697fc7
|
|
@ -17,11 +17,9 @@ function App() {
|
||||||
// Load user from localStorage on app start
|
// Load user from localStorage on app start
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const savedUser = localStorage.getItem('iMeetingUser');
|
const savedUser = localStorage.getItem('iMeetingUser');
|
||||||
console.log('Saved user from localStorage:', savedUser);
|
|
||||||
if (savedUser) {
|
if (savedUser) {
|
||||||
try {
|
try {
|
||||||
const parsedUser = JSON.parse(savedUser);
|
const parsedUser = JSON.parse(savedUser);
|
||||||
console.log('Parsed user:', parsedUser);
|
|
||||||
setUser(parsedUser);
|
setUser(parsedUser);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error parsing saved user:', error);
|
console.error('Error parsing saved user:', error);
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,9 @@ const MindMap = ({ meetingId, meetingTitle, meeting, formatDateTime }) => {
|
||||||
// 移除分隔线
|
// 移除分隔线
|
||||||
processed = processed.replace(/^---+$/gm, '');
|
processed = processed.replace(/^---+$/gm, '');
|
||||||
|
|
||||||
// 如果没有主标题,添加一个
|
// 检查是否已经有一级标题,如果没有才添加
|
||||||
if (!processed.startsWith('# ')) {
|
const hasMainTitle = processed.match(/^#+\s+.*会议总结/m);
|
||||||
|
if (!processed.startsWith('# ') && !hasMainTitle) {
|
||||||
processed = `# 会议总结\n\n${processed}`;
|
processed = `# 会议总结\n\n${processed}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,18 +97,25 @@ const MindMap = ({ meetingId, meetingTitle, meeting, formatDateTime }) => {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
while (i < lines.length) {
|
while (i < lines.length) {
|
||||||
const line = lines[i].trim();
|
const line = lines[i];
|
||||||
|
const trimmedLine = line.trim();
|
||||||
|
|
||||||
if (line === '') {
|
if (trimmedLine === '') {
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理标题行
|
// 处理标题行
|
||||||
if (line.match(/^#+\s+/)) {
|
if (trimmedLine.match(/^#+\s+/)) {
|
||||||
// 清理标题格式,移除粗体和多余符号
|
// 清理标题格式,移除粗体和多余符号
|
||||||
let cleanTitle = line.replace(/\*\*([^*]+)\*\*/g, '$1'); // 移除粗体
|
let cleanTitle = trimmedLine.replace(/\*\*([^*]+)\*\*/g, '$1'); // 移除粗体
|
||||||
cleanTitle = cleanTitle.replace(/[*_]/g, ''); // 移除其他markdown符号
|
cleanTitle = cleanTitle.replace(/[*_]/g, ''); // 移除其他markdown符号
|
||||||
|
|
||||||
|
// 如果是包含"会议总结"的标题,且不是一级标题,调整为一级标题
|
||||||
|
if (cleanTitle.includes('会议总结') && !cleanTitle.startsWith('# ')) {
|
||||||
|
cleanTitle = `# ${cleanTitle.replace(/^#+\s*/, '')}`;
|
||||||
|
}
|
||||||
|
|
||||||
processedLines.push(cleanTitle);
|
processedLines.push(cleanTitle);
|
||||||
|
|
||||||
// 查看下一个非空行
|
// 查看下一个非空行
|
||||||
|
|
@ -119,16 +127,19 @@ const MindMap = ({ meetingId, meetingTitle, meeting, formatDateTime }) => {
|
||||||
// 如果下一行不是标题、列表或表格,将段落内容转换为列表项
|
// 如果下一行不是标题、列表或表格,将段落内容转换为列表项
|
||||||
if (j < lines.length) {
|
if (j < lines.length) {
|
||||||
const nextLine = lines[j].trim();
|
const nextLine = lines[j].trim();
|
||||||
if (!nextLine.match(/^#+\s+/) && !nextLine.match(/^[-*+]\s+/) && !nextLine.includes('|') && nextLine.length > 0) {
|
const nextLineOriginal = lines[j];
|
||||||
|
if (!nextLine.match(/^#+\s+/) && !nextLine.match(/^[-*+]\s+/) && !nextLineOriginal.match(/^\s+[-*+]\s+/) && !nextLine.includes('|') && nextLine.length > 0) {
|
||||||
// 收集段落内容直到下一个标题、列表或表格
|
// 收集段落内容直到下一个标题、列表或表格
|
||||||
const paragraphLines = [];
|
const paragraphLines = [];
|
||||||
while (j < lines.length) {
|
while (j < lines.length) {
|
||||||
const currentLine = lines[j].trim();
|
const currentLine = lines[j].trim();
|
||||||
|
const currentLineOriginal = lines[j];
|
||||||
if (currentLine === '') {
|
if (currentLine === '') {
|
||||||
j++;
|
j++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (currentLine.match(/^#+\s+/) || currentLine.match(/^[-*+]\s+/) || currentLine.includes('|')) {
|
// 遇到标题、任何列表(包括缩进列表)或表格就停止
|
||||||
|
if (currentLine.match(/^#+\s+/) || currentLine.match(/^[-*+]\s+/) || currentLineOriginal.match(/^\s+[-*+]\s+/) || currentLine.includes('|')) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
paragraphLines.push(currentLine);
|
paragraphLines.push(currentLine);
|
||||||
|
|
@ -163,18 +174,21 @@ const MindMap = ({ meetingId, meetingTitle, meeting, formatDateTime }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 处理列表项
|
// 处理列表项,只保留顶级列表项(没有缩进的第一层)
|
||||||
else if (line.match(/^[-*+]\s+/)) {
|
else if (trimmedLine.match(/^[-*+]\s+/)) {
|
||||||
const cleanListItem = line.replace(/\*\*([^*]+)\*\*/g, '$1'); // 移除粗体
|
// 检查原始行是否有缩进(以空格或制表符开头)
|
||||||
processedLines.push(cleanListItem);
|
if (!line.match(/^\s/)) {
|
||||||
|
const cleanListItem = trimmedLine.replace(/\*\*([^*]+)\*\*/g, '$1'); // 移除粗体
|
||||||
|
processedLines.push(cleanListItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 保持表格原样,让markmap自己处理
|
// 保持表格原样,让markmap自己处理
|
||||||
else if (line.includes('|')) {
|
else if (trimmedLine.includes('|')) {
|
||||||
processedLines.push(line);
|
processedLines.push(trimmedLine);
|
||||||
}
|
}
|
||||||
// 处理其他普通段落(如果前面没有被处理)
|
// 处理其他普通段落(如果前面没有被处理)
|
||||||
else if (line.length > 0 && !line.match(/\*\*总字数:\d+字\*\*/)) {
|
else if (trimmedLine.length > 0 && !trimmedLine.match(/\*\*总字数:\d+字\*\*/)) {
|
||||||
processedLines.push(`- ${line}`);
|
processedLines.push(`- ${trimmedLine}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
|
|
@ -193,14 +207,10 @@ const MindMap = ({ meetingId, meetingTitle, meeting, formatDateTime }) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const processedMarkdown = preprocessMarkdownForMindMap(markdown);
|
const processedMarkdown = preprocessMarkdownForMindMap(markdown);
|
||||||
console.log('原始markdown内容:', markdown);
|
|
||||||
console.log('预处理后的markdown:', processedMarkdown);
|
|
||||||
|
|
||||||
const transformer = new Transformer();
|
const transformer = new Transformer();
|
||||||
const { root } = transformer.transform(processedMarkdown);
|
const { root } = transformer.transform(processedMarkdown);
|
||||||
|
|
||||||
console.log('转换后的思维导图数据:', root);
|
|
||||||
|
|
||||||
if (markmapRef.current) {
|
if (markmapRef.current) {
|
||||||
markmapRef.current.setData(root);
|
markmapRef.current.setData(root);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@ import UserManagement from '../components/admin/UserManagement';
|
||||||
import SystemConfiguration from '../components/admin/SystemConfiguration';
|
import SystemConfiguration from '../components/admin/SystemConfiguration';
|
||||||
import './AdminManagement.css';
|
import './AdminManagement.css';
|
||||||
|
|
||||||
const { TabPane } = Tabs;
|
|
||||||
|
|
||||||
const AdminManagement = () => {
|
const AdminManagement = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
|
@ -28,20 +26,22 @@ const AdminManagement = () => {
|
||||||
</header>
|
</header>
|
||||||
<div className="admin-content">
|
<div className="admin-content">
|
||||||
<div className="admin-wrapper">
|
<div className="admin-wrapper">
|
||||||
<Tabs defaultActiveKey="userManagement" className="admin-tabs">
|
<Tabs
|
||||||
<TabPane
|
defaultActiveKey="userManagement"
|
||||||
tab={<span><Users size={16} /> 用户管理</span>}
|
className="admin-tabs"
|
||||||
key="userManagement"
|
items={[
|
||||||
>
|
{
|
||||||
<UserManagement />
|
key: 'userManagement',
|
||||||
</TabPane>
|
label: <span><Users size={16} /> 用户管理</span>,
|
||||||
<TabPane
|
children: <UserManagement />
|
||||||
tab={<span><Settings size={16} /> 系统配置</span>}
|
},
|
||||||
key="systemConfiguration"
|
{
|
||||||
>
|
key: 'systemConfiguration',
|
||||||
<SystemConfiguration />
|
label: <span><Settings size={16} /> 系统配置</span>,
|
||||||
</TabPane>
|
children: <SystemConfiguration />
|
||||||
</Tabs>
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -39,14 +39,10 @@ const Dashboard = ({ user, onLogout }) => {
|
||||||
const fetchUserData = async () => {
|
const fetchUserData = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
console.log('Fetching user data for user_id:', user.user_id);
|
|
||||||
|
|
||||||
const userResponse = await apiClient.get(buildApiUrl(API_ENDPOINTS.USERS.DETAIL(user.user_id)));
|
const userResponse = await apiClient.get(buildApiUrl(API_ENDPOINTS.USERS.DETAIL(user.user_id)));
|
||||||
console.log('User response:', userResponse.data);
|
|
||||||
setUserInfo(userResponse.data);
|
setUserInfo(userResponse.data);
|
||||||
|
|
||||||
const meetingsResponse = await apiClient.get(buildApiUrl(`${API_ENDPOINTS.MEETINGS.LIST}?user_id=${user.user_id}`));
|
const meetingsResponse = await apiClient.get(buildApiUrl(`${API_ENDPOINTS.MEETINGS.LIST}?user_id=${user.user_id}`));
|
||||||
console.log('Meetings response:', meetingsResponse.data);
|
|
||||||
setMeetings(meetingsResponse.data);
|
setMeetings(meetingsResponse.data);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ import MeetingSummary from '../components/MeetingSummary';
|
||||||
import { Tabs } from 'antd';
|
import { Tabs } from 'antd';
|
||||||
import './MeetingDetails.css';
|
import './MeetingDetails.css';
|
||||||
|
|
||||||
const { TabPane } = Tabs;
|
|
||||||
|
|
||||||
const MeetingDetails = ({ user }) => {
|
const MeetingDetails = ({ user }) => {
|
||||||
const { meeting_id } = useParams();
|
const { meeting_id } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
@ -224,15 +222,11 @@ const MeetingDetails = ({ user }) => {
|
||||||
const transcriptResponse = await apiClient.get(`${baseUrl}${transcriptEndpoint}`);
|
const transcriptResponse = await apiClient.get(`${baseUrl}${transcriptEndpoint}`);
|
||||||
setTranscript(transcriptResponse.data);
|
setTranscript(transcriptResponse.data);
|
||||||
|
|
||||||
console.log('First transcript item:', transcriptResponse.data[0]);
|
|
||||||
|
|
||||||
// 现在使用speaker_id字段进行分组
|
// 现在使用speaker_id字段进行分组
|
||||||
const allSpeakerIds = transcriptResponse.data
|
const allSpeakerIds = transcriptResponse.data
|
||||||
.map(item => item.speaker_id)
|
.map(item => item.speaker_id)
|
||||||
.filter(speakerId => speakerId !== null && speakerId !== undefined);
|
.filter(speakerId => speakerId !== null && speakerId !== undefined);
|
||||||
|
|
||||||
console.log('Extracted speaker IDs:', allSpeakerIds);
|
|
||||||
|
|
||||||
const uniqueSpeakers = [...new Set(allSpeakerIds)]
|
const uniqueSpeakers = [...new Set(allSpeakerIds)]
|
||||||
.map(speakerId => {
|
.map(speakerId => {
|
||||||
const segment = transcriptResponse.data.find(item => item.speaker_id === speakerId);
|
const segment = transcriptResponse.data.find(item => item.speaker_id === speakerId);
|
||||||
|
|
@ -243,7 +237,6 @@ const MeetingDetails = ({ user }) => {
|
||||||
})
|
})
|
||||||
.sort((a, b) => a.speaker_id - b.speaker_id); // 按speaker_id数值排序
|
.sort((a, b) => a.speaker_id - b.speaker_id); // 按speaker_id数值排序
|
||||||
|
|
||||||
console.log('Final unique speakers:', uniqueSpeakers);
|
|
||||||
setSpeakerList(uniqueSpeakers);
|
setSpeakerList(uniqueSpeakers);
|
||||||
|
|
||||||
// 初始化编辑状态
|
// 初始化编辑状态
|
||||||
|
|
@ -467,9 +460,6 @@ const MeetingDetails = ({ user }) => {
|
||||||
|
|
||||||
const handleSpeakerEditOpen = () => {
|
const handleSpeakerEditOpen = () => {
|
||||||
console.log('Opening speaker edit modal');
|
console.log('Opening speaker edit modal');
|
||||||
console.log('Current transcript:', transcript);
|
|
||||||
console.log('Current speakerList:', speakerList);
|
|
||||||
console.log('Current editingSpeakers:', editingSpeakers);
|
|
||||||
setShowSpeakerEdit(true);
|
setShowSpeakerEdit(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -947,26 +937,37 @@ const MeetingDetails = ({ user }) => {
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="card-section summary-tabs-section">
|
<section className="card-section summary-tabs-section">
|
||||||
<Tabs defaultActiveKey="1">
|
<Tabs
|
||||||
<TabPane tab={<span><FileText size={16} /> 会议总结</span>} key="1">
|
defaultActiveKey="1"
|
||||||
<MeetingSummary
|
items={[
|
||||||
meeting={meeting}
|
{
|
||||||
summaryResult={summaryResult}
|
key: '1',
|
||||||
summaryHistory={summaryHistory}
|
label: <span><FileText size={16} /> 会议总结</span>,
|
||||||
isCreator={isCreator}
|
children: (
|
||||||
onOpenSummaryModal={openSummaryModal}
|
<MeetingSummary
|
||||||
formatDateTime={formatDateTime}
|
meeting={meeting}
|
||||||
/>
|
summaryResult={summaryResult}
|
||||||
</TabPane>
|
summaryHistory={summaryHistory}
|
||||||
<TabPane tab={<span><Brain size={16} /> 会议脑图</span>} key="2">
|
isCreator={isCreator}
|
||||||
<MindMap
|
onOpenSummaryModal={openSummaryModal}
|
||||||
meetingId={meeting_id}
|
formatDateTime={formatDateTime}
|
||||||
meetingTitle={meeting.title}
|
/>
|
||||||
meeting={meeting}
|
)
|
||||||
formatDateTime={formatDateTime}
|
},
|
||||||
/>
|
{
|
||||||
</TabPane>
|
key: '2',
|
||||||
</Tabs>
|
label: <span><Brain size={16} /> 会议脑图</span>,
|
||||||
|
children: (
|
||||||
|
<MindMap
|
||||||
|
meetingId={meeting_id}
|
||||||
|
meetingTitle={meeting.title}
|
||||||
|
meeting={meeting}
|
||||||
|
formatDateTime={formatDateTime}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue