增加了权限系统

main
mula.liu 2025-12-11 21:19:08 +08:00
parent 39eb9e8812
commit 3bb66c8e81
15 changed files with 172 additions and 170 deletions

BIN
.DS_Store vendored

Binary file not shown.

BIN
dist.zip

Binary file not shown.

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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">

View File

@ -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;

View File

@ -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 {

View File

@ -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">
{/* 左侧知识库列表 */}

View File

@ -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">

View File

@ -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;

View File

@ -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;
}

View File

@ -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' : ''}`}>

View File

@ -26,6 +26,7 @@
font-size: 14px;
width: 240px;
transition: all 0.2s;
margin: 0px;
}
.user-management .search-input:focus {