feat: 智能客服系统基础架构完成
✅ 已完成功能: 1. 项目基础设施和Docker开发环境 2. 前端React 18 + TypeScript架构 3. 后端Golang + Gin框架 4. 多租户数据库设计 5. 完整API路由系统 6. 智能客服聊天界面 7. 详细文档和部署指南 🔧 技术栈: - 前端:React 18, TypeScript, Vite, Zustand - 后端:Golang, Gin, GORM, PostgreSQL - 部署:Docker, Docker Compose 🎨 设计规范: - 无渐变色,无紫色 - 简洁专业的中性色系 - 响应式布局 📊 状态: - 前端开发服务器:http://localhost:5173 - 后端API服务:http://localhost:8080 - 数据库:PostgreSQL + Redis - 完整的多租户架构 作者:小弟 (大哥的AI助手) 日期:2026-02-27
This commit is contained in:
175
frontend/src/components/Layout/Header.tsx
Normal file
175
frontend/src/components/Layout/Header.tsx
Normal file
@@ -0,0 +1,175 @@
|
||||
import React from 'react';
|
||||
import { useTheme } from '../../hooks/useTheme';
|
||||
import { Bell, Search, User, Settings } from 'lucide-react';
|
||||
|
||||
export const Header: React.FC = () => {
|
||||
const { theme } = useTheme();
|
||||
|
||||
return (
|
||||
<header style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: `${theme.spacing.sm} ${theme.spacing.lg}`,
|
||||
backgroundColor: theme.colors.background.header,
|
||||
borderBottom: `1px solid ${theme.colors.border.light}`,
|
||||
boxShadow: theme.shadows.sm,
|
||||
}}>
|
||||
{/* 左侧:搜索框 */}
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
maxWidth: '400px',
|
||||
}}>
|
||||
<div style={{
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
}}>
|
||||
<Search size={20} style={{
|
||||
position: 'absolute',
|
||||
left: theme.spacing.sm,
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
color: theme.colors.text.secondary,
|
||||
}} />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="搜索对话、工单或用户..."
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: `${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.xl}`,
|
||||
borderRadius: theme.borderRadius.md,
|
||||
border: `1px solid ${theme.colors.border.default}`,
|
||||
backgroundColor: theme.colors.background.light,
|
||||
fontSize: theme.typography.fontSize.sm,
|
||||
color: theme.colors.text.primary,
|
||||
outline: 'none',
|
||||
transition: `border-color ${theme.transitions.duration.fast} ${theme.transitions.timing.ease}`,
|
||||
}}
|
||||
onFocus={(e) => {
|
||||
e.target.style.borderColor = theme.colors.primary[500];
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
e.target.style.borderColor = theme.colors.border.default;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 右侧:用户操作 */}
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: theme.spacing.md,
|
||||
}}>
|
||||
{/* 通知 */}
|
||||
<button
|
||||
style={{
|
||||
position: 'relative',
|
||||
padding: theme.spacing.sm,
|
||||
borderRadius: theme.borderRadius.full,
|
||||
border: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
cursor: 'pointer',
|
||||
color: theme.colors.text.secondary,
|
||||
transition: `all ${theme.transitions.duration.fast} ${theme.transitions.timing.ease}`,
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.backgroundColor = theme.colors.neutral[100];
|
||||
e.currentTarget.style.color = theme.colors.text.primary;
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.backgroundColor = 'transparent';
|
||||
e.currentTarget.style.color = theme.colors.text.secondary;
|
||||
}}
|
||||
>
|
||||
<Bell size={20} />
|
||||
<span style={{
|
||||
position: 'absolute',
|
||||
top: '4px',
|
||||
right: '4px',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: theme.colors.semantic.error,
|
||||
border: `2px solid ${theme.colors.background.header}`,
|
||||
}} />
|
||||
</button>
|
||||
|
||||
{/* 设置 */}
|
||||
<button
|
||||
style={{
|
||||
padding: theme.spacing.sm,
|
||||
borderRadius: theme.borderRadius.full,
|
||||
border: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
cursor: 'pointer',
|
||||
color: theme.colors.text.secondary,
|
||||
transition: `all ${theme.transitions.duration.fast} ${theme.transitions.timing.ease}`,
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.backgroundColor = theme.colors.neutral[100];
|
||||
e.currentTarget.style.color = theme.colors.text.primary;
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.backgroundColor = 'transparent';
|
||||
e.currentTarget.style.color = theme.colors.text.secondary;
|
||||
}}
|
||||
>
|
||||
<Settings size={20} />
|
||||
</button>
|
||||
|
||||
{/* 用户头像 */}
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: theme.spacing.sm,
|
||||
padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
|
||||
borderRadius: theme.borderRadius.md,
|
||||
cursor: 'pointer',
|
||||
transition: `background-color ${theme.transitions.duration.fast} ${theme.transitions.timing.ease}`,
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.backgroundColor = theme.colors.neutral[100];
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.backgroundColor = 'transparent';
|
||||
}}
|
||||
>
|
||||
<div style={{
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: theme.colors.primary[500],
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: theme.colors.text.inverse,
|
||||
fontWeight: theme.typography.fontWeight.medium,
|
||||
}}>
|
||||
<User size={16} />
|
||||
</div>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}>
|
||||
<span style={{
|
||||
fontSize: theme.typography.fontSize.sm,
|
||||
fontWeight: theme.typography.fontWeight.medium,
|
||||
color: theme.colors.text.primary,
|
||||
}}>
|
||||
管理员
|
||||
</span>
|
||||
<span style={{
|
||||
fontSize: theme.typography.fontSize.xs,
|
||||
color: theme.colors.text.secondary,
|
||||
}}>
|
||||
admin@example.com
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user