mirror of
https://github.com/Funkoala14/KnowledgeBase_OOIN.git
synced 2025-06-08 05:26:07 +08:00
[dev]add mock data
This commit is contained in:
parent
b4a0874a4d
commit
523c474001
@ -21,6 +21,7 @@ export default function HeaderWithNav() {
|
||||
const isActive = (path) => {
|
||||
return location.pathname.startsWith(path);
|
||||
};
|
||||
console.log('user', user);
|
||||
|
||||
// 检查用户是否有管理权限(leader 或 admin)
|
||||
const hasManagePermission = user && (user.role === 'leader' || user.role === 'admin');
|
||||
|
@ -4,6 +4,7 @@ import { fetchMessages, sendMessage } from '../../store/chat/chat.messages.thunk
|
||||
import { resetMessages, resetSendMessageStatus } from '../../store/chat/chat.slice';
|
||||
import { showNotification } from '../../store/notification.slice';
|
||||
import SvgIcon from '../../components/SvgIcon';
|
||||
import { fetchKnowledgeBases } from '../../store/knowledgeBase/knowledgeBase.thunks';
|
||||
|
||||
export default function ChatWindow({ chatId, knowledgeBaseId }) {
|
||||
const dispatch = useDispatch();
|
||||
@ -18,8 +19,9 @@ export default function ChatWindow({ chatId, knowledgeBaseId }) {
|
||||
} = useSelector((state) => state.chat.messages);
|
||||
const { status: sendStatus, error: sendError } = useSelector((state) => state.chat.sendMessage);
|
||||
const knowledgeBase = useSelector((state) =>
|
||||
state.knowledgeBase.list.items.find((kb) => kb.id === knowledgeBaseId)
|
||||
state.knowledgeBase.list.data?.items?.find((kb) => kb.id === knowledgeBaseId)
|
||||
);
|
||||
const isLoadingKnowledgeBases = useSelector((state) => state.knowledgeBase.list.isLoading);
|
||||
|
||||
// 获取聊天消息
|
||||
useEffect(() => {
|
||||
@ -51,6 +53,13 @@ export default function ChatWindow({ chatId, knowledgeBaseId }) {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
}, [messages]);
|
||||
|
||||
// 从 Redux store 获取知识库信息
|
||||
useEffect(() => {
|
||||
if (!knowledgeBase && !isLoadingKnowledgeBases) {
|
||||
dispatch(fetchKnowledgeBases());
|
||||
}
|
||||
}, [dispatch, knowledgeBase, isLoadingKnowledgeBases]);
|
||||
|
||||
const handleSendMessage = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
|
@ -1,87 +1,92 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { showNotification } from '../../store/notification.slice';
|
||||
import { get } from '../../services/api';
|
||||
import { fetchKnowledgeBases } from '../../store/knowledgeBase/knowledgeBase.thunks';
|
||||
import SvgIcon from '../../components/SvgIcon';
|
||||
|
||||
export default function NewChat() {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const [knowledgeBases, setKnowledgeBases] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// 从 Redux store 获取知识库数据
|
||||
const { data, status, error } = useSelector((state) => state.knowledgeBase.list);
|
||||
const knowledgeBases = data?.items || [];
|
||||
const isLoading = status === 'loading';
|
||||
|
||||
// 获取知识库列表
|
||||
useEffect(() => {
|
||||
const fetchKnowledgeBases = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await get('/knowledge-bases/');
|
||||
if (!data?.items?.length && status !== 'loading') {
|
||||
dispatch(fetchKnowledgeBases());
|
||||
}
|
||||
}, [dispatch, data, status]);
|
||||
|
||||
// 过滤出有 can_read 权限的知识库
|
||||
const readableKnowledgeBases = response.data.items.filter(
|
||||
(kb) => kb.permissions && kb.permissions.can_read === true
|
||||
);
|
||||
// 监听错误状态
|
||||
useEffect(() => {
|
||||
if (status === 'failed' && error) {
|
||||
dispatch(
|
||||
showNotification({
|
||||
message: `获取知识库列表失败: ${error.message || error}`,
|
||||
type: 'danger',
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [status, error, dispatch]);
|
||||
|
||||
setKnowledgeBases(readableKnowledgeBases);
|
||||
} catch (error) {
|
||||
console.error('获取知识库列表失败:', error);
|
||||
dispatch(
|
||||
showNotification({
|
||||
message: '获取知识库列表失败,请稍后重试',
|
||||
type: 'danger',
|
||||
})
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchKnowledgeBases();
|
||||
}, [dispatch]);
|
||||
// 过滤出有 can_read 权限的知识库
|
||||
const readableKnowledgeBases = knowledgeBases.filter((kb) => kb.permissions && kb.permissions.can_read === true);
|
||||
|
||||
const handleSelectKnowledgeBase = (knowledgeBaseId) => {
|
||||
// 创建新聊天并导航到聊天页面
|
||||
navigate(`/chat/${knowledgeBaseId}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='new-chat container py-4'>
|
||||
<div className='text-center mb-5'>
|
||||
<h2 className='mb-4'>选择知识库开始聊天</h2>
|
||||
// 渲染加载状态
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className='container-fluid px-4 py-5 text-center'>
|
||||
<div className='spinner-border' role='status'>
|
||||
<span className='visually-hidden'>加载中...</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
{loading ? (
|
||||
<div className='d-flex justify-content-center my-5'>
|
||||
<div className='spinner-border' role='status'>
|
||||
<span className='visually-hidden'>加载中...</span>
|
||||
</div>
|
||||
</div>
|
||||
) : knowledgeBases.length === 0 ? (
|
||||
<div className='text-center my-5'>
|
||||
<p className='text-muted'>没有可用的知识库,请联系管理员获取权限</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className='row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 justify-content-center'>
|
||||
{knowledgeBases.map((kb) => (
|
||||
return (
|
||||
<div className='container-fluid px-4 py-5'>
|
||||
<h4 className='mb-4'>选择知识库开始聊天</h4>
|
||||
<div className='row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4'>
|
||||
{readableKnowledgeBases.length > 0 ? (
|
||||
readableKnowledgeBases.map((kb) => (
|
||||
<div key={kb.id} className='col'>
|
||||
<div
|
||||
className='card h-100 bg-light border-0 cursor-pointer'
|
||||
className='card h-100 shadow-sm border-0 cursor-pointer'
|
||||
onClick={() => handleSelectKnowledgeBase(kb.id)}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
<div className='card-body py-4'>
|
||||
<p className='card-title h5'>{kb.name}</p>
|
||||
<p className='card-text text-muted'>{kb.description}</p>
|
||||
<div className='d-flex justify-content-between align-items-center mt-3'>
|
||||
<small className='text-muted'>文档数: {kb.document_count || 0}</small>
|
||||
<div className='card-body'>
|
||||
<h5 className='card-title'>{kb.name}</h5>
|
||||
<p className='card-text text-muted'>{kb.desc || kb.description || ''}</p>
|
||||
<div className='text-muted small d-flex align-items-center gap-2'>
|
||||
<span className='d-flex align-items-center gap-1'>
|
||||
<SvgIcon className='file' />
|
||||
{kb.document_count} 文档
|
||||
</span>
|
||||
<span className='d-flex align-items-center gap-1'>
|
||||
<SvgIcon className='clock' />
|
||||
{new Date(kb.create_time).toLocaleDateString()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
))
|
||||
) : (
|
||||
<div className='col-12'>
|
||||
<div className='alert alert-warning'>暂无可访问的知识库,请先申请知识库访问权限</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { showNotification } from '../../../store/notification.slice';
|
||||
import { fetchKnowledgeBases } from '../../../store/knowledgeBase/knowledgeBase.thunks';
|
||||
import SvgIcon from '../../../components/SvgIcon';
|
||||
import DatasetTab from './DatasetTab';
|
||||
import SettingsTab from './SettingsTab';
|
||||
@ -13,8 +14,16 @@ export default function KnowledgeBaseDetail() {
|
||||
const [activeTab, setActiveTab] = useState(tab === 'settings' ? 'settings' : 'datasets');
|
||||
|
||||
// Get knowledge base details from Redux store
|
||||
const { items: knowledgeBases } = useSelector((state) => state.knowledgeBase.list);
|
||||
const knowledgeBase = knowledgeBases.find((kb) => kb.id === id);
|
||||
const { data, status } = useSelector((state) => state.knowledgeBase.list);
|
||||
const knowledgeBase = data?.items?.find((kb) => kb.id === id);
|
||||
const isLoading = status === 'loading';
|
||||
|
||||
// Fetch knowledge bases if not available
|
||||
useEffect(() => {
|
||||
if (!data?.items?.length && status !== 'loading') {
|
||||
dispatch(fetchKnowledgeBases());
|
||||
}
|
||||
}, [dispatch, data, status]);
|
||||
|
||||
// Update active tab when URL changes
|
||||
useEffect(() => {
|
||||
@ -25,7 +34,7 @@ export default function KnowledgeBaseDetail() {
|
||||
|
||||
// If knowledge base not found in Redux store, show notification and redirect
|
||||
useEffect(() => {
|
||||
if (!knowledgeBase && knowledgeBases.length > 0) {
|
||||
if (!knowledgeBase && data?.items?.length > 0 && !isLoading) {
|
||||
dispatch(
|
||||
showNotification({
|
||||
message: '未找到知识库,请返回知识库列表',
|
||||
@ -34,7 +43,7 @@ export default function KnowledgeBaseDetail() {
|
||||
);
|
||||
navigate('/knowledge-base');
|
||||
}
|
||||
}, [knowledgeBase, knowledgeBases, dispatch, navigate]);
|
||||
}, [knowledgeBase, data, isLoading, dispatch, navigate]);
|
||||
|
||||
// Handle tab change
|
||||
const handleTabChange = (tab) => {
|
||||
@ -43,7 +52,7 @@ export default function KnowledgeBaseDetail() {
|
||||
};
|
||||
|
||||
// Show loading state if knowledge base not loaded yet
|
||||
if (!knowledgeBase) {
|
||||
if (isLoading || !knowledgeBase) {
|
||||
return (
|
||||
<div className='container-fluid px-4 py-5 text-center'>
|
||||
<div className='spinner-border' role='status'>
|
||||
@ -61,7 +70,7 @@ export default function KnowledgeBaseDetail() {
|
||||
<div className='py-4'>
|
||||
<div className='h4 mb-3 text-center'>{knowledgeBase.name}</div>
|
||||
<p className='text-center text-muted small mb-4'>
|
||||
{knowledgeBase.desc || knowledgeBase.description || ''}
|
||||
{knowledgeBase.desc || ''}
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
@ -5,7 +5,7 @@ import KnowledgeCard from './KnowledgeCard';
|
||||
* 知识库列表组件
|
||||
*/
|
||||
const KnowledgeBaseList = ({ knowledgeBases, isSearching, onCardClick, onRequestAccess, onDelete }) => {
|
||||
if (knowledgeBases.length === 0) {
|
||||
if (!knowledgeBases?.length) {
|
||||
return (
|
||||
<div className='alert alert-warning'>
|
||||
{isSearching ? '没有找到匹配的知识库' : '暂无知识库,请创建新的知识库'}
|
||||
@ -19,15 +19,18 @@ const KnowledgeBaseList = ({ knowledgeBases, isSearching, onCardClick, onRequest
|
||||
<React.Fragment key={item.id}>
|
||||
<KnowledgeCard
|
||||
id={item.id}
|
||||
title={item.name}
|
||||
description={item.description || item.desc || ''}
|
||||
documents={item.document_count || 0}
|
||||
date={new Date(item.create_time || item.created_at).toLocaleDateString()}
|
||||
title={item.highlighted_name || item.name}
|
||||
description={item.desc || ''}
|
||||
documents={item.document_count}
|
||||
date={new Date(item.create_time).toLocaleDateString()}
|
||||
permissions={item.permissions}
|
||||
access={item.permissions?.can_edit ? 'full' : item.permissions?.can_read ? 'read' : 'none'}
|
||||
onClick={() => onCardClick(item.id, item.permissions)}
|
||||
onRequestAccess={onRequestAccess}
|
||||
onDelete={(e) => onDelete(e, item.id)}
|
||||
type={item.type}
|
||||
department={item.department}
|
||||
group={item.group}
|
||||
/>
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
@ -13,6 +13,9 @@ export default function KnowledgeCard({
|
||||
onClick,
|
||||
onRequestAccess,
|
||||
onDelete,
|
||||
type,
|
||||
department,
|
||||
group,
|
||||
}) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
@ -41,7 +44,7 @@ export default function KnowledgeCard({
|
||||
return (
|
||||
<div className='knowledge-card card shadow border-0 p-0 col' onClick={onClick}>
|
||||
<div className='card-body'>
|
||||
<h5 className='card-title'>{title}</h5>
|
||||
<h5 className='card-title' dangerouslySetInnerHTML={{ __html: title }} />
|
||||
{permissions && permissions.can_delete && (
|
||||
<div className='hoverdown position-absolute end-0 top-0'>
|
||||
<button type='button' className='detail-btn btn'>
|
||||
@ -66,6 +69,13 @@ export default function KnowledgeCard({
|
||||
{date}
|
||||
</span>
|
||||
</div>
|
||||
{/* <div className='mt-2 d-flex flex-wrap gap-2'>
|
||||
<span className='badge bg-secondary-subtle text-secondary'>
|
||||
{type === 'private' ? '私有' : '公开'}
|
||||
</span>
|
||||
{department && <span className='badge bg-info-subtle text-info'>{department}</span>}
|
||||
{group && <span className='badge bg-primary-subtle text-primary'>{group}</span>}
|
||||
</div> */}
|
||||
<div className='mt-3 d-flex justify-content-between align-items-end'>
|
||||
{access === 'full' ? (
|
||||
<span className='badge bg-success-subtle text-success d-flex align-items-center gap-1'>
|
||||
|
@ -10,136 +10,6 @@ import { resetApproveRejectStatus } from '../../../store/permissions/permissions
|
||||
import './PendingRequests.css'; // 引入外部CSS文件
|
||||
import SvgIcon from '../../../components/SvgIcon';
|
||||
|
||||
// 模拟数据
|
||||
const mockPendingRequests = [
|
||||
{
|
||||
id: 1,
|
||||
applicant: {
|
||||
name: '王五',
|
||||
department: '达人组',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '达人直播数据报告',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: true,
|
||||
can_delete: false,
|
||||
},
|
||||
reason: '需要查看和编辑直播数据报告',
|
||||
created_at: '2024-01-07T10:30:00Z',
|
||||
expires_at: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
applicant: {
|
||||
name: '赵六',
|
||||
department: '直播组',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '人力资源政策文件',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_delete: false,
|
||||
},
|
||||
reason: '需要了解最新的人力资源政策',
|
||||
created_at: '2024-01-06T14:20:00Z',
|
||||
expires_at: '2025-01-06T14:20:00Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
applicant: {
|
||||
name: '钱七',
|
||||
department: '市场部',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '市场分析报告',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_delete: false,
|
||||
},
|
||||
reason: '需要了解市场趋势',
|
||||
created_at: '2024-01-05T09:15:00Z',
|
||||
expires_at: '2024-07-05T09:15:00Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
applicant: {
|
||||
name: '孙八',
|
||||
department: '技术部',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '技术架构文档',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: true,
|
||||
can_delete: true,
|
||||
},
|
||||
reason: '需要进行技术架构更新',
|
||||
created_at: '2024-01-04T16:45:00Z',
|
||||
expires_at: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
applicant: {
|
||||
name: '周九',
|
||||
department: '产品部',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '产品规划文档',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: true,
|
||||
can_delete: false,
|
||||
},
|
||||
reason: '需要参与产品规划讨论',
|
||||
created_at: '2024-01-03T11:30:00Z',
|
||||
expires_at: '2024-12-31T23:59:59Z',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
applicant: {
|
||||
name: '吴十',
|
||||
department: '设计部',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '设计规范文档',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_delete: false,
|
||||
},
|
||||
reason: '需要参考设计规范',
|
||||
created_at: '2024-01-02T14:20:00Z',
|
||||
expires_at: '2024-06-30T23:59:59Z',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
applicant: {
|
||||
name: '郑十一',
|
||||
department: '财务部',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '财务报表',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_delete: false,
|
||||
},
|
||||
reason: '需要查看财务数据',
|
||||
created_at: '2024-01-01T09:00:00Z',
|
||||
expires_at: null,
|
||||
},
|
||||
];
|
||||
|
||||
// 每页显示的申请数量
|
||||
const PAGE_SIZE = 5;
|
||||
|
||||
@ -173,31 +43,16 @@ export default function PendingRequests() {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
setFetchStatus('loading');
|
||||
// 尝试从API获取数据
|
||||
const result = await dispatch(fetchPermissionsThunk());
|
||||
|
||||
// 检查API返回的数据
|
||||
if (result && result.payload && result.payload.length > 0) {
|
||||
// 使用API返回的数据
|
||||
if (result.payload) {
|
||||
setPendingRequests(result.payload);
|
||||
setTotalPages(Math.ceil(result.payload.length / PAGE_SIZE));
|
||||
console.log('使用API返回的待处理申请数据');
|
||||
} else {
|
||||
// API返回的数据为空,使用模拟数据
|
||||
console.log('API返回的待处理申请数据为空,使用模拟数据');
|
||||
setPendingRequests(mockPendingRequests);
|
||||
setTotalPages(Math.ceil(mockPendingRequests.length / PAGE_SIZE));
|
||||
}
|
||||
setFetchStatus('succeeded');
|
||||
} catch (error) {
|
||||
console.error('获取待处理申请失败:', error);
|
||||
setFetchError('获取待处理申请失败');
|
||||
console.error('获取待处理申请列表失败:', error);
|
||||
setFetchError(error.message || '获取待处理申请列表失败');
|
||||
setFetchStatus('failed');
|
||||
|
||||
// API请求失败,使用模拟数据作为后备
|
||||
console.log('API请求失败,使用模拟数据作为后备');
|
||||
setPendingRequests(mockPendingRequests);
|
||||
setTotalPages(Math.ceil(mockPendingRequests.length / PAGE_SIZE));
|
||||
}
|
||||
};
|
||||
|
||||
@ -318,7 +173,7 @@ export default function PendingRequests() {
|
||||
const getCurrentPageData = () => {
|
||||
const startIndex = (currentPage - 1) * PAGE_SIZE;
|
||||
const endIndex = startIndex + PAGE_SIZE;
|
||||
return pendingRequests.slice(startIndex, endIndex);
|
||||
return Array.isArray(pendingRequests) ? pendingRequests.slice(startIndex, endIndex) : [];
|
||||
};
|
||||
|
||||
// 处理页码变化
|
||||
@ -401,14 +256,13 @@ export default function PendingRequests() {
|
||||
<div key={request.id} className='pending-request-item' onClick={() => handleRowClick(request)}>
|
||||
<div className='request-header'>
|
||||
<div className='user-info'>
|
||||
<h6 className='mb-0'>{request.applicant.name}</h6>
|
||||
<p className='department'>{request.applicant.department}</p>
|
||||
<h6 className='mb-0'>{request.applicant}</h6>
|
||||
</div>
|
||||
<div className='request-date'>{new Date(request.created_at).toLocaleDateString()}</div>
|
||||
</div>
|
||||
|
||||
<div className='request-content'>
|
||||
<p className='mb-2'>申请访问:{request.knowledge_base.name}</p>
|
||||
<p className='mb-2'>申请访问:{request.knowledge_base}</p>
|
||||
|
||||
{request.permissions.can_edit ? (
|
||||
<span
|
||||
@ -477,15 +331,10 @@ export default function PendingRequests() {
|
||||
<h6 className='text-muted mb-2'>申请人信息</h6>
|
||||
<div className='d-flex align-items-center mb-3'>
|
||||
<div className='avatar-placeholder me-3 bg-dark'>
|
||||
{(selectedRequest.applicant.name || selectedRequest.applicant).charAt(0)}
|
||||
{selectedRequest.applicant.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<h5 className='mb-1'>
|
||||
{selectedRequest.applicant.name || selectedRequest.applicant}
|
||||
</h5>
|
||||
<p className='text-muted mb-0'>
|
||||
{selectedRequest.applicant.department || '无归属部门'}
|
||||
</p>
|
||||
<h5 className='mb-1'>{selectedRequest.applicant}</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -493,8 +342,7 @@ export default function PendingRequests() {
|
||||
<div className='mb-4'>
|
||||
<h6 className='text-muted mb-2'>知识库信息</h6>
|
||||
<p className='mb-1'>
|
||||
<strong>名称:</strong>{' '}
|
||||
{selectedRequest.knowledge_base.name || selectedRequest.knowledge_base}
|
||||
<strong>ID:</strong> {selectedRequest.knowledge_base}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@ -295,235 +295,230 @@ const mockDeleteChat = (id) => {
|
||||
// 模拟聊天消息数据
|
||||
const chatMessages = {};
|
||||
|
||||
// 模拟待处理权限申请
|
||||
// 权限申请列表的 mock 数据
|
||||
const mockPendingRequests = [
|
||||
{
|
||||
id: 1,
|
||||
applicant: {
|
||||
name: '王五',
|
||||
department: '达人组',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '达人直播数据报告',
|
||||
},
|
||||
knowledge_base: 'f13c4bdb-eb03-4ce2-b83c-30917351fb72',
|
||||
applicant: 'f2799611-7a3d-436d-b3fa-3789bdd877e2',
|
||||
permissions: {
|
||||
can_edit: false,
|
||||
can_read: true,
|
||||
can_edit: true,
|
||||
can_delete: false,
|
||||
},
|
||||
reason: '需要查看和编辑直播数据报告',
|
||||
created_at: '2024-01-07T10:30:00Z',
|
||||
expires_at: null,
|
||||
status: 'pending',
|
||||
reason: '需要访问知识库进行学习',
|
||||
response_message: null,
|
||||
expires_at: '2025-03-19T00:17:43.781000Z',
|
||||
created_at: '2025-03-12T00:17:44.044351Z',
|
||||
updated_at: '2025-03-12T00:17:44.044369Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
applicant: {
|
||||
name: '赵六',
|
||||
department: '直播组',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '人力资源政策文件',
|
||||
},
|
||||
knowledge_base: 'f13c4bdb-eb03-4ce2-b83c-30917351fb73',
|
||||
applicant: 'f2799611-7a3d-436d-b3fa-3789bdd877e3',
|
||||
permissions: {
|
||||
can_edit: true,
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_delete: false,
|
||||
},
|
||||
reason: '需要了解最新的人力资源政策',
|
||||
created_at: '2024-01-06T14:20:00Z',
|
||||
expires_at: '2025-01-06T14:20:00Z',
|
||||
status: 'pending',
|
||||
reason: '需要编辑和更新文档',
|
||||
response_message: null,
|
||||
expires_at: '2025-03-20T00:17:43.781000Z',
|
||||
created_at: '2025-03-12T00:17:44.044351Z',
|
||||
updated_at: '2025-03-12T00:17:44.044369Z',
|
||||
},
|
||||
];
|
||||
|
||||
// 用户权限列表的 mock 数据
|
||||
const mockUserPermissions = [
|
||||
{
|
||||
id: 3,
|
||||
applicant: {
|
||||
name: '钱七',
|
||||
department: '市场部',
|
||||
id: 'perm-001',
|
||||
user: {
|
||||
id: 'user-001',
|
||||
username: 'johndoe',
|
||||
name: 'John Doe',
|
||||
email: 'john@example.com',
|
||||
department: '研发部',
|
||||
group: '前端开发组',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '市场分析报告',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_delete: false,
|
||||
},
|
||||
reason: '需要了解市场趋势',
|
||||
created_at: '2024-01-05T09:15:00Z',
|
||||
expires_at: '2024-07-05T09:15:00Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
applicant: {
|
||||
name: '孙八',
|
||||
department: '技术部',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '技术架构文档',
|
||||
id: 'kb-001',
|
||||
name: 'Frontend Development Guide',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: true,
|
||||
can_delete: true,
|
||||
can_manage: true,
|
||||
},
|
||||
granted_at: '2024-01-15T10:00:00Z',
|
||||
granted_by: {
|
||||
id: 'user-admin',
|
||||
username: 'admin',
|
||||
name: 'System Admin',
|
||||
},
|
||||
reason: '需要进行技术架构更新',
|
||||
created_at: '2024-01-04T16:45:00Z',
|
||||
expires_at: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
applicant: {
|
||||
name: '周九',
|
||||
department: '产品部',
|
||||
id: 'perm-002',
|
||||
user: {
|
||||
id: 'user-002',
|
||||
username: 'janedoe',
|
||||
name: 'Jane Doe',
|
||||
email: 'jane@example.com',
|
||||
department: '研发部',
|
||||
group: '前端开发组',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '产品规划文档',
|
||||
id: 'kb-001',
|
||||
name: 'Frontend Development Guide',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: true,
|
||||
can_delete: false,
|
||||
can_manage: false,
|
||||
},
|
||||
granted_at: '2024-01-20T14:30:00Z',
|
||||
granted_by: {
|
||||
id: 'user-001',
|
||||
username: 'johndoe',
|
||||
name: 'John Doe',
|
||||
},
|
||||
reason: '需要参与产品规划讨论',
|
||||
created_at: '2024-01-03T11:30:00Z',
|
||||
expires_at: '2024-12-31T23:59:59Z',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
applicant: {
|
||||
name: '吴十',
|
||||
department: '设计部',
|
||||
id: 'perm-003',
|
||||
user: {
|
||||
id: 'user-003',
|
||||
username: 'alexsmith',
|
||||
name: 'Alex Smith',
|
||||
email: 'alex@example.com',
|
||||
department: '研发部',
|
||||
group: '后端开发组',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '设计规范文档',
|
||||
id: 'kb-001',
|
||||
name: 'Frontend Development Guide',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_delete: false,
|
||||
can_manage: false,
|
||||
},
|
||||
reason: '需要参考设计规范',
|
||||
created_at: '2024-01-02T14:20:00Z',
|
||||
expires_at: '2024-06-30T23:59:59Z',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
applicant: {
|
||||
name: '郑十一',
|
||||
department: '财务部',
|
||||
granted_at: '2024-02-01T09:15:00Z',
|
||||
granted_by: {
|
||||
id: 'user-001',
|
||||
username: 'johndoe',
|
||||
name: 'John Doe',
|
||||
},
|
||||
knowledge_base: {
|
||||
name: '财务报表',
|
||||
},
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_delete: false,
|
||||
},
|
||||
reason: '需要查看财务数据',
|
||||
created_at: '2024-01-01T09:00:00Z',
|
||||
expires_at: null,
|
||||
},
|
||||
];
|
||||
|
||||
// 模拟用户权限详情
|
||||
const mockUserPermissions = {
|
||||
'user-001': [
|
||||
{
|
||||
knowledge_base: {
|
||||
id: 'kb-001',
|
||||
name: '达人直播数据报告',
|
||||
department: '达人组',
|
||||
// Mock API handlers for permissions
|
||||
const mockPermissionApi = {
|
||||
// 获取待处理的权限申请列表
|
||||
getPendingRequests: () => {
|
||||
return {
|
||||
code: 200,
|
||||
message: 'success',
|
||||
data: {
|
||||
items: mockPendingRequests,
|
||||
total: mockPendingRequests.length,
|
||||
},
|
||||
permission: {
|
||||
can_read: true,
|
||||
can_edit: true,
|
||||
can_admin: false,
|
||||
};
|
||||
},
|
||||
|
||||
// 获取用户权限列表
|
||||
getUserPermissions: (knowledgeBaseId) => {
|
||||
const permissions = mockUserPermissions.filter((perm) => perm.knowledge_base.id === knowledgeBaseId);
|
||||
return {
|
||||
code: 200,
|
||||
message: 'success',
|
||||
data: {
|
||||
items: permissions,
|
||||
total: permissions.length,
|
||||
},
|
||||
last_access_time: '2024-03-10T14:30:00Z',
|
||||
},
|
||||
{
|
||||
knowledge_base: {
|
||||
id: 'kb-002',
|
||||
name: '人力资源政策文件',
|
||||
department: '人力资源组',
|
||||
},
|
||||
permission: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_admin: false,
|
||||
},
|
||||
last_access_time: '2024-03-08T09:15:00Z',
|
||||
},
|
||||
{
|
||||
knowledge_base: {
|
||||
id: 'kb-003',
|
||||
name: '市场分析报告',
|
||||
department: '市场部',
|
||||
},
|
||||
permission: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_admin: false,
|
||||
},
|
||||
last_access_time: null,
|
||||
},
|
||||
],
|
||||
'user-002': [
|
||||
{
|
||||
knowledge_base: {
|
||||
id: 'kb-001',
|
||||
name: '达人直播数据报告',
|
||||
department: '达人组',
|
||||
},
|
||||
permission: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_admin: false,
|
||||
},
|
||||
last_access_time: '2024-03-05T10:20:00Z',
|
||||
},
|
||||
{
|
||||
knowledge_base: {
|
||||
id: 'kb-004',
|
||||
name: '产品规划文档',
|
||||
department: '产品部',
|
||||
},
|
||||
permission: {
|
||||
can_read: true,
|
||||
can_edit: true,
|
||||
can_admin: true,
|
||||
},
|
||||
last_access_time: '2024-03-15T11:20:00Z',
|
||||
},
|
||||
],
|
||||
'user-003': [
|
||||
{
|
||||
knowledge_base: {
|
||||
id: 'kb-003',
|
||||
name: '市场分析报告',
|
||||
department: '市场部',
|
||||
},
|
||||
permission: {
|
||||
can_read: true,
|
||||
can_edit: true,
|
||||
can_admin: false,
|
||||
},
|
||||
last_access_time: '2024-03-12T15:40:00Z',
|
||||
},
|
||||
{
|
||||
knowledge_base: {
|
||||
id: 'kb-005',
|
||||
name: 'UI/UX设计指南',
|
||||
department: '设计部',
|
||||
},
|
||||
permission: {
|
||||
can_read: true,
|
||||
can_edit: false,
|
||||
can_admin: false,
|
||||
},
|
||||
last_access_time: '2024-03-01T09:10:00Z',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
// 处理权限申请
|
||||
handlePermissionRequest: (requestId, action) => {
|
||||
const request = mockPendingRequests.find((req) => req.id === requestId);
|
||||
if (!request) {
|
||||
return {
|
||||
code: 404,
|
||||
message: 'Permission request not found',
|
||||
};
|
||||
}
|
||||
|
||||
request.status = action === 'approve' ? 'approved' : 'rejected';
|
||||
|
||||
if (action === 'approve') {
|
||||
// 如果批准,添加新的权限记录
|
||||
const newPermission = {
|
||||
id: `perm-${Date.now()}`,
|
||||
user: request.user,
|
||||
knowledge_base: request.knowledge_base,
|
||||
permissions: {
|
||||
can_read: true,
|
||||
can_edit: request.request_type === 'edit',
|
||||
can_delete: false,
|
||||
can_manage: false,
|
||||
},
|
||||
granted_at: new Date().toISOString(),
|
||||
granted_by: mockCurrentUser,
|
||||
};
|
||||
mockUserPermissions.push(newPermission);
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: 'success',
|
||||
data: request,
|
||||
};
|
||||
},
|
||||
|
||||
// 更新用户权限
|
||||
updateUserPermission: (permissionId, permissions) => {
|
||||
const permission = mockUserPermissions.find((perm) => perm.id === permissionId);
|
||||
if (!permission) {
|
||||
return {
|
||||
code: 404,
|
||||
message: 'Permission not found',
|
||||
};
|
||||
}
|
||||
|
||||
permission.permissions = {
|
||||
...permission.permissions,
|
||||
...permissions,
|
||||
};
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: 'success',
|
||||
data: permission,
|
||||
};
|
||||
},
|
||||
|
||||
// 删除用户权限
|
||||
deleteUserPermission: (permissionId) => {
|
||||
const index = mockUserPermissions.findIndex((perm) => perm.id === permissionId);
|
||||
if (index === -1) {
|
||||
return {
|
||||
code: 404,
|
||||
message: 'Permission not found',
|
||||
};
|
||||
}
|
||||
|
||||
mockUserPermissions.splice(index, 1);
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: 'success',
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
// Mock API functions
|
||||
@ -536,13 +531,7 @@ export const mockGet = async (url, config = {}) => {
|
||||
// Get current user
|
||||
if (url === '/users/me/') {
|
||||
return {
|
||||
data: {
|
||||
code: 200,
|
||||
message: 'success',
|
||||
data: {
|
||||
user: mockUsers[0], // 默认返回第一个用户
|
||||
},
|
||||
},
|
||||
user: mockUsers[0], // 默认返回第一个用户
|
||||
};
|
||||
}
|
||||
|
||||
@ -670,7 +659,8 @@ export const mockGet = async (url, config = {}) => {
|
||||
code: 200,
|
||||
message: 'success',
|
||||
data: {
|
||||
pending_requests: mockPendingRequests,
|
||||
items: mockPendingRequests,
|
||||
total: mockPendingRequests.length,
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -721,22 +711,18 @@ export const mockPost = async (url, data) => {
|
||||
const token = `mock-jwt-token-${uuidv4()}`;
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: '登录成功',
|
||||
data: {
|
||||
code: 200,
|
||||
message: '登录成功',
|
||||
data: {
|
||||
token,
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
department: user.department,
|
||||
group: user.group,
|
||||
role: user.role,
|
||||
avatar: user.avatar,
|
||||
},
|
||||
},
|
||||
token,
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
department: user.department,
|
||||
group: user.group,
|
||||
role: user.role,
|
||||
avatar: user.avatar,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -1003,3 +989,18 @@ export const mockDelete = async (url) => {
|
||||
export const resetMockData = () => {
|
||||
knowledgeBases = [...mockKnowledgeBases];
|
||||
};
|
||||
|
||||
// 添加权限相关的 API 处理
|
||||
export const mockApi = {
|
||||
// ... existing api handlers ...
|
||||
|
||||
// 权限管理相关的 API
|
||||
'GET /api/permissions/pending': () => mockPermissionApi.getPendingRequests(),
|
||||
'GET /api/permissions/users/:knowledgeBaseId': (params) =>
|
||||
mockPermissionApi.getUserPermissions(params.knowledgeBaseId),
|
||||
'POST /api/permissions/handle/:requestId': (params, body) =>
|
||||
mockPermissionApi.handlePermissionRequest(params.requestId, body.action),
|
||||
'PUT /api/permissions/:permissionId': (params, body) =>
|
||||
mockPermissionApi.updateUserPermission(params.permissionId, body.permissions),
|
||||
'DELETE /api/permissions/:permissionId': (params) => mockPermissionApi.deleteUserPermission(params.permissionId),
|
||||
};
|
||||
|
@ -11,6 +11,8 @@ export const loginThunk = createAsyncThunk(
|
||||
async ({ username, password }, { rejectWithValue, dispatch }) => {
|
||||
try {
|
||||
const { message, data } = await post('/auth/login/', { username, password });
|
||||
console.log('data', data);
|
||||
|
||||
if (!data) {
|
||||
throw new Error(message || 'Something went wrong');
|
||||
}
|
||||
|
@ -11,20 +11,24 @@ import {
|
||||
const initialState = {
|
||||
// List state
|
||||
list: {
|
||||
items: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
data: {
|
||||
items: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
},
|
||||
status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
|
||||
error: null,
|
||||
},
|
||||
// Search state
|
||||
search: {
|
||||
items: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
keyword: '',
|
||||
data: {
|
||||
items: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
keyword: '',
|
||||
},
|
||||
status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
|
||||
error: null,
|
||||
},
|
||||
@ -62,11 +66,13 @@ const knowledgeBaseSlice = createSlice({
|
||||
},
|
||||
resetSearchState: (state) => {
|
||||
state.search = {
|
||||
items: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
keyword: '',
|
||||
data: {
|
||||
items: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
keyword: '',
|
||||
},
|
||||
status: 'idle',
|
||||
error: null,
|
||||
};
|
||||
@ -93,15 +99,12 @@ const knowledgeBaseSlice = createSlice({
|
||||
state.search.status = 'loading';
|
||||
// Store the keyword for reference
|
||||
if (action.meta.arg.keyword) {
|
||||
state.search.keyword = action.meta.arg.keyword;
|
||||
state.search.data.keyword = action.meta.arg.keyword;
|
||||
}
|
||||
})
|
||||
.addCase(searchKnowledgeBases.fulfilled, (state, action) => {
|
||||
state.search.status = 'succeeded';
|
||||
state.search.items = action.payload.items;
|
||||
state.search.total = action.payload.total;
|
||||
state.search.page = action.payload.page;
|
||||
state.search.page_size = action.payload.page_size;
|
||||
state.search.data = action.payload;
|
||||
state.search.error = null;
|
||||
})
|
||||
.addCase(searchKnowledgeBases.rejected, (state, action) => {
|
||||
@ -146,14 +149,14 @@ const knowledgeBaseSlice = createSlice({
|
||||
.addCase(updateKnowledgeBase.fulfilled, (state, action) => {
|
||||
state.operations.status = 'succeeded';
|
||||
// Update in list if present
|
||||
const index = state.list.items.findIndex((item) => item.id === action.payload.id);
|
||||
const index = state.list.data.items.findIndex((item) => item.id === action.payload.id);
|
||||
if (index !== -1) {
|
||||
state.list.items[index] = action.payload;
|
||||
state.list.data.items[index] = action.payload;
|
||||
}
|
||||
// Update in search results if present
|
||||
const searchIndex = state.search.items.findIndex((item) => item.id === action.payload.id);
|
||||
const searchIndex = state.search.data.items.findIndex((item) => item.id === action.payload.id);
|
||||
if (searchIndex !== -1) {
|
||||
state.search.items[searchIndex] = action.payload;
|
||||
state.search.data.items[searchIndex] = action.payload;
|
||||
}
|
||||
// Update current if it's the same knowledge base
|
||||
if (state.current.data && state.current.data.id === action.payload.id) {
|
||||
@ -174,9 +177,9 @@ const knowledgeBaseSlice = createSlice({
|
||||
.addCase(deleteKnowledgeBase.fulfilled, (state, action) => {
|
||||
state.operations.status = 'succeeded';
|
||||
// Remove from list if present
|
||||
state.list.items = state.list.items.filter((item) => item.id !== action.payload);
|
||||
state.list.data.items = state.list.data.items.filter((item) => item.id !== action.payload);
|
||||
// Remove from search results if present
|
||||
state.search.items = state.search.items.filter((item) => item.id !== action.payload);
|
||||
state.search.data.items = state.search.data.items.filter((item) => item.id !== action.payload);
|
||||
// Reset current if it's the same knowledge base
|
||||
if (state.current.data && state.current.data.id === action.payload) {
|
||||
state.current.data = null;
|
||||
|
@ -35,10 +35,13 @@ export const searchKnowledgeBases = createAsyncThunk(
|
||||
async ({ keyword, page = 1, page_size = 10 }, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await get('/knowledge-bases/search/', {
|
||||
keyword,
|
||||
page,
|
||||
page_size,
|
||||
params: { keyword, page, page_size },
|
||||
});
|
||||
|
||||
// 处理新的返回格式
|
||||
if (response.data && response.data.code === 200) {
|
||||
return response.data.data;
|
||||
}
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
return rejectWithValue(error.response?.data || 'Failed to search knowledge bases');
|
||||
@ -75,6 +78,10 @@ export const getKnowledgeBaseById = createAsyncThunk(
|
||||
async (id, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await get(`/knowledge-bases/${id}/`);
|
||||
// 处理新的返回格式
|
||||
if (response.data && response.data.code === 200) {
|
||||
return response.data.data.knowledge_base;
|
||||
}
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
return rejectWithValue(error.response?.data || 'Failed to get knowledge base details');
|
||||
|
@ -6,8 +6,11 @@ export const fetchPermissionsThunk = createAsyncThunk(
|
||||
'permissions/fetchPermissions',
|
||||
async (_, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await get('/permissions/');
|
||||
return response || [];
|
||||
const response = await get('/permissions/pending/');
|
||||
if (response?.data?.code === 200) {
|
||||
return response.data.data.items || [];
|
||||
}
|
||||
return rejectWithValue('获取权限申请列表失败');
|
||||
} catch (error) {
|
||||
console.error('获取权限申请列表失败:', error);
|
||||
return rejectWithValue('获取权限申请列表失败');
|
||||
|
Loading…
Reference in New Issue
Block a user