增加了权限系统
parent
39eb9e8812
commit
3bb66c8e81
|
|
@ -0,0 +1,79 @@
|
|||
/* 面包屑导航容器 */
|
||||
.breadcrumb-container {
|
||||
background: white;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.breadcrumb-content {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 0.875rem 2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* 面包屑项 */
|
||||
.breadcrumb-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
/* 首页链接 */
|
||||
.breadcrumb-home {
|
||||
color: #667eea;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0.375rem 0.75rem;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.breadcrumb-home:hover {
|
||||
background: #eff6ff;
|
||||
color: #5568d3;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* 分隔符 */
|
||||
.breadcrumb-separator {
|
||||
color: #cbd5e1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 当前页 */
|
||||
.breadcrumb-current {
|
||||
color: #1e293b;
|
||||
padding: 0.375rem 0.75rem;
|
||||
background: #f8fafc;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.breadcrumb-current svg {
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
/* 响应式 */
|
||||
@media (max-width: 768px) {
|
||||
.breadcrumb-content {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.breadcrumb-item {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.breadcrumb-item span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.breadcrumb-separator {
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
import React from 'react';
|
||||
import { Home, ChevronRight } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import './Breadcrumb.css';
|
||||
|
||||
/**
|
||||
* 面包屑导航组件
|
||||
* @param {string} currentPage - 当前页面名称
|
||||
* @param {string} icon - 当前页面图标(可选,lucide-react组件)
|
||||
*/
|
||||
const Breadcrumb = ({ currentPage, icon: Icon }) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleHomeClick = () => {
|
||||
navigate('/dashboard');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="breadcrumb-container">
|
||||
<div className="breadcrumb-content">
|
||||
<button className="breadcrumb-item breadcrumb-home" onClick={handleHomeClick}>
|
||||
<Home size={16} />
|
||||
<span>首页</span>
|
||||
</button>
|
||||
<ChevronRight size={16} className="breadcrumb-separator" />
|
||||
<div className="breadcrumb-item breadcrumb-current">
|
||||
{Icon && <Icon size={16} />}
|
||||
<span>{currentPage}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Breadcrumb;
|
||||
|
|
@ -221,7 +221,7 @@ const AdminDashboard = ({ user, onLogout }) => {
|
|||
<div className="header-content">
|
||||
<div className="logo">
|
||||
<Waves size={32} className="logo-icon" />
|
||||
<span>iMeeting 管理后台</span>
|
||||
<span>管理面板</span>
|
||||
</div>
|
||||
<div className="user-actions">
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -1,55 +1,23 @@
|
|||
/* AdminManagement.css */
|
||||
.admin-management-page {
|
||||
min-height: 100vh;
|
||||
height: 100vh;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.admin-header {
|
||||
background: white;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.admin-header .header-content {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem 2rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.admin-header .logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.admin-header .logo-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.admin-header h1 {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
color: #1e293b;
|
||||
font-weight: 600;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
.admin-content {
|
||||
flex: 1;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
padding: 2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.admin-wrapper {
|
||||
|
|
|
|||
|
|
@ -1,33 +1,20 @@
|
|||
import React from 'react';
|
||||
import { MessageSquare, Settings, Users, Smartphone, Shield } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Settings, Users, Smartphone, Shield } from 'lucide-react';
|
||||
import { Tabs } from 'antd';
|
||||
import UserManagement from './admin/UserManagement';
|
||||
import SystemConfiguration from './admin/SystemConfiguration';
|
||||
import ClientManagement from './ClientManagement';
|
||||
import PermissionManagement from './admin/PermissionManagement';
|
||||
import Breadcrumb from '../components/Breadcrumb';
|
||||
import './AdminManagement.css';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
const AdminManagement = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleLogoClick = () => {
|
||||
navigate('/dashboard');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="admin-management-page">
|
||||
<header className="admin-header">
|
||||
<div className="header-content">
|
||||
<div className="logo" onClick={handleLogoClick} style={{ cursor: 'pointer' }}>
|
||||
<MessageSquare className="logo-icon" />
|
||||
<span className="logo-text">iMeeting</span>
|
||||
</div>
|
||||
<h1>平台管理</h1>
|
||||
</div>
|
||||
</header>
|
||||
<Breadcrumb currentPage="平台管理" icon={Shield} />
|
||||
|
||||
<div className="admin-content">
|
||||
<div className="admin-wrapper">
|
||||
<Tabs defaultActiveKey="userManagement" className="admin-tabs">
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
}
|
||||
|
||||
.header-content {
|
||||
max-width: 1200px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem 2rem;
|
||||
display: flex;
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
|
||||
/* Dashboard Content */
|
||||
.dashboard-content {
|
||||
max-width: 1200px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
/* 整体页面布局 */
|
||||
.kb-management-page {
|
||||
min-height: 100vh;
|
||||
height: 100vh;
|
||||
background: #f8fafc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 加载和错误状态 */
|
||||
|
|
@ -31,60 +32,27 @@
|
|||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 顶部Header */
|
||||
.kb-header {
|
||||
background: white;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.kb-header .header-content {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem 2rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.kb-header .logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.kb-header .logo-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.kb-header h1 {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
color: #1e293b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 主布局区 - 左右分栏 */
|
||||
.kb-layout {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
gap: 1.5rem;
|
||||
overflow: hidden;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* 左侧边栏 */
|
||||
.kb-sidebar {
|
||||
width: 320px;
|
||||
background: white;
|
||||
border-right: 1px solid #e2e8f0;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
|
|
@ -93,18 +61,21 @@
|
|||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 1.5rem 1rem;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
padding: 1rem 1.25rem;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
background: #f8f9fa;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.sidebar-header h2 {
|
||||
margin: 0;
|
||||
font-size: 1.125rem;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar-actions {
|
||||
|
|
@ -137,8 +108,10 @@
|
|||
}
|
||||
|
||||
.btn-toggle-sidebar {
|
||||
background: #f1f5f9;
|
||||
background: none;
|
||||
color: #64748b;
|
||||
padding: 0.25rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.btn-toggle-sidebar:hover {
|
||||
|
|
@ -161,13 +134,13 @@
|
|||
.date-group-header {
|
||||
padding: 0.5rem 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
color: #475569;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
background: #f8fafc;
|
||||
background: #f1f5f9;
|
||||
border-radius: 6px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
|
@ -175,22 +148,25 @@
|
|||
}
|
||||
|
||||
.kb-list-item {
|
||||
padding: 1rem;
|
||||
padding: 0.75rem 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border: 1px solid transparent;
|
||||
border: 1px solid #e2e8f0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.kb-list-item:hover {
|
||||
background: #f8fafc;
|
||||
border-color: #e2e8f0;
|
||||
border-color: #cbd5e1;
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.kb-list-item.active {
|
||||
background: #eff6ff;
|
||||
border-color: #667eea;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.15);
|
||||
}
|
||||
|
||||
.kb-list-item-header {
|
||||
|
|
@ -234,19 +210,6 @@
|
|||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.btn-delete-kb {
|
||||
padding: 0.25rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: #94a3b8;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-delete-kb:hover {
|
||||
background: #fee2e2;
|
||||
color: #ef4444;
|
||||
|
|
@ -269,9 +232,12 @@
|
|||
/* 右侧详情区 */
|
||||
.kb-detail-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 2rem;
|
||||
background: #f8fafc;
|
||||
background: white;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.kb-detail-header {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { MessageSquare, ChevronLeft, ChevronRight, Plus, Calendar, Database, Trash2, Edit, FileText, Image, X } from 'lucide-react';
|
||||
import { Database, ChevronLeft, ChevronRight, Plus, Calendar, Trash2, Edit, FileText, Image, X } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import apiClient from '../utils/apiClient';
|
||||
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
|
||||
|
|
@ -10,6 +10,7 @@ import ConfirmDialog from '../components/ConfirmDialog';
|
|||
import FormModal from '../components/FormModal';
|
||||
import StepIndicator from '../components/StepIndicator';
|
||||
import SimpleSearchInput from '../components/SimpleSearchInput';
|
||||
import Breadcrumb from '../components/Breadcrumb';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import rehypeRaw from 'rehype-raw';
|
||||
import rehypeSanitize from 'rehype-sanitize';
|
||||
|
|
@ -340,10 +341,6 @@ const KnowledgeBasePage = ({ user }) => {
|
|||
return { todayKbs, pastKbs };
|
||||
};
|
||||
|
||||
const handleLogoClick = () => {
|
||||
navigate('/dashboard');
|
||||
};
|
||||
|
||||
// 导出知识库内容为图片
|
||||
const exportSummaryToImage = async () => {
|
||||
try {
|
||||
|
|
@ -400,15 +397,7 @@ const KnowledgeBasePage = ({ user }) => {
|
|||
|
||||
return (
|
||||
<div className="kb-management-page">
|
||||
<header className="kb-header">
|
||||
<div className="header-content">
|
||||
<div className="logo" onClick={handleLogoClick} style={{ cursor: 'pointer' }}>
|
||||
<MessageSquare className="logo-icon" />
|
||||
<span className="logo-text">iMeeting</span>
|
||||
</div>
|
||||
<h1>知识库管理</h1>
|
||||
</div>
|
||||
</header>
|
||||
<Breadcrumb currentPage="知识库管理" icon={Database} />
|
||||
|
||||
<div className="kb-layout">
|
||||
{/* 左侧知识库列表 */}
|
||||
|
|
|
|||
|
|
@ -126,13 +126,9 @@ const MeetingPreview = () => {
|
|||
{meetingData.creator_username}
|
||||
</div>
|
||||
<div className="info-item">
|
||||
<strong>参会人数:</strong>
|
||||
<strong>人数:</strong>
|
||||
{meetingData.attendees_count}人
|
||||
</div>
|
||||
<div className="info-item">
|
||||
<strong>参会人员:</strong>
|
||||
{attendeesList}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="summary-section">
|
||||
|
|
|
|||
|
|
@ -1,34 +1,8 @@
|
|||
import React from 'react';
|
||||
import { MessageSquare } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import PromptManagement from './admin/PromptManagement';
|
||||
import './PromptManagementPage.css';
|
||||
|
||||
const PromptManagementPage = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleLogoClick = () => {
|
||||
navigate('/dashboard');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="prompt-management-page">
|
||||
<header className="prompt-header">
|
||||
<div className="header-content">
|
||||
<div className="logo" onClick={handleLogoClick} style={{ cursor: 'pointer' }}>
|
||||
<MessageSquare className="logo-icon" />
|
||||
<span className="logo-text">iMeeting</span>
|
||||
</div>
|
||||
<h1>提示词仓库</h1>
|
||||
</div>
|
||||
</header>
|
||||
<div className="prompt-content">
|
||||
<div className="prompt-wrapper">
|
||||
<PromptManagement />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <PromptManagement />;
|
||||
};
|
||||
|
||||
export default PromptManagementPage;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* 提示词管理页面 - 左右分栏布局 */
|
||||
.prompt-management {
|
||||
height: 100vh;
|
||||
background: #f8fafc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
|
@ -12,6 +13,9 @@
|
|||
gap: 1.5rem;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import ConfirmDialog from '../../components/ConfirmDialog';
|
|||
import FormModal from '../../components/FormModal';
|
||||
import Toast from '../../components/Toast';
|
||||
import MarkdownEditor from '../../components/MarkdownEditor';
|
||||
import Breadcrumb from '../../components/Breadcrumb';
|
||||
|
||||
const TASK_TYPES = {
|
||||
MEETING_TASK: { label: '会议任务', icon: '📝' },
|
||||
|
|
@ -338,6 +339,8 @@ const PromptManagement = () => {
|
|||
|
||||
return (
|
||||
<div className="prompt-management">
|
||||
<Breadcrumb currentPage="提示词管理" icon={BookText} />
|
||||
|
||||
<div className="prompt-layout">
|
||||
{/* 左侧提示词列表 */}
|
||||
<div className={`prompt-sidebar ${sidebarCollapsed ? 'collapsed' : ''}`}>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
font-size: 14px;
|
||||
width: 240px;
|
||||
transition: all 0.2s;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.user-management .search-input:focus {
|
||||
|
|
|
|||
Loading…
Reference in New Issue