import { Request, Response } from 'express'; import { prisma } from '../config/database'; import { AuthRequest } from '../middleware/authMiddleware'; export const accountController = { // 获取所有账号 (管理员) async getAllAccounts(req: Request, res: Response) { const accounts = await prisma.websiteAccount.findMany({ include: { accountAssignments: { include: { user: { select: { id: true, username: true, } } } } } }); return res.json({ accounts: accounts.map((account: any) => ({ id: account.id, website: account.website, username: account.accountName, token: account.token, isActive: account.isActive, createdAt: account.createdAt, updatedAt: account.updatedAt, assignedUsers: account.accountAssignments.map((aa: any) => aa.user) })) }); }, // 根据ID获取账号 (管理员) async getAccountById(req: Request, res: Response) { const { id } = req.params; if (!id) { return res.status(400).json({ error: '账号ID是必需的' }); } const account = await prisma.websiteAccount.findUnique({ where: { id }, include: { accountAssignments: { include: { user: { select: { id: true, username: true, } } } } } }); if (!account) { return res.status(404).json({ error: '账号不存在' }); } return res.json({ account: { id: account.id, website: account.website, username: account.accountName, token: account.token, isActive: account.isActive, createdAt: account.createdAt, updatedAt: account.updatedAt, assignedUsers: account.accountAssignments.map((aa: any) => aa.user) } }); }, // 创建新账号 (管理员) async createAccount(req: Request, res: Response) { const { website, accountName, token, isActive, maxUsers } = req.body; if (!website || !accountName || !token) { return res.status(400).json({ error: '网站、账号名称和token是必需的' }); } // 检查账号是否已存在 const existingAccount = await prisma.websiteAccount.findFirst({ where: { website, accountName } }); if (existingAccount) { return res.status(400).json({ error: '账号已存在' }); } const account = await prisma.websiteAccount.create({ data: { website, accountName, token, isActive: isActive !== undefined ? isActive : true, maxUsers: maxUsers || 1, currentUsers: 0, } }); return res.status(201).json({ message: '账号创建成功', account: { id: account.id, website: account.website, username: account.accountName, token: account.token, isActive: account.isActive, createdAt: account.createdAt, updatedAt: account.updatedAt } }); }, // 更新账号 (管理员) async updateAccount(req: Request, res: Response) { const { id } = req.params; const { website, accountName, token, maxUsers, isActive } = req.body; if (!id) { return res.status(400).json({ error: '账号ID是必需的' }); } const account = await prisma.websiteAccount.findUnique({ where: { id } }); if (!account) { return res.status(404).json({ error: '账号不存在' }); } // 检查是否与其他账号重复(排除当前账号) if (website && accountName) { const existingAccount = await prisma.websiteAccount.findFirst({ where: { website, accountName, id: { not: id } } }); if (existingAccount) { return res.status(400).json({ error: '该网站和账号名称组合已存在' }); } } const updatedAccount = await prisma.websiteAccount.update({ where: { id }, data: { website, accountName, token, maxUsers, isActive, } }); return res.json({ message: '账号更新成功', account: { id: updatedAccount.id, website: updatedAccount.website, username: updatedAccount.accountName, token: updatedAccount.token, isActive: updatedAccount.isActive, createdAt: updatedAccount.createdAt, updatedAt: updatedAccount.updatedAt } }); }, // 删除账号 (管理员) async deleteAccount(req: Request, res: Response) { const { id } = req.params; if (!id) { return res.status(400).json({ error: '账号ID是必需的' }); } const account = await prisma.websiteAccount.findUnique({ where: { id } }); if (!account) { return res.status(404).json({ error: '账号不存在' }); } // 删除账号相关的所有分配 await prisma.$transaction([ prisma.accountAssignment.deleteMany({ where: { accountId: id } }), prisma.websiteAccount.delete({ where: { id } }) ]); return res.json({ message: '账号删除成功' }); }, // 获取用户的已分配账号 async getUserAccounts(req: AuthRequest, res: Response) { if (!req.user) { return res.status(401).json({ error: '未授权' }); } const assignments = await prisma.accountAssignment.findMany({ where: { userId: req.user.id, isActive: true, OR: [ { expiresAt: null }, { expiresAt: { gt: new Date() } } ] }, include: { account: { select: { id: true, website: true, accountName: true, token: true, isActive: true, createdAt: true, updatedAt: true, } } } }); return res.json({ accounts: assignments.map((aa: any) => ({ id: aa.account.id, website: aa.account.website, username: aa.account.accountName, token: aa.account.token, isActive: aa.account.isActive, createdAt: aa.account.createdAt, updatedAt: aa.account.updatedAt, assignedAt: aa.assignedAt, expiresAt: aa.expiresAt, })) }); }, // 分配账号给用户 (管理员) async assignAccount(req: Request, res: Response) { const { id } = req.params; const { userId, expiresAt } = req.body; if (!id || !userId) { return res.status(400).json({ error: '账号ID和用户ID都是必需的' }); } // 检查账号是否存在 const account = await prisma.websiteAccount.findUnique({ where: { id } }); if (!account) { return res.status(404).json({ error: '账号不存在' }); } // 检查用户是否存在 const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) { return res.status(404).json({ error: '用户不存在' }); } // 检查账号是否已满 if (account.currentUsers >= account.maxUsers) { return res.status(400).json({ error: '账号已达到最大用户数' }); } // 检查是否已经分配 const existingAssignment = await prisma.accountAssignment.findFirst({ where: { userId, accountId: id, isActive: true } }); if (existingAssignment) { return res.status(400).json({ error: '用户已分配此账号' }); } // 创建分配 const assignment = await prisma.accountAssignment.create({ data: { userId, accountId: id, expiresAt: expiresAt ? new Date(expiresAt) : null, isActive: true, } }); // 更新账号当前用户数 await prisma.websiteAccount.update({ where: { id }, data: { currentUsers: { increment: 1 } } }); return res.json({ message: '账号分配成功', assignment }); }, // 取消账号分配 (管理员) async unassignAccount(req: Request, res: Response) { const { id, userId } = req.params; if (!id || !userId) { return res.status(400).json({ error: '账号ID和用户ID都是必需的' }); } const assignment = await prisma.accountAssignment.findFirst({ where: { userId, accountId: id, isActive: true } }); if (!assignment) { return res.status(404).json({ error: '分配不存在' }); } // 删除分配 await prisma.accountAssignment.delete({ where: { id: assignment.id } }); // 更新账号当前用户数 await prisma.websiteAccount.update({ where: { id }, data: { currentUsers: { decrement: 1 } } }); return res.json({ message: '账号分配已取消' }); }, // 网站登录 async loginToWebsite(req: Request, res: Response) { const { accountId } = req.params; const { userId } = req.body; if (!accountId || !userId) { return res.status(400).json({ error: '账号ID和用户ID是必需的' }); } try { // 获取账号信息 const account = await prisma.websiteAccount.findUnique({ where: { id: accountId } }); if (!account) { return res.status(404).json({ error: '账号不存在' }); } // 检查用户是否有权限访问该账号 console.log('检查用户权限:', { accountId, userId }); const assignment = await prisma.accountAssignment.findFirst({ where: { accountId, userId, isActive: true, OR: [ { expiresAt: null }, { expiresAt: { gt: new Date() } } ] } }); console.log('权限检查结果:', { assignment: assignment ? 'found' : 'not found', accountId, userId, currentTime: new Date() }); if (!assignment) { // 获取更多调试信息 const allAssignments = await prisma.accountAssignment.findMany({ where: { accountId, userId } }); console.log('该用户的所有分配记录:', allAssignments); return res.status(403).json({ error: '您没有权限访问该账号' }); } let loginUrl = ''; // 根据网站类型处理登录 switch (account.website) { case 'claude': loginUrl = await handleClaudeLogin(account.token, userId); break; case 'chatgpt': loginUrl = await handleChatGPTLogin(account.token, userId); break; case 'grok': loginUrl = await handleGrokLogin(account.token, userId); break; default: return res.status(400).json({ error: '不支持的网站类型' }); } return res.json({ success: true, loginUrl, website: account.website, accountName: account.accountName }); } catch (error) { console.error('网站登录失败:', error); return res.status(500).json({ error: '登录失败,请稍后重试' }); } } }; // Claude 登录处理 async function handleClaudeLogin(token: string, userName: string): Promise { try { const baseUrl = process.env.CLAUDE_TARGET_URL || 'https://chat.micar9.com'; console.log('Claude登录处理:', { token, userName }); // 第一步:获取oauth token const oauthResponse = await fetch(`${baseUrl}/manage-api/auth/oauth_token`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_key: token, unique_name: userName }) }); if (!oauthResponse.ok) { throw new Error(`OAuth token 请求失败: ${oauthResponse.status}`); } const oauthData = await oauthResponse.json() as { login_url?: string }; if (!oauthData.login_url) { throw new Error('未获取到登录URL'); } return oauthData.login_url; } catch (error) { console.error('Claude登录处理失败:', error); throw error; } } // ChatGPT 登录处理 async function handleChatGPTLogin(token: string, userName: string): Promise { try { const baseUrl = process.env.CHATGPT_TARGET_URL || 'http://127.0.0.1:8181'; const response = await fetch(`${baseUrl}/api/login`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.ADMIN_PASSWORD || 'admin'}` }, body: JSON.stringify({ access_token: token, user_name: userName, isolated_session: true, limits: [] }) }); if (!response.ok) { throw new Error(`ChatGPT登录请求失败: ${response.status}`); } const data = await response.json() as { login_url?: string }; if (!data.login_url) { throw new Error('未获取到登录URL'); } return data.login_url; } catch (error) { console.error('ChatGPT登录处理失败:', error); throw error; } } // Grok 登录处理 async function handleGrokLogin(token: string, userName: string): Promise { try { const baseUrl = process.env.GROK_TARGET_URL || 'https://grok-mirror.micar9.com'; const response = await fetch(`${baseUrl}/api/login-v2`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ user_name: userName, sso_token: token }) }); if (!response.ok) { throw new Error(`Grok登录请求失败: ${response.status}`); } const data = await response.json() as { login_url?: string }; if (!data.login_url) { throw new Error('未获取到登录URL'); } return data.login_url; } catch (error) { console.error('Grok登录处理失败:', error); throw error; } }