"use client";
|
|
import { useState, useEffect } from 'react';
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
// 导入场景数据
|
const defaultServices = [
|
{
|
title: '插单2.0',
|
description: '智能评估需求插单对产能,原材料和交付服务的影响,提升客户满意度',
|
imageUrl: '/images/xuqiu.jpg',
|
chatbotId: 'zO9YQDEHdIApG9zC',
|
background: '在生产计划执行过程中,常常会遇到紧急订单需要插单的情况。AI系统可以快速评估插单对现有生产计划的影响,并提供最优的插单方案。',
|
instructions: '请提供需要插单的订单信息,包括产品类型、数量和期望交付时间,AI助手将为您分析可行性并给出具体的插单建议。'
|
},
|
{
|
title: '补料',
|
description: '智能动态分析产线,工位的缺料情况,降低停线风险',
|
imageUrl: '/images/kanban.jpg',
|
chatbotId: 'JELkWpPLHQfRNhEH',
|
},
|
{
|
title: '插单1.0',
|
description: '智能评估需求插单对产能,原材料和交付服务的影响,提升客户满意度',
|
imageUrl: '/images/xuqiu.jpg',
|
chatbotId: 'DfH4cIzujVGvn5iR',
|
background: '在生产计划执行过程中,常常会遇到紧急订单需要插单的情况。AI系统可以快速评估插单对现有生产计划的影响,并提供最优的插单方案。',
|
instructions: '请提供需要插单的订单信息,包括产品类型、数量和期望交付时间,AI助手将为您分析可行性并给出具体的插单建议。'
|
},
|
{
|
title: '科沃斯销售推荐小助手',
|
description: '智能化产品推荐提升导购效率',
|
imageUrl: '/images/robot.jpg',
|
chatbotId: 'sUAviPXvcEIw3oQC',
|
},
|
{
|
title: '库存管理知识库问答',
|
description: '库存知识,提供专业的供应链库存知识问答',
|
imageUrl: '/images/know.jpg',
|
chatbotId: 'pDDfkU9HyBl2gzXx',
|
},
|
];
|
|
export default function AISceneChatPage() {
|
const [services, setServices] = useState(defaultServices);
|
const [selectedScene, setSelectedScene] = useState(services[0]);
|
const [iframeKey, setIframeKey] = useState(0);
|
|
// 切换场景时重新加载iframe
|
const handleSceneChange = (scene: typeof services[0]) => {
|
setSelectedScene(scene);
|
setIframeKey(prev => prev + 1);
|
};
|
|
// 添加新场景
|
const handleAddNewScene = () => {
|
const newScene = {
|
title: `新场景 ${services.length + 1}`,
|
description: '这是一个新的AI场景',
|
imageUrl: '/images/robot.jpg', // 默认图片
|
chatbotId: `new-scene-${Date.now()}`, // 生成唯一ID
|
};
|
setServices(prev => [...prev, newScene]);
|
};
|
|
return (
|
<div className="h-screen flex bg-white">
|
{/* 左侧场景选项卡 */}
|
<div className="w-64 bg-white border-r flex flex-col">
|
{/* 固定头部 */}
|
<div className="p-4 pt-20 bg-white">
|
<h2 className="text-xl font-bold flex items-center mb-4">
|
<span className="text-gray-900">
|
AI场景
|
</span>
|
<motion.span
|
className="ml-2 inline-block w-2 h-2 rounded-full bg-[#6ADBFF]"
|
animate={{
|
scale: [1, 1.5, 1],
|
opacity: [0.7, 1, 0.7]
|
}}
|
transition={{
|
duration: 2,
|
repeat: Infinity,
|
ease: "easeInOut"
|
}}
|
/>
|
</h2>
|
|
{/* 新增场景按钮 */}
|
<button
|
onClick={handleAddNewScene}
|
className="w-full p-3 bg-[#EEF3FD] text-[#4080FF] rounded-lg font-medium transition-all duration-300 flex items-center hover:bg-[#E1E9FA] group cursor-pointer"
|
>
|
<svg
|
className="w-5 h-5 mr-2"
|
viewBox="0 0 24 24"
|
fill="none"
|
stroke="currentColor"
|
>
|
<path
|
d="M12 5v14M5 12h14"
|
strokeWidth="2"
|
strokeLinecap="round"
|
strokeLinejoin="round"
|
/>
|
</svg>
|
开启新场景
|
</button>
|
</div>
|
|
{/* 滚动内容区 */}
|
<div className="flex-1 overflow-y-auto px-4 [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-[#E5E6EB] [&::-webkit-scrollbar-thumb]:rounded-full hover:[&::-webkit-scrollbar-thumb]:bg-[#C9CDD4]">
|
<div className="space-y-3 py-4">
|
{services.map((scene) => (
|
<motion.div
|
key={scene.chatbotId}
|
className="relative group"
|
>
|
<motion.button
|
onClick={() => handleSceneChange(scene)}
|
className={`w-full p-4 rounded-lg text-left transition-all duration-500 relative cursor-pointer
|
${selectedScene.chatbotId === scene.chatbotId
|
? 'text-[#6ADBFF] bg-gray-100 shadow-sm'
|
: 'text-gray-600 hover:text-[#6ADBFF] hover:bg-gray-50'
|
}`}
|
whileHover={{ scale: 1.02 }}
|
whileTap={{ scale: 0.98 }}
|
>
|
{selectedScene.chatbotId === scene.chatbotId && (
|
<motion.div
|
className="absolute inset-0 bg-gradient-to-r from-gray-100 to-gray-50 -z-10"
|
layoutId="activeBackground"
|
initial={false}
|
transition={{
|
type: "spring",
|
stiffness: 200,
|
damping: 20
|
}}
|
/>
|
)}
|
<div className="flex items-center relative z-10">
|
<div className="w-8 h-8 rounded-lg overflow-hidden mr-3 relative flex-shrink-0">
|
<img
|
src={scene.imageUrl}
|
alt={scene.title}
|
className="w-full h-full object-cover transform transition-transform duration-700 group-hover:scale-110"
|
/>
|
<div className="absolute inset-0 bg-gradient-to-br from-black/20 to-transparent"></div>
|
</div>
|
<div className="relative max-w-[120px] group/text">
|
<span className="font-medium truncate block w-full" ref={(el) => {
|
if (el) {
|
el.dataset.truncated = (el.scrollWidth > el.clientWidth).toString();
|
}
|
}}>{scene.title}</span>
|
{/* Tooltip - 只在文本被截断时显示 */}
|
<div
|
className="absolute left-1/2 -translate-x-1/2 -top-2 -translate-y-full bg-gray-800/95 text-white text-sm px-3 py-2 rounded-lg opacity-0 invisible data-[show=true]:group-hover/text:opacity-100 data-[show=true]:group-hover/text:visible transition-all duration-200 whitespace-nowrap shadow-lg z-[1000]"
|
data-show={scene.title.length > 8}
|
>
|
<div className="absolute left-1/2 -translate-x-1/2 top-full border-[6px] border-transparent border-t-gray-800/95"></div>
|
{scene.title}
|
</div>
|
</div>
|
</div>
|
{selectedScene.chatbotId === scene.chatbotId && (
|
<motion.div
|
className="absolute right-3 top-1/2 -translate-y-1/2 w-1.5 h-6 bg-[#6ADBFF] rounded-full"
|
layoutId="activeIndicator"
|
initial={{ opacity: 0 }}
|
animate={{ opacity: 1 }}
|
exit={{ opacity: 0 }}
|
/>
|
)}
|
</motion.button>
|
</motion.div>
|
))}
|
</div>
|
</div>
|
</div>
|
|
{/* 中间聊天区域 */}
|
<div className="flex-1 flex flex-col bg-white pt-20 overflow-hidden">
|
{/* 场景标题 */}
|
<div className="h-16 bg-white flex items-center justify-center px-6 border-b">
|
<h1 className="text-lg font-medium text-gray-900">
|
{selectedScene.title}
|
</h1>
|
</div>
|
|
{/* 聊天窗口 */}
|
<div className="flex-1 relative [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-[#E5E6EB] [&::-webkit-scrollbar-thumb]:rounded-full hover:[&::-webkit-scrollbar-thumb]:bg-[#C9CDD4]">
|
<AnimatePresence mode="wait">
|
<motion.div
|
key={iframeKey}
|
className="absolute inset-0"
|
initial={{ opacity: 0, scale: 0.98 }}
|
animate={{ opacity: 1, scale: 1 }}
|
exit={{ opacity: 0, scale: 1.02 }}
|
transition={{ duration: 0.3 }}
|
>
|
<iframe
|
src={`http://121.43.139.99/chatbot/${selectedScene.chatbotId}`}
|
className="w-full h-full"
|
style={{ border: 'none' }}
|
allow="microphone"
|
/>
|
</motion.div>
|
</AnimatePresence>
|
</div>
|
</div>
|
</div>
|
);
|
}
|