{"repo": "19125119617/ai-customer-service", "files": {"src/app/api/ai/chat/route.ts": {"db4291e5eaaede2c19cffd573e01d953bafb54e5": {"t": 1785746034.3805614, "n": 3100, "h": "5ebe05ef50393fcf", "c": "// AI 聊天 API\nimport { NextRequest, NextResponse } from 'next/server';\nimport { ragQuery } from '@/lib/rag';\nimport prisma from '@/lib/prisma';\n\n// AI 提供商配置\nconst AI_PROVIDERS = {\n deepseek: {\n baseURL: 'https://api.deepseek.com/v1',\n model: 'deepseek-chat',\n },\n qwen: {\n baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',\n model: 'qwen-turbo',\n },\n moonshot: {\n baseURL: 'https://api.moonshot.cn/v1',\n model: 'moonshot-v1-8k',\n },\n zhipu: {\n baseURL: 'https://open.bigmodel.cn/api/paas/v4',\n model: 'glm-4-flash',\n },\n};\n\n// 调用 AI 接口\nasync function callAI(prompt: string, provider: keyof typeof AI_PROVIDERS = 'deepseek', apiKey?: string) {\n const config = AI_PROVIDERS[provider];\n const key = apiKey || process.env.AI_API_KEY;\n\n if (!key) {\n throw new Error('未配置 API Key');\n }\n\n const response = await fetch(`${config.baseURL}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${key}`,\n },\n body: JSON.stringify({\n model: config.model,\n messages: [\n { role: 'system', content: '你是一个专业的客服助手,请用友好的语气回答用户的问题。' },\n { role: 'user', content: prompt },\n ],\n temperature: 0.7,\n max_tokens: 1000,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`AI 调用失败: ${error}`);\n }\n\n const data = await response.json();\n return data.choices[0]?.message?.content || '抱歉,我暂时无法回答这个问题。';\n}\n\n// POST /api/ai/chat - AI 聊天\nexport async function POST(request: NextRequest) {\n try {\n const body = await request.json();\n const { conversationId, message, provider = 'deepseek' } = body;\n\n if (!message) {\n return NextResponse.json({ error: '缺少消息内容' }, { status: 400 });\n }\n\n // 1. 从知识库检索相关内容\n const teamId = 'default-team';\n const ragResult = await ragQuery(message, teamId);\n\n // 2. 构建 prompt\n let prompt = message;\n if (ragResult.sources.length > 0) {\n const context = ragResult.sources\n .map((s, i) => `[参考${i + 1}]: ${s.content}`)\n .join('\\n\\n');\n prompt = `参考以下知识库内容回答用户问题:\\n\\n${context}\\n\\n用户问题:${message}\\n\\n请根据知识库内容给出回答,如果没有相关信息,请如实说明。`;\n }\n\n // 3. 调用 AI\n const aiResponse = await callAI(prompt, provider as any);\n\n // 4. 如果有会话ID,保存 AI 回复到数据库\n if (conversationId) {\n // 获取默认用户或创建系统消息\n const aiMessage = await prisma.message.create({\n data: {\n conversationId,\n senderId: 'ai-assistant',\n senderType: 'AI',\n content: aiResponse,\n isAiGenerated: true,\n },\n });\n\n return NextResponse.json({\n message: aiMessage,\n sources: ragResult.sources,\n elapsed: ragResult.elapsed,\n });\n }\n\n return NextResponse.json({\n response: aiResponse,\n sources: ragResult.sources,\n elapsed: ragResult.elapsed,\n });\n } catch (error) {\n console.error('Error in AI chat:', error);\n return NextResponse.json(\n { error: error instanceof Error ? error.message : 'AI 聊天失败' },\n { status: 500 }\n );\n }\n}\n"}}, "src/app/settings/page.tsx": {"db4291e5eaaede2c19cffd573e01d953bafb54e5": {"t": 1785747362.861727, "n": 78799, "h": "3bfce95adb7c851c", "c": "\"use client\";\nimport { useState } from \"react\";\nimport PageLayout from \"@/components/PageLayout\";\nimport {\n Settings, Users, Bell, Shield, Globe, Palette, Database, Key,\n Check, X, Plus, Trash2, Copy, Eye, EyeOff, RefreshCw, Download,\n Mail, Smartphone, Webhook, Trash, AlertTriangle,\n CheckCircle2, Image as ImageIcon, Moon, Sun, Monitor,\n Store, Link, TestTube, Edit2, ToggleLeft, ToggleRight,\n Book, ExternalLink,\n} from \"lucide-react\";\n\nconst menuItems = [\n { icon: Book, label: \"使用教程\", desc: \"各模块使用指南、API配置教程\" },\n { icon: Settings, label: \"项目设置\", desc: \"基本信息、时区、语言\" },\n { icon: Users, label: \"成员管理\", desc: \"添加成员、设置角色\" },\n { icon: Shield, label: \"权限配置\", desc: \"角色权限、访问控制\" },\n { icon: Bell, label: \"通知设置\", desc: \"邮件、短信、推送通知\" },\n { icon: Globe, label: \"渠道配置\", desc: \"渠道接入、Webhook\" },\n { icon: Palette, label: \"界面定制\", desc: \"主题、Logo、颜色\" },\n { icon: Database, label: \"数据管理\", desc: \"数据导出、清理\" },\n { icon: Key, label: \"API密钥\", desc: \"管理API访问密钥\" },\n];\n\nconst permissionModules = [\n { id: \"dashboard\", name: \"首页仪表盘\", permissions: [\"查看\", \"编辑\"] },\n { id: \"conversations\", name: \"聊天会话\", permissions: [\"查看\", \"回复\", \"转接\", \"关闭\"] },\n { id: \"customers\", name: \"客户管理\", permissions: [\"查看\", \"编辑\", \"删除\", \"导入导出\"] },\n { id: \"marketing\", name: \"营销模块\", permissions: [\"查看\", \"创建\", \"编辑\", \"删除\", \"发送\"] },\n { id: \"ai\", name: \"AI机器人\", permissions: [\"查看\", \"配置\", \"训练\", \"启停\"] },\n { id: \"knowledge\", name: \"知识库\", permissions: [\"查看\", \"上传\", \"编辑\", \"删除\"] },\n { id: \"channels\", name: \"渠道管理\", permissions: [\"查看\", \"添加\", \"编辑\", \"删除\"] },\n { id: \"reports\", name: \"报告分析\", permissions: [\"查看\", \"导出\"] },\n { id: \"settings\", name: \"系统设置\", permissions: [\"查看\", \"编辑\"] },\n];\n\nconst roles = [\n { id: \"admin\", name: \"管理员\", description: \"拥有所有权限\", color: \"bg-red-100 text-red-700\" },\n { id: \"supervisor\", name: \"主管\", description: \"管理团队和查看报告\", color: \"bg-purple-100 text-purple-700\" },\n { id: \"agent\", name: \"客服\", description: \"处理会话和客户\", color: \"bg-blue-100 text-blue-700\" },\n { id: \"viewer\", name: \"访客\", description: \"仅查看权限\", color: \"bg-gray-100 text-gray-700\" },\n];\n\nconst notificationTypes = [\n { id: \"new_message\", name: \"新消息提醒\", description: \"当有新客户消息时\", email: true, push: true, sms: false },\n { id: \"assigned\", name: \"会话分配\", description: \"当有新会话分配给你时\", email: true, push: true, sms: false },\n { id: \"ai_handover\", name: \"AI转人工\", description: \"当AI无法处理转人工时\", email: true, push: true, sms: true },\n { id: \"customer_join\", name: \"客户接入\", description: \"当高价值客户接入时\", email: false, push: true, sms: false },\n { id: \"daily_report\", name: \"日报\", description: \"每日工作汇总\", email: true, push: false, sms: false },\n { id: \"weekly_report\", name: \"周报\", description: \"每周工作汇总\", email: true, push: false, sms: false },\n { id: \"system_alert\", name: \"系统告警\", description: \"系统异常或维护通知\", email: true, push: true, sms: true },\n];\n\ntype ChannelConfig = {\n id: string; name: string; type: string; status: string; icon: string;\n webhook: string; appId: string; appSecret: string; bindStore: string; enabled: boolean;\n};\n\nconst channelConfigs: ChannelConfig[] = [\n { id: \"whatsapp\", name: \"WhatsApp\", type: \"即时通讯\", status: \"已连接\", icon: \"💬\", webhook: \"https://api.example.com/webhook/whatsapp\", appId: \"WA_APP_12345\", appSecret: \"whasec_xxxx\", bindStore: \"主店铺\", enabled: true },\n { id: \"messenger\", name: \"Messenger\", type: \"即时通讯\", status: \"已连接\", icon: \"📘\", webhook: \"https://api.example.com/webhook/messenger\", appId: \"MSG_APP_67890\", appSecret: \"msgsec_xxxx\", bindStore: \"主店铺\", enabled: true },\n { id: \"telegram\", name: \"Telegram\", type: \"即时通讯\", status: \"已连接\", icon: \"✈️\", webhook: \"https://api.example.com/webhook/telegram\", appId: \"TG_BOT_11111\", appSecret: \"tgsec_xxxx\", bindStore: \"\", enabled: true },\n { id: \"email\", name: \"Email\", type: \"邮件\", status: \"已连接\", icon: \"📧\", webhook: \"https://api.example.com/webhook/email\", appId: \"support@company.com\", appSecret: \"\", bindStore: \"主店铺\", enabled: true },\n { id: \"line\", name: \"LINE\", type: \"即时通讯\", status: \"未连接\", icon: \"🟢\", webhook: \"\", appId: \"\", appSecret: \"\", bindStore: \"\", enabled: false },\n { id: \"wechat\", name: \"微信公众号\", type: \"即时通讯\", status: \"未连接\", icon: \"💚\", webhook: \"\", appId: \"\", appSecret: \"\", bindStore: \"\", enabled: false },\n];\n\nconst apiKeys = [\n { id: \"1\", name: \"生产环境密钥\", key: \"ak_live_xxxxxxxxxxxx\", createdAt: \"2026-01-15\", lastUsed: \"2小时前\", status: \"active\" },\n { id: \"2\", name: \"测试环境密钥\", key: \"ak_test_xxxxxxxxxxxx\", createdAt: \"2026-02-01\", lastUsed: \"1天前\", status: \"active\" },\n { id: \"3\", name: \"开发环境密钥\", key: \"ak_dev_xxxxxxxxxxxx\", createdAt: \"2026-01-20\", lastUsed: \"3天前\", status: \"inactive\" },\n];\n\n// ---- Toast 组件 ----\nfunction Toast({ msg, type = \"success\", onClose }: { msg: string; type?: \"success\" | \"error\" | \"info\"; onClose: () => void }) {\n const colorMap = { success: \"bg-gray-900 text-white\", error: \"bg-red-600 text-white\", info: \"bg-blue-600 text-white\" };\n return (\n
学习系统各功能的使用方法和API配置指南
\n{item.desc}
\n观看完整操作视频,手把手教学
\n管理你的客服系统基本配置
\n管理团队成员和权限
\n| {h} | )}||||
|---|---|---|---|---|
| \n \n \n {m.name[0]} \n \n \n {m.name} \n {m.email} \n | \n \n {m.role}\n | \n\n \n \n {m.status}\n \n | \n {m.joined} | \n\n \n \n | \n
管理角色权限和访问控制
\n| 功能模块 | \n {permissionModules[0]?.permissions.map(p =>{p} | )}\n
|---|---|
| {module.name} | \n {module.permissions.map(permission => {\n const key = `${module.id}:${permission}`;\n const has = rolePermissions[selectedRole]?.includes(key);\n return (\n\n \n | \n );\n })}\n
配置邮件、短信和推送通知
\n浏览器 / APP 推送通知,无需额外配置
\n| 通知类型 | \n邮件 | \n推送 | \n短信 | \n
|---|---|---|---|
| \n {n.name} \n {n.description} \n | \n {([\"email\", \"push\", \"sms\"] as const).map(type => (\n \n toggleNotification(n.id, type)} className=\"rounded text-blue-600\" />\n | \n ))}\n
管理各渠道接入、绑定店铺和 Webhook 设置
\n自定义主题、Logo和品牌颜色
\n数据导出、备份和清理
\n管理API访问密钥和权限
\n| {h} | )}|||||
|---|---|---|---|---|---|
| {k.name} | \n\n \n \n {showKeyId === k.id ? k.key : `${k.key.substring(0, 8)}...`}\n \n | \n {k.createdAt} | \n{k.lastUsed} | \n\n \n {k.status === \"active\" ? \"活跃\" : \"已禁用\"}\n \n | \n\n \n \n \n \n | \n
查看完整的 API 文档和示例代码
\n \n邀请邮件将发送至上述地址,对方接受后成为团队成员。
\n确定要移除成员 \"{deletingMember.name}\" 吗?移除后该成员将无法访问系统。
\n绑定后,该渠道的会话将关联到对应店铺的客户数据
\n✓ Webhook 连通性正常
}\n {webhookTestResult[editingChannel.id] === \"fail\" &&✗ Webhook 测试失败,请检查地址
}\nAPI Key 将加密保存,不会在页面中明文展示
\n请立即复制保存,此密钥仅显示一次
\n{generatedKey}\n \n 即将导出 {showExportConfirm.name}
\n此操作不可恢复,请谨慎操作
\n{showCleanConfirm.desc}
\n