Compare commits

...

2 Commits

Author SHA1 Message Date
mula.liu 1977477fd3 修复部分错误 2025-10-20 11:36:37 +08:00
mula.liu a27102d1fa 修正了一些显示问题 2025-10-16 18:47:53 +08:00
7 changed files with 256 additions and 87 deletions

BIN
.DS_Store vendored

Binary file not shown.

BIN
dist.zip

Binary file not shown.

View File

@ -144,11 +144,11 @@ const MindMap = ({ content, title }) => {
try {
const processedMarkdown = preprocessMarkdownForMindMap(markdown, title);
console.log('=== 思维导图数据调试 ===');
console.log('原始markdown内容:');
console.log(markdown);
console.log('预处理后的markdown:');
console.log(processedMarkdown);
// console.log('=== ===');
// console.log('markdown:');
// console.log(markdown);
// console.log('markdown:');
// console.log(processedMarkdown);
const transformer = new Transformer();
const { root } = transformer.transform(processedMarkdown);
@ -161,10 +161,20 @@ const MindMap = ({ content, title }) => {
markmapRef.current.fit();
// fit
// fit
setTimeout(() => {
if (markmapRef.current) {
markmapRef.current.fit();
// fit1.8
try {
const { state } = markmapRef.current;
if (state) {
const currentScale = state.transform.k;
markmapRef.current.rescale(currentScale * 1.8);
}
} catch (e) {
console.log('缩放调整失败:', e);
}
}
}, 500);

View File

@ -504,6 +504,7 @@ const EditMeeting = ({ user }) => {
onClick={() => {
setShowUploadArea(false);
setAudioFile(null);
setError('');
// Reset file input
const fileInput = document.getElementById('audio-file');
if (fileInput) fileInput.value = '';
@ -550,6 +551,36 @@ const EditMeeting = ({ user }) => {
)}
</div>
)}
{/* Error message for audio upload - shown right after upload area */}
{error && showUploadArea && (
<div className="error-message">{error}</div>
)}
{/* Upload Confirmation Modal - moved here to be right after upload area */}
{showUploadConfirm && (
<div className="delete-modal-overlay" onClick={() => setShowUploadConfirm(false)}>
<div className="delete-modal" onClick={(e) => e.stopPropagation()}>
<h3>确认重新上传</h3>
<p>重传音频文件将清空已有的会话转录是否继续</p>
<div className="modal-actions">
<button
className="btn-cancel"
onClick={() => setShowUploadConfirm(false)}
>
取消
</button>
<button
className="btn-submit"
onClick={handleUploadAudio}
disabled={isUploading}
>
确定重传
</button>
</div>
</div>
</div>
)}
</div>
</div>
@ -604,7 +635,7 @@ const EditMeeting = ({ user }) => {
)}
</div>
{error && (
{error && !showUploadArea && (
<div className="error-message">{error}</div>
)}
@ -624,31 +655,6 @@ const EditMeeting = ({ user }) => {
</form>
</div>
</div>
{/* Upload Confirmation Modal */}
{showUploadConfirm && (
<div className="delete-modal-overlay" onClick={() => setShowUploadConfirm(false)}>
<div className="delete-modal" onClick={(e) => e.stopPropagation()}>
<h3>确认重新上传</h3>
<p>重传音频文件将清空已有的会话转录是否继续</p>
<div className="modal-actions">
<button
className="btn-cancel"
onClick={() => setShowUploadConfirm(false)}
>
取消
</button>
<button
className="btn-submit"
onClick={handleUploadAudio}
disabled={isUploading}
>
确定重传
</button>
</div>
</div>
</div>
)}
</div>
);
};

View File

@ -93,8 +93,6 @@
padding: 0.5rem;
border: none;
border-radius: 6px;
background: #f1f5f9;
color: #64748b;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
@ -102,9 +100,20 @@
justify-content: center;
}
.btn-new-kb {
background: #667eea;
color: white;
}
.btn-new-kb:hover {
background: #e2e8f0;
color: #667eea;
background: #5568d3;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.btn-toggle-sidebar {
background: #f1f5f9;
color: #64748b;
}
.btn-toggle-sidebar:hover {
@ -119,6 +128,27 @@
padding: 0.5rem;
}
/* 日期分组 */
.kb-date-group {
margin-bottom: 1rem;
}
.date-group-header {
padding: 0.5rem 0.75rem;
margin: 0.5rem 0;
font-size: 0.75rem;
font-weight: 600;
color: #64748b;
text-transform: uppercase;
letter-spacing: 0.05em;
border-bottom: 1px solid #e2e8f0;
background: #f8fafc;
border-radius: 6px;
position: sticky;
top: 0;
z-index: 10;
}
.kb-list-item {
padding: 1rem;
margin-bottom: 0.5rem;
@ -627,13 +657,25 @@
width: 18px;
height: 18px;
cursor: pointer;
flex-shrink: 0;
}
.meeting-item label {
cursor: pointer;
.meeting-item-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.meeting-item-title {
font-size: 0.95rem;
color: #475569;
font-weight: 500;
}
.meeting-item-creator {
font-size: 0.8rem;
color: #94a3b8;
}
.selected-meetings-info {

View File

@ -74,10 +74,14 @@ const KnowledgeBasePage = ({ user }) => {
//
apiClient.get(buildApiUrl(API_ENDPOINTS.KNOWLEDGE_BASE.LIST))
.then(response => {
setKbs(response.data.kbs);
//
const sortedKbs = response.data.kbs.sort((a, b) =>
new Date(b.created_at) - new Date(a.created_at)
);
setKbs(sortedKbs);
//
if (response.data.kbs.length > 0 && !selectedKb) {
loadKbDetail(response.data.kbs[0].kb_id);
if (sortedKbs.length > 0 && !selectedKb) {
loadKbDetail(sortedKbs[0].kb_id);
}
setLoading(false);
})
@ -177,6 +181,45 @@ const KnowledgeBasePage = ({ user }) => {
});
};
const formatTime = (dateString) => {
const date = new Date(dateString);
return date.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit'
});
};
const formatShortDate = (dateString) => {
const date = new Date(dateString);
return date.toLocaleDateString('zh-CN', {
month: 'numeric',
day: 'numeric'
});
};
const isToday = (dateString) => {
const date = new Date(dateString);
const today = new Date();
return date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear();
};
const groupKbsByDate = (kbList) => {
const todayKbs = [];
const pastKbs = [];
kbList.forEach(kb => {
if (isToday(kb.created_at)) {
todayKbs.push(kb);
} else {
pastKbs.push(kb);
}
});
return { todayKbs, pastKbs };
};
const handleLogoClick = () => {
navigate('/dashboard');
};
@ -445,51 +488,110 @@ const KnowledgeBasePage = ({ user }) => {
<p>暂无知识库条目</p>
</div>
) : (
kbs.map(kb => (
<div
key={kb.kb_id}
className={`kb-list-item ${selectedKb && selectedKb.kb_id === kb.kb_id ? 'active' : ''}`}
onClick={() => handleKbSelect(kb)}
>
<div className="kb-list-item-header">
<h3>{kb.title}</h3>
{isCreator && (
<div className="kb-item-actions">
<button
className="btn-edit-kb"
onClick={(e) => {
e.stopPropagation();
navigate(`/knowledge-base/edit/${kb.kb_id}`);
}}
title="编辑"
>
<Edit size={14} />
</button>
<button
className="btn-delete-kb"
onClick={(e) => {
e.stopPropagation();
handleDelete(kb);
}}
title="删除"
>
<Trash2 size={14} />
</button>
(() => {
const { todayKbs, pastKbs } = groupKbsByDate(kbs);
return (
<>
{/* 今天的知识库 */}
{todayKbs.length > 0 && (
<div className="kb-date-group">
<div className="date-group-header">今天</div>
{todayKbs.map(kb => (
<div
key={kb.kb_id}
className={`kb-list-item ${selectedKb && selectedKb.kb_id === kb.kb_id ? 'active' : ''}`}
onClick={() => handleKbSelect(kb)}
>
<div className="kb-list-item-header">
<h3>{kb.title}</h3>
{String(kb.creator_id) === String(user.user_id) && (
<div className="kb-item-actions">
<button
className="btn-edit-kb"
onClick={(e) => {
e.stopPropagation();
navigate(`/knowledge-base/edit/${kb.kb_id}`);
}}
title="编辑"
>
<Edit size={14} />
</button>
<button
className="btn-delete-kb"
onClick={(e) => {
e.stopPropagation();
handleDelete(kb);
}}
title="删除"
>
<Trash2 size={14} />
</button>
</div>
)}
</div>
<div className="kb-list-item-meta">
<span className="meta-time">{formatTime(kb.created_at)}</span>
<span className="meta-item">
<Database size={12} />
{kb.source_meeting_count || 0} 个数据源
</span>
</div>
</div>
))}
</div>
)}
</div>
<div className="kb-list-item-meta">
<span className="meta-item">
<Calendar size={12} />
{formatDate(kb.created_at)}
</span>
<span className="meta-item">
<Database size={12} />
{kb.source_meeting_count || 0} 个数据源
</span>
</div>
</div>
))
{/* 之前的知识库 */}
{pastKbs.length > 0 && (
<div className="kb-date-group">
<div className="date-group-header">之前</div>
{pastKbs.map(kb => (
<div
key={kb.kb_id}
className={`kb-list-item ${selectedKb && selectedKb.kb_id === kb.kb_id ? 'active' : ''}`}
onClick={() => handleKbSelect(kb)}
>
<div className="kb-list-item-header">
<h3>{kb.title}</h3>
{String(kb.creator_id) === String(user.user_id) && (
<div className="kb-item-actions">
<button
className="btn-edit-kb"
onClick={(e) => {
e.stopPropagation();
navigate(`/knowledge-base/edit/${kb.kb_id}`);
}}
title="编辑"
>
<Edit size={14} />
</button>
<button
className="btn-delete-kb"
onClick={(e) => {
e.stopPropagation();
handleDelete(kb);
}}
title="删除"
>
<Trash2 size={14} />
</button>
</div>
)}
</div>
<div className="kb-list-item-meta">
<span className="meta-date">{formatShortDate(kb.created_at)}</span>
<span className="meta-item">
<Database size={12} />
{kb.source_meeting_count || 0} 个数据源
</span>
</div>
</div>
))}
</div>
)}
</>
);
})()
)}
</div>
)}
@ -644,9 +746,18 @@ const KnowledgeBasePage = ({ user }) => {
<input
type="checkbox"
checked={selectedMeetings.includes(meeting.meeting_id)}
onChange={() => toggleMeetingSelection(meeting.meeting_id)}
onChange={(e) => {
e.stopPropagation();
toggleMeetingSelection(meeting.meeting_id);
}}
onClick={(e) => e.stopPropagation()}
/>
<label>{meeting.title}</label>
<div className="meeting-item-content">
<div className="meeting-item-title">{meeting.title}</div>
{meeting.creator_username && (
<div className="meeting-item-creator">创建人: {meeting.creator_username}</div>
)}
</div>
</div>
))
)}

View File

@ -6,7 +6,7 @@ import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeRaw from 'rehype-raw';
import rehypeSanitize from 'rehype-sanitize';
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
import { buildApiUrl, API_ENDPOINTS, API_BASE_URL } from '../config/api';
import ContentViewer from '../components/ContentViewer';
import TagDisplay from '../components/TagDisplay';
import { Tabs } from 'antd';