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