feat: 完善代理商端业务逻辑与前后端框架

主要更新:
- 更新代理商端文档,明确项目由品牌方分配流程
- 新增Brief配置详情页(已配置)设计稿
- 完善工作台紧急待办中品牌新任务功能
- 整理Pencil设计文件中代理商端页面顺序
- 新增后端FastAPI框架及核心API
- 新增前端Next.js页面和组件库
- 添加.gitignore排除构建和缓存文件

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-02-05 19:27:31 +08:00
co-authored by Claude Opus 4.5
parent d52509d630
commit e4959d584f
132 changed files with 58539 additions and 21353 deletions
+118
View File
@@ -0,0 +1,118 @@
'use client'
import { createContext, useContext, useState, useEffect, ReactNode } from 'react'
import { User, UserRole, LoginCredentials, AuthContextType } from '@/types/auth'
const AuthContext = createContext<AuthContextType | undefined>(undefined)
// 模拟用户数据(后续替换为真实 API)
const MOCK_USERS: Record<string, User & { password: string }> = {
'creator@demo.com': {
id: 'user-001',
name: '达人小美',
email: 'creator@demo.com',
role: 'creator',
tenantId: 'tenant-001',
tenantName: '美妆品牌A',
password: 'demo123',
},
'agency@demo.com': {
id: 'user-002',
name: '张经理',
email: 'agency@demo.com',
role: 'agency',
tenantId: 'tenant-001',
tenantName: '美妆品牌A',
password: 'demo123',
},
'brand@demo.com': {
id: 'user-003',
name: '李总监',
email: 'brand@demo.com',
role: 'brand',
tenantId: 'tenant-001',
tenantName: '美妆品牌A',
password: 'demo123',
},
}
const STORAGE_KEY = 'miaosi_auth'
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null)
const [isLoading, setIsLoading] = useState(true)
const [mounted, setMounted] = useState(false)
// 初始化时从 localStorage 恢复登录状态
useEffect(() => {
setMounted(true)
if (typeof window !== 'undefined') {
const stored = localStorage.getItem(STORAGE_KEY)
if (stored) {
try {
const parsed = JSON.parse(stored)
setUser(parsed)
} catch {
localStorage.removeItem(STORAGE_KEY)
}
}
}
setIsLoading(false)
}, [])
const login = async (credentials: LoginCredentials): Promise<{ success: boolean; error?: string }> => {
// 模拟 API 延迟
await new Promise((resolve) => setTimeout(resolve, 500))
const mockUser = MOCK_USERS[credentials.email]
if (!mockUser) {
return { success: false, error: '用户不存在' }
}
if (mockUser.password !== credentials.password) {
return { success: false, error: '密码错误' }
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { password, ...userWithoutPassword } = mockUser
setUser(userWithoutPassword)
localStorage.setItem(STORAGE_KEY, JSON.stringify(userWithoutPassword))
return { success: true }
}
const logout = () => {
setUser(null)
localStorage.removeItem(STORAGE_KEY)
}
const switchRole = (role: UserRole) => {
if (user) {
const updated = { ...user, role }
setUser(updated)
localStorage.setItem(STORAGE_KEY, JSON.stringify(updated))
}
}
return (
<AuthContext.Provider
value={{
user,
isAuthenticated: !!user,
isLoading,
login,
logout,
switchRole,
}}
>
{children}
</AuthContext.Provider>
)
}
export function useAuth() {
const context = useContext(AuthContext)
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider')
}
return context
}