imetting_frontend/src/pages/EditKnowledgeBase.jsx

252 lines
7.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import React, { useState, useEffect, useRef, useCallback } from 'react';
import { Link, useNavigate, useParams } from 'react-router-dom';
import apiClient from '../utils/apiClient';
import { ArrowLeft, FileText, Tag, Save } from 'lucide-react';
import MDEditor, * as commands from '@uiw/react-md-editor';
import '@uiw/react-md-editor/markdown-editor.css';
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
import TagEditor from '../components/TagEditor';
import './EditKnowledgeBase.css';
const EditKnowledgeBase = ({ user }) => {
const navigate = useNavigate();
const { kb_id } = useParams();
const [formData, setFormData] = useState({
title: '',
content: '',
tags: ''
});
const [isLoading, setIsLoading] = useState(true);
const [isSaving, setIsSaving] = useState(false);
const [error, setError] = useState('');
const [kb, setKb] = useState(null);
const handleContentChange = useCallback((value) => {
setFormData(prev => ({ ...prev, content: value || '' }));
}, []);
useEffect(() => {
fetchKbData();
}, [kb_id]);
const fetchKbData = async () => {
try {
const response = await apiClient.get(buildApiUrl(API_ENDPOINTS.KNOWLEDGE_BASE.DETAIL(kb_id)));
const kbData = response.data;
// Check if current user is the creator
if (kbData.creator_id !== user.user_id) {
navigate('/knowledge-base');
return;
}
setKb(kbData);
setFormData({
title: kbData.title,
content: kbData.content || '',
tags: kbData.tags ? kbData.tags.map(t => t.name).join(', ') : ''
});
} catch (err) {
setError('无法加载知识库信息');
console.error('Error fetching knowledge base:', err);
} finally {
setIsLoading(false);
}
};
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!formData.title.trim()) {
setError('请输入知识库标题');
return;
}
setIsSaving(true);
setError('');
try {
const updateData = {
title: formData.title,
content: formData.content,
tags: formData.tags
};
await apiClient.put(buildApiUrl(API_ENDPOINTS.KNOWLEDGE_BASE.UPDATE(kb_id)), updateData);
navigate('/knowledge-base');
} catch (err) {
setError(err.response?.data?.message || '更新知识库失败,请重试');
} finally {
setIsSaving(false);
}
};
// 自定义工具栏命令配置
const customCommands = [
commands.bold,
commands.italic,
commands.strikethrough,
commands.hr,
commands.group([
commands.title1,
commands.title2,
commands.title3,
commands.title4,
commands.title5,
commands.title6,
], {
name: 'title',
groupName: 'title',
buttonProps: { 'aria-label': '插入标题', title: '插入标题' }
}),
commands.divider,
commands.link,
commands.quote,
commands.code,
commands.codeBlock,
commands.image,
commands.divider,
commands.unorderedListCommand,
commands.orderedListCommand,
commands.checkedListCommand,
];
// 右侧额外命令(预览、全屏等)
const customExtraCommands = [
commands.codeEdit,
commands.codeLive,
commands.codePreview,
commands.divider,
commands.fullscreen,
];
if (isLoading) {
return (
<div className="edit-kb-page">
<div className="loading-container">
<div className="loading-spinner"></div>
<p>加载中...</p>
</div>
</div>
);
}
return (
<div className="edit-kb-page">
<div className="edit-header">
<Link to="/knowledge-base">
<span className="back-link">
<ArrowLeft size={20} />
<span>返回知识库</span>
</span>
</Link>
</div>
<div className="edit-content">
<div className="edit-card">
<header className="edit-card-header">
<h1>编辑知识库</h1>
<p>修改知识库标题标签和内容摘要</p>
</header>
<form onSubmit={handleSubmit} className="edit-form">
<div className="form-group">
<label htmlFor="title">
<FileText size={18} />
知识库标题 *
</label>
<input
type="text"
id="title"
name="title"
value={formData.title}
onChange={handleInputChange}
placeholder="请输入知识库标题"
required
/>
</div>
<div className="form-group">
<label htmlFor="tags">
<Tag size={18} />
标签
</label>
<TagEditor
value={formData.tags}
onChange={(value) => setFormData(prev => ({ ...prev, tags: value }))}
placeholder="输入标签,按回车或逗号分隔"
/>
</div>
<div className="form-group">
<div className="content-header">
<label htmlFor="content">
<FileText size={18} />
内容总结
</label>
</div>
<div className="markdown-editor-container">
<MDEditor
key="content-editor"
value={formData.content}
onChange={handleContentChange}
data-color-mode="light"
height={500}
preview="edit"
hideToolbar={false}
toolbarBottom={false}
commands={customCommands}
extraCommands={customExtraCommands}
autoFocus={false}
textareaProps={{
placeholder: '在这里编写知识库内容摘要...',
style: {
fontSize: '14px',
lineHeight: '1.5',
fontFamily: 'inherit'
},
spellCheck: false,
autoComplete: 'off',
autoCapitalize: 'off',
autoCorrect: 'off'
}}
/>
</div>
<div className="markdown-hint">
<small>使用Markdown格式编写知识库内容支持**粗体***斜体*# 标题- 列表等格式</small>
</div>
</div>
{error && (
<div className="error-message">{error}</div>
)}
<div className="form-actions">
<Link to="/knowledge-base">
<span className="btn-cancel">取消</span>
</Link>
<button
type="submit"
className="btn-submit"
disabled={isSaving}
>
<Save size={16} />
{isSaving ? '保存中...' : '保存更改'}
</button>
</div>
</form>
</div>
</div>
</div>
);
};
export default EditKnowledgeBase;