From d38a3ae95ce1ca3d736ec0f88f17973fa0d5a914 Mon Sep 17 00:00:00 2001
From: hongjli <3117313295@qq.com>
Date: 星期四, 05 六月 2025 13:10:08 +0800
Subject: [PATCH] 页面调整优化

---
 src/components/SceneIntroDialog.tsx           |  138 ++++
 src/app/ai-scene/chat/page.tsx                |  104 +++
 src/components/DataPreviewDialog.tsx          |   76 ++
 src/app/ai-scene/page.tsx                     |   92 +++
 src/components/layout/ClientLayoutContent.tsx |    3 
 src/app/supply-chain-chat/page.tsx            | 1207 ++++++++++++++++++++++++++++++++++++++++++++
 public/images/333.png                         |    0 
 7 files changed, 1,601 insertions(+), 19 deletions(-)

diff --git a/public/images/333.png b/public/images/333.png
new file mode 100644
index 0000000..756949c
--- /dev/null
+++ b/public/images/333.png
Binary files differ
diff --git a/src/app/ai-scene/chat/page.tsx b/src/app/ai-scene/chat/page.tsx
index 41d53ad..4d40b9a 100644
--- a/src/app/ai-scene/chat/page.tsx
+++ b/src/app/ai-scene/chat/page.tsx
@@ -207,6 +207,99 @@
 | S5 | 1005 | 16673976114@163.com |
 `
   },
+  {
+    title: '渚涘簲閾惧叏鏅礊瀵�',
+    description: '閫氳繃AI Agent涓嶢PS鐨勬繁搴﹀崗鍚岋紝灏嗘彃鍗曞搷搴斾粠"琚姩鏁戠伀"鍗囩骇涓�"棰勬祴-鍐崇瓥-鎵ц"涓変綅涓�浣撶殑鏅鸿兘杩愯惀妯″紡锛屽姪鍔涙柊鑳芥簮涓氬姟澧為暱銆�',
+    imageUrl: '/images/333.png',
+    chatbotId: 'SCPanoramaInsight',
+    background: `渚涘簲閾惧叏鏅礊瀵熺郴缁熸槸鏂颁竴浠f櫤鑳戒緵搴旈摼绠$悊骞冲彴鐨勬牳蹇冨紩鎿庛�傝AI绯荤粺鑳藉瑙e喅浼犵粺渚涘簲閾剧鐞嗕腑鐨勫洓澶у叧閿棶棰橈細
+
+**鐢熶骇璁″垝涓庝骇鑳藉奖鍝嶈瘎浼帮細**
+- 瀹炴椂鐩戞帶鐢熶骇绾跨姸鎬侊紝鍔ㄦ�佽瘎浼颁骇鑳藉埄鐢ㄧ巼
+- 鍩轰簬鍘嗗彶鏁版嵁鍜屽疄鏃惰鍗曪紝鏅鸿兘棰勬祴鐢熶骇鐡堕
+- 鑷姩璋冩暣鐢熶骇璁″垝锛屾渶澶у寲浜ц兘鍒╃敤鏁堢巼
+- 鎻愪緵澶氬満鏅敓浜ц鍒掑姣斿垎鏋愶紝杈呭姪鍐崇瓥鍒跺畾
+
+**渚涘簲鍗忓悓鑳藉姏璇勪及锛�**
+- 瀹炴椂杩借釜渚涘簲鍟嗕氦浠樼姸鎬侊紝璇勪及渚涘簲椋庨櫓
+- 鏅鸿兘鍒嗘瀽渚涘簲鍟嗙哗鏁堬紝鎻愪緵渚涘簲鍟嗕紭鍖栧缓璁�
+- 棰勬祴鍘熸潗鏂欓渶姹傦紝鎻愬墠鍚姩閲囪喘娴佺▼
+- 鏋勫缓渚涘簲閾剧綉缁滈煣鎬фā鍨嬶紝鎻愬崌鎶楅闄╄兘鍔�
+
+**浜や粯灞ョ害椋庨櫓璇勪及锛�**
+- 鍩轰簬璁㈠崟銆佸簱瀛樸�佺敓浜ц繘搴﹁繘琛岀患鍚堥闄╄瘎浼�
+- 鎻愬墠璇嗗埆娼滃湪寤舵湡椋庨櫓锛屽埗瀹氬簲瀵归妗�
+- 瀹炴椂璺熻釜浜や粯杩涘害锛岀‘淇濆鎴锋弧鎰忓害
+- 寤虹珛瀹㈡埛棰勬湡绠$悊鏈哄埗锛屾彁鍗囨湇鍔′綋楠�
+
+**鎴愭湰涓庤储鍔″奖鍝嶈瘎浼帮細**
+- 鍏ㄩ摼璺垚鏈拷韪紝绮剧‘璁$畻鍚勭幆鑺傛垚鏈瀯鎴�
+- 鍔ㄦ�佹垚鏈紭鍖栧缓璁紝闄嶄綆鏁翠綋杩愯惀鎴愭湰
+- 璐㈠姟褰卞搷棰勬祴鍒嗘瀽锛屾敮鎸佸晢涓氬喅绛�
+- ROI璇勪及妯″瀷锛岄噺鍖栨敼杩涙帾鏂界殑璐㈠姟鏁堢泭`,
+    instructions: `鎮ㄥ彲浠ラ�氳繃浠ヤ笅鏂瑰紡涓庝緵搴旈摼鍏ㄦ櫙娲炲療绯荤粺浜掑姩锛�
+
+**鍦烘櫙涓�锛氭彃鍗曞奖鍝嶅垎鏋�**
+鎻愪緵鏂拌鍗曚俊鎭紝绯荤粺灏嗕粠鍥涗釜缁村害璇勪及鎻掑崟鍙鎬у拰褰卞搷銆�
+
+**鍦烘櫙浜岋細鐢熶骇璁″垝浼樺寲**
+鎻忚堪褰撳墠鐢熶骇鐘跺喌锛岃幏鍙栨櫤鑳戒紭鍖栧缓璁拰椋庨櫓棰勮銆�
+
+**鍦烘櫙涓夛細渚涘簲閾鹃闄╄瘎浼�**
+杈撳叆渚涘簲鍟嗘垨鍘熸潗鏂欎俊鎭紝鑾峰彇渚涘簲椋庨櫓鍒嗘瀽鍜屽簲瀵圭瓥鐣ャ��
+
+**鍦烘櫙鍥涳細鎴愭湰浼樺寲鍒嗘瀽**
+鎻愪緵鎴愭湰鐩稿叧鏁版嵁锛岃幏鍙栨垚鏈紭鍖栧缓璁拰璐㈠姟褰卞搷璇勪及銆�
+
+绯荤粺灏嗗熀浜庡疄鏃舵暟鎹拰AI绠楁硶锛屼负鎮ㄦ彁渚涗笓涓氱殑鍒嗘瀽鎶ュ憡鍜屽喅绛栧缓璁�俙,
+    dataDescription: '鏈満鏅暣鍚堜簡OMS銆丒RP銆乄MS绛夊涓郴缁熺殑瀹炴椂鏁版嵁锛岄�氳繃AI绠楁硶杩涜娣卞害鍒嗘瀽銆備互涓嬩负鏂拌兘婧愯涓氱殑妯℃嫙鏁版嵁锛屽疄闄呭簲鐢ㄤ腑灏嗚嚜鍔ㄥ鎺ヤ紒涓氱幇鏈夌郴缁熴��',
+    exampleData: `
+### 璁㈠崟闇�姹傛暟鎹� (OMS绯荤粺)
+
+| 璁㈠崟鍙� | 浜у搧鍨嬪彿 | 鏁伴噺 | 瀹㈡埛鍚嶇О | 棰勬湡浜や粯鏃ユ湡 | 浼樺厛绾� | 璁㈠崟閲戦 |
+| :--: | :--: | :--: | :--: | :--: | :--: | :--: |
+| SO20250201001 | NEV-Battery-A | 500 | 姣斾簹杩� | 2025-02-15 | 楂� | 2,500,000 |
+| SO20250201002 | NEV-Motor-B | 200 | 钄氭潵姹借溅 | 2025-02-20 | 涓� | 1,800,000 |
+| SO20250201003 | NEV-Controller-C | 300 | 鐞嗘兂姹借溅 | 2025-02-25 | 楂� | 3,200,000 |
+| SO20250201004 | NEV-Charger-D | 150 | 灏忛箯姹借溅 | 2025-03-01 | 涓� | 1,200,000 |
+
+### 鐢熶骇宸ュ崟鏁版嵁 (ERP绯荤粺)
+
+| 宸ュ崟鍙� | 浜у搧鍨嬪彿 | 璁″垝鏁伴噺 | 宸插畬鎴愭暟閲� | 鐢熶骇鐘舵�� | 棰勮瀹屾垚鏃堕棿 | 鐢熶骇绾� |
+| :--: | :--: | :--: | :--: | :--: | :--: | :--: |
+| WO20250201001 | NEV-Battery-A | 600 | 350 | 杩涜涓� | 2025-02-12 | 浜х嚎1 |
+| WO20250201002 | NEV-Motor-B | 250 | 180 | 杩涜涓� | 2025-02-18 | 浜х嚎2 |
+| WO20250201003 | NEV-Controller-C | 200 | 50 | 璁″垝涓� | 2025-02-22 | 浜х嚎3 |
+| WO20250201004 | NEV-Charger-D | 100 | 0 | 寰呮帓浜� | 2025-02-28 | 浜х嚎4 |
+
+### 搴撳瓨鏁版嵁 (WMS绯荤粺)
+
+| 鐗╂枡缂栫爜 | 鐗╂枡鍚嶇О | 褰撳墠搴撳瓨 | 瀹夊叏搴撳瓨 | 鍦ㄩ�旀暟閲� | 棰勮鍒拌揣鏃堕棿 | 搴撲綅 |
+| :--: | :--: | :--: | :--: | :--: | :--: | :--: |
+| MAT001 | 閿傜數姹犺姱 | 1,200 | 500 | 800 | 2025-02-10 | A鍖�-01 |
+| MAT002 | 鐢垫満瀹氬瓙 | 350 | 200 | 150 | 2025-02-12 | B鍖�-02 |
+| MAT003 | 鎺у埗鑺墖 | 180 | 100 | 200 | 2025-02-15 | C鍖�-03 |
+| MAT004 | 鍏呯數妯″潡 | 95 | 50 | 100 | 2025-02-18 | D鍖�-04 |
+
+### 渚涘簲鍟嗙哗鏁堟暟鎹�
+
+| 渚涘簲鍟嗗悕绉� | 渚涘簲鐗╂枡 | 鎸夋椂浜や粯鐜� | 璐ㄩ噺鍚堟牸鐜� | 浠锋牸绔炰簤鍔� | 椋庨櫓绛夌骇 |
+| :--: | :--: | :--: | :--: | :--: | :--: |
+| 瀹佸痉鏃朵唬 | 閿傜數姹犺姱 | 95% | 99.5% | 楂� | 浣� |
+| 姹囧窛鎶�鏈� | 鐢垫満瀹氬瓙 | 88% | 98.2% | 涓� | 涓� |
+| 鍦板钩绾� | 鎺у埗鑺墖 | 92% | 99.8% | 涓� | 浣� |
+| 鐗规潵鐢� | 鍏呯數妯″潡 | 85% | 97.5% | 楂� | 涓� |
+
+### 浜ц兘鏁版嵁
+
+| 鐢熶骇绾� | 鏃ヤ骇鑳� | 褰撳墠鍒╃敤鐜� | 鐡堕宸ュ簭 | 鍙皟閰嶄骇鑳� | 缁存姢璁″垝 |
+| :--: | :--: | :--: | :--: | :--: | :--: |
+| 浜х嚎1 | 50鍙� | 85% | 缁勮 | 10鍙� | 2025-02-20 |
+| 浜х嚎2 | 30鍙� | 75% | 娴嬭瘯 | 8鍙� | 2025-02-25 |
+| 浜х嚎3 | 40鍙� | 60% | 鐒婃帴 | 15鍙� | 2025-03-01 |
+| 浜х嚎4 | 25鍙� | 45% | 鍖呰 | 12鍙� | 2025-03-05 |
+`
+  },
 ];
 
 export default function AISceneChatPage() {
@@ -219,14 +312,15 @@
 
 function AISceneChatContent() {
   const searchParams = useSearchParams();
-  const sceneId = searchParams.get('scene');
+  const sceneId = searchParams.get('scene') || searchParams.get('chatbotId');
   const router = useRouter();
   const [showDataPreview, setShowDataPreview] = useState(false);
   
   // 鏍规嵁URL鍙傛暟鎵惧埌瀵瑰簲鐨勫満鏅�
   const initialScene = defaultServices.find(s => s.chatbotId === sceneId) || defaultServices[0];
+  
   // 淇敼涓轰娇鐢ㄥ畬鏁寸殑鍦烘櫙鏁版嵁
-  const [services] = useState([defaultServices.find(s => s.chatbotId === sceneId) || defaultServices[0]]);
+  const [services] = useState([initialScene]);
   const [selectedScene, setSelectedScene] = useState(initialScene);
   const [iframeKey, setIframeKey] = useState(0);
   const [token, setToken] = useState<string | null>(null);
@@ -394,7 +488,8 @@
             {/* 鏁版嵁璇存槑 - 鍙湪琛ユ枡鍜屾彃鍗曞満鏅樉绀� */}
             {(selectedScene.chatbotId === 'JELkWpPLHQfRNhEH' || 
               selectedScene.chatbotId === 'RhMYLHI1SZNiX4kl' ||
-              selectedScene.chatbotId === 'zO9YQDEHdIApG9zC') && (
+              selectedScene.chatbotId === 'zO9YQDEHdIApG9zC' ||
+              selectedScene.chatbotId === 'SCPanoramaInsight') && (
               <>
                 <div className="bg-gray-50 rounded-lg p-4 border border-gray-100 hover:border-gray-200 transition-colors duration-300 shadow-sm">
                   <div className="flex items-center justify-between mb-2">
@@ -423,7 +518,8 @@
                   isOpen={showDataPreview}
                   onClose={() => setShowDataPreview(false)}
                   markdownContent={selectedScene.exampleData || ''}
-                  sceneType={selectedScene.chatbotId === 'JELkWpPLHQfRNhEH' ? 'buliao' : 'chadan'}
+                  sceneType={selectedScene.chatbotId === 'JELkWpPLHQfRNhEH' ? 'buliao' : 
+                           selectedScene.chatbotId === 'SCPanoramaInsight' ? 'panorama' : 'chadan'}
                 />
               </>
             )}
diff --git a/src/app/ai-scene/page.tsx b/src/app/ai-scene/page.tsx
index 0b7e8c8..acd47cf 100644
--- a/src/app/ai-scene/page.tsx
+++ b/src/app/ai-scene/page.tsx
@@ -200,6 +200,98 @@
 | S4 | 1004 | chenqinghonghs@163.com |
 | S5 | 1005 | 16673976114@163.com |
 `
+  },
+  {
+    title: '渚涘簲閾惧叏鏅礊瀵�',
+    description: '閫氳繃AI Agent涓嶢PS鐨勬繁搴﹀崗鍚岋紝灏嗘彃鍗曞搷搴斾粠"琚姩鏁戠伀"鍗囩骇涓�"棰勬祴-鍐崇瓥-鎵ц"涓変綅涓�浣撶殑鏅鸿兘杩愯惀妯″紡锛屽姪鍔涙柊鑳芥簮涓氬姟澧為暱銆�',
+    imageUrl: '/images/333.png',
+    chatbotId: 'SCPanoramaInsight',
+    background: `渚涘簲閾惧叏鏅礊瀵熺郴缁熸槸鏂颁竴浠f櫤鑳戒緵搴旈摼绠$悊骞冲彴鐨勬牳蹇冨紩鎿庛�傝AI绯荤粺鑳藉瑙e喅浼犵粺渚涘簲閾剧鐞嗕腑鐨勫洓澶у叧閿棶棰橈細
+
+**鐢熶骇璁″垝涓庝骇鑳藉奖鍝嶈瘎浼帮細**
+- 瀹炴椂鐩戞帶鐢熶骇绾跨姸鎬侊紝鍔ㄦ�佽瘎浼颁骇鑳藉埄鐢ㄧ巼
+- 鍩轰簬鍘嗗彶鏁版嵁鍜屽疄鏃惰鍗曪紝鏅鸿兘棰勬祴鐢熶骇鐡堕
+- 鑷姩璋冩暣鐢熶骇璁″垝锛屾渶澶у寲浜ц兘鍒╃敤鏁堢巼
+- 鎻愪緵澶氬満鏅敓浜ц鍒掑姣斿垎鏋愶紝杈呭姪鍐崇瓥鍒跺畾
+
+**渚涘簲鍗忓悓鑳藉姏璇勪及锛�**
+- 瀹炴椂杩借釜渚涘簲鍟嗕氦浠樼姸鎬侊紝璇勪及渚涘簲椋庨櫓
+- 鏅鸿兘鍒嗘瀽渚涘簲鍟嗙哗鏁堬紝鎻愪緵渚涘簲鍟嗕紭鍖栧缓璁�
+- 棰勬祴鍘熸潗鏂欓渶姹傦紝鎻愬墠鍚姩閲囪喘娴佺▼
+- 鏋勫缓渚涘簲閾剧綉缁滈煣鎬фā鍨嬶紝鎻愬崌鎶楅闄╄兘鍔�
+
+**浜や粯灞ョ害椋庨櫓璇勪及锛�**
+- 鍩轰簬璁㈠崟銆佸簱瀛樸�佺敓浜ц繘搴﹁繘琛岀患鍚堥闄╄瘎浼�
+- 鎻愬墠璇嗗埆娼滃湪寤舵湡椋庨櫓锛屽埗瀹氬簲瀵归妗�
+- 瀹炴椂璺熻釜浜や粯杩涘害锛岀‘淇濆鎴锋弧鎰忓害
+- 寤虹珛瀹㈡埛棰勬湡绠$悊鏈哄埗锛屾彁鍗囨湇鍔′綋楠�
+
+**鎴愭湰涓庤储鍔″奖鍝嶈瘎浼帮細**
+- 鍏ㄩ摼璺垚鏈拷韪紝绮剧‘璁$畻鍚勭幆鑺傛垚鏈瀯鎴�
+- 鍔ㄦ�佹垚鏈紭鍖栧缓璁紝闄嶄綆鏁翠綋杩愯惀鎴愭湰
+- 璐㈠姟褰卞搷棰勬祴鍒嗘瀽锛屾敮鎸佸晢涓氬喅绛�
+- ROI璇勪及妯″瀷锛岄噺鍖栨敼杩涙帾鏂界殑璐㈠姟鏁堢泭`,
+    instructions: `鎮ㄥ彲浠ラ�氳繃浠ヤ笅鏂瑰紡涓庝緵搴旈摼鍏ㄦ櫙娲炲療绯荤粺浜掑姩锛�
+
+**鍦烘櫙涓�锛氭彃鍗曞奖鍝嶅垎鏋�**
+鎻愪緵鏂拌鍗曚俊鎭紝绯荤粺灏嗕粠鍥涗釜缁村害璇勪及鎻掑崟鍙鎬у拰褰卞搷銆�
+
+**鍦烘櫙浜岋細鐢熶骇璁″垝浼樺寲**
+鎻忚堪褰撳墠鐢熶骇鐘跺喌锛岃幏鍙栨櫤鑳戒紭鍖栧缓璁拰椋庨櫓棰勮銆�
+
+**鍦烘櫙涓夛細渚涘簲閾鹃闄╄瘎浼�**
+杈撳叆渚涘簲鍟嗘垨鍘熸潗鏂欎俊鎭紝鑾峰彇渚涘簲椋庨櫓鍒嗘瀽鍜屽簲瀵圭瓥鐣ャ��
+
+**鍦烘櫙鍥涳細鎴愭湰浼樺寲鍒嗘瀽**
+鎻愪緵鎴愭湰鐩稿叧鏁版嵁锛岃幏鍙栨垚鏈紭鍖栧缓璁拰璐㈠姟褰卞搷璇勪及銆�
+
+绯荤粺灏嗗熀浜庡疄鏃舵暟鎹拰AI绠楁硶锛屼负鎮ㄦ彁渚涗笓涓氱殑鍒嗘瀽鎶ュ憡鍜屽喅绛栧缓璁�俙,
+    exampleData: `
+### 璁㈠崟闇�姹傛暟鎹� (OMS绯荤粺)
+
+| 璁㈠崟鍙� | 浜у搧鍨嬪彿 | 鏁伴噺 | 瀹㈡埛鍚嶇О | 棰勬湡浜や粯鏃ユ湡 | 浼樺厛绾� | 璁㈠崟閲戦 |
+| :--: | :--: | :--: | :--: | :--: | :--: | :--: |
+| SO20250201001 | NEV-Battery-A | 500 | 姣斾簹杩� | 2025-02-15 | 楂� | 2,500,000 |
+| SO20250201002 | NEV-Motor-B | 200 | 钄氭潵姹借溅 | 2025-02-20 | 涓� | 1,800,000 |
+| SO20250201003 | NEV-Controller-C | 300 | 鐞嗘兂姹借溅 | 2025-02-25 | 楂� | 3,200,000 |
+| SO20250201004 | NEV-Charger-D | 150 | 灏忛箯姹借溅 | 2025-03-01 | 涓� | 1,200,000 |
+
+### 鐢熶骇宸ュ崟鏁版嵁 (ERP绯荤粺)
+
+| 宸ュ崟鍙� | 浜у搧鍨嬪彿 | 璁″垝鏁伴噺 | 宸插畬鎴愭暟閲� | 鐢熶骇鐘舵�� | 棰勮瀹屾垚鏃堕棿 | 鐢熶骇绾� |
+| :--: | :--: | :--: | :--: | :--: | :--: | :--: |
+| WO20250201001 | NEV-Battery-A | 600 | 350 | 杩涜涓� | 2025-02-12 | 浜х嚎1 |
+| WO20250201002 | NEV-Motor-B | 250 | 180 | 杩涜涓� | 2025-02-18 | 浜х嚎2 |
+| WO20250201003 | NEV-Controller-C | 200 | 50 | 璁″垝涓� | 2025-02-22 | 浜х嚎3 |
+| WO20250201004 | NEV-Charger-D | 100 | 0 | 寰呮帓浜� | 2025-02-28 | 浜х嚎4 |
+
+### 搴撳瓨鏁版嵁 (WMS绯荤粺)
+
+| 鐗╂枡缂栫爜 | 鐗╂枡鍚嶇О | 褰撳墠搴撳瓨 | 瀹夊叏搴撳瓨 | 鍦ㄩ�旀暟閲� | 棰勮鍒拌揣鏃堕棿 | 搴撲綅 |
+| :--: | :--: | :--: | :--: | :--: | :--: | :--: |
+| MAT001 | 閿傜數姹犺姱 | 1,200 | 500 | 800 | 2025-02-10 | A鍖�-01 |
+| MAT002 | 鐢垫満瀹氬瓙 | 350 | 200 | 150 | 2025-02-12 | B鍖�-02 |
+| MAT003 | 鎺у埗鑺墖 | 180 | 100 | 200 | 2025-02-15 | C鍖�-03 |
+| MAT004 | 鍏呯數妯″潡 | 95 | 50 | 100 | 2025-02-18 | D鍖�-04 |
+
+### 渚涘簲鍟嗙哗鏁堟暟鎹�
+
+| 渚涘簲鍟嗗悕绉� | 渚涘簲鐗╂枡 | 鎸夋椂浜や粯鐜� | 璐ㄩ噺鍚堟牸鐜� | 浠锋牸绔炰簤鍔� | 椋庨櫓绛夌骇 |
+| :--: | :--: | :--: | :--: | :--: | :--: |
+| 瀹佸痉鏃朵唬 | 閿傜數姹犺姱 | 95% | 99.5% | 楂� | 浣� |
+| 姹囧窛鎶�鏈� | 鐢垫満瀹氬瓙 | 88% | 98.2% | 涓� | 涓� |
+| 鍦板钩绾� | 鎺у埗鑺墖 | 92% | 99.8% | 涓� | 浣� |
+| 鐗规潵鐢� | 鍏呯數妯″潡 | 85% | 97.5% | 楂� | 涓� |
+
+### 浜ц兘鏁版嵁
+
+| 鐢熶骇绾� | 鏃ヤ骇鑳� | 褰撳墠鍒╃敤鐜� | 鐡堕宸ュ簭 | 鍙皟閰嶄骇鑳� | 缁存姢璁″垝 |
+| :--: | :--: | :--: | :--: | :--: | :--: |
+| 浜х嚎1 | 50鍙� | 85% | 缁勮 | 10鍙� | 2025-02-20 |
+| 浜х嚎2 | 30鍙� | 75% | 娴嬭瘯 | 8鍙� | 2025-02-25 |
+| 浜х嚎3 | 40鍙� | 60% | 鐒婃帴 | 15鍙� | 2025-03-01 |
+| 浜х嚎4 | 25鍙� | 45% | 鍖呰 | 12鍙� | 2025-03-05 |
+`
   }
 ];
 
diff --git a/src/app/supply-chain-chat/page.tsx b/src/app/supply-chain-chat/page.tsx
new file mode 100644
index 0000000..567c1b6
--- /dev/null
+++ b/src/app/supply-chain-chat/page.tsx
@@ -0,0 +1,1207 @@
+'use client';
+
+import { useState, useEffect, useRef, useCallback, useContext, createContext } from 'react';
+import Link from 'next/link';
+import { useRouter, useSearchParams } from 'next/navigation';
+import Image from 'next/image';
+import ReactMarkdown from 'react-markdown';
+import remarkGfm from 'remark-gfm';
+import rehypeRaw from 'rehype-raw';
+import rehypeSanitize from 'rehype-sanitize';
+import dynamic from 'next/dynamic';
+import { ReactNode } from 'react';
+
+// 鍒涘缓涓�涓秷鎭畬鎴愮姸鎬佺殑Context
+const MessageCompletionContext = createContext<boolean>(true);
+
+// 鍔ㄦ�佸鍏� ECharts锛岀‘淇濆畠鍙湪瀹㈡埛绔覆鏌�
+const ReactECharts = dynamic(() => import('echarts-for-react'), { ssr: false });
+
+interface Message {
+  role: 'user' | 'assistant';
+  content: string | null;
+  timestamp: number;
+  id: string;
+  conversation_id?: string;
+  feedback?: 'like' | 'dislike' | null;
+  metadata?: {
+    usage?: {
+      prompt_tokens: number;
+      completion_tokens: number;
+      total_tokens: number;
+      total_price: string;
+    };
+  };
+}
+
+const BASE_URL = 'http://121.43.139.99:7000';
+
+// 榛樿鐢ㄦ埛澶村儚
+const DEFAULT_USER_AVATAR = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23999999'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z'/%3E%3C/svg%3E";
+const AI_AVATAR = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%234F46E5'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 1c4.96 0 9 4.04 9 9s-4.04 9-9 9-9-4.04-9-9 4.04-9 9-9zm0 3.5c-2.48 0-4.5 2.02-4.5 4.5h1.5c0-1.66 1.34-3 3-3s3 1.34 3 3h1.5c0-2.48-2.02-4.5-4.5-4.5zM8 13h2v2H8v-2zm6 0h2v2h-2v-2z'/%3E%3C/svg%3E";
+
+// 娣诲姞鐢ㄤ簬瑙f瀽鍜屾覆鏌� ECharts 鐨勭粍浠�
+function EchartsRenderer({ code }: { code: string }) {
+  const [error, setError] = useState<string | null>(null);
+  const [isLoading, setIsLoading] = useState(true);
+  const [isModalOpen, setIsModalOpen] = useState(false);
+  const chartContainerRef = useRef<HTMLDivElement>(null);
+  const modalChartRef = useRef<HTMLDivElement>(null);
+  const hasRenderedRef = useRef<boolean>(false);
+  const chartInstanceRef = useRef<any>(null);
+  
+  // 鍒濆鍖朌OM瀹瑰櫒 - 鎻愬墠璁剧疆鍥哄畾楂樺害
+  useEffect(() => {
+    // 纭繚瀹瑰櫒鍑嗗濂戒簡骞朵笖鏈夌‘瀹氱殑楂樺害
+    if (chartContainerRef.current) {
+      // 璁剧疆涓�涓浐瀹氱殑楂樺害锛岄伩鍏嶆覆鏌撳悗鍙樺寲
+      const container = chartContainerRef.current;
+      container.style.width = '100%';
+      container.style.height = '400px'; // 鍥哄畾楂樺害400px
+      container.style.minHeight = '400px'; // 闃叉楂樺害鍙樺皬
+      
+      // 娣诲姞涓存椂鍐呭锛岀‘淇滵OM娓叉煋瀹屾垚
+      container.innerHTML = '<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:#f5f7f9;"><span>姝e湪鍑嗗鍥捐〃...</span></div>';
+    }
+  }, []);
+  
+  // 涓�娆℃�у姞杞藉浘琛紝涓嶈繘琛屽姩鎬佹洿鏂�
+  useEffect(() => {
+    // 濡傛灉宸茬粡娓叉煋杩囷紝璺宠繃
+    if (hasRenderedRef.current) {
+      return;
+    }
+    
+    setIsLoading(true);
+    
+    // 纭繚DOM鍏冪礌宸茬粡瀹屽叏鎸傝浇鍜屾覆鏌�
+    const timer = setTimeout(() => {
+      // 纭繚DOM鍏冪礌浠嶇劧瀛樺湪
+      if (!chartContainerRef.current) {
+        console.error('鍥捐〃瀹瑰櫒涓嶅瓨鍦紝璺宠繃鍒濆鍖�');
+        setIsLoading(false);
+        return;
+      }
+      
+      // 娓呴櫎涓存椂鍐呭
+      chartContainerRef.current.innerHTML = '';
+      
+      // 鏍囪涓哄凡娓叉煋
+      hasRenderedRef.current = true;
+      
+      // 鍒濆鍖栧浘琛�
+      const initializeChart = async () => {
+        try {
+          const echarts = await import('echarts');
+          
+          // 鍒濆鍖栧浘琛�
+          const chartInstance = echarts.init(chartContainerRef.current);
+          chartInstanceRef.current = chartInstance;
+          
+          // 灏濊瘯瑙f瀽鍜岃缃浘琛ㄩ�夐」
+          try {
+            const safeCode = code.replace(/window\.option/g, 'option');
+            const safeFunc = new Function(`
+              "use strict";
+              let option;
+              try {
+                ${safeCode}
+                return option;
+              } catch (e) {
+                console.error("鍥捐〃浠g爜鎵ц閿欒:", e);
+                return null;
+              }
+            `);
+            
+            const chartOption = safeFunc();
+            
+            if (chartOption) {
+              // 绂佺敤鍔ㄧ敾锛岄伩鍏嶆覆鏌撴椂鐨勫竷灞�鍙樺寲
+              chartOption.animation = false;
+              
+              // 淇敼tooltip閰嶇疆锛岀‘淇濇樉绀哄湪閫傚綋浣嶇疆
+              if (chartOption.tooltip) {
+                chartOption.tooltip = {
+                  ...chartOption.tooltip,
+                  confine: false, // 涓嶉檺鍒跺湪鍥捐〃鍖哄煙鍐�
+                  extraCssText: 'z-index:9999; pointer-events:auto; margin-top:0;'
+                };
+              }
+              
+              chartInstance.setOption(chartOption);
+              setError(null);
+            } else {
+              throw new Error("鏃犳硶鑾峰彇鍥捐〃閰嶇疆");
+            }
+          } catch (e) {
+            console.error('鍥捐〃浠g爜鎵ц閿欒:', e);
+            setError('鍥捐〃閰嶇疆閿欒');
+            
+            // 璁剧疆涓�涓粯璁ゅ浘琛ㄤ互鏄剧ず閿欒
+            chartInstance.setOption({
+              title: { text: '鍥捐〃閰嶇疆閿欒' },
+              xAxis: { type: 'category', data: ['閿欒'] },
+              yAxis: { type: 'value' },
+              series: [{ data: [0], type: 'bar' }]
+            });
+          }
+          
+          // 娣诲姞绐楀彛澶у皬鍙樺寲鐩戝惉鍣�
+          const handleResize = () => chartInstance.resize();
+          window.addEventListener('resize', handleResize);
+          
+          // 娓呯悊鍑芥暟
+          return () => {
+            window.removeEventListener('resize', handleResize);
+            chartInstance.dispose();
+          };
+        } catch (e) {
+          console.error('ECharts鍔犺浇澶辫触:', e);
+          setError('鍥捐〃搴撳姞杞藉け璐�');
+        } finally {
+          setIsLoading(false);
+        }
+      };
+      
+      initializeChart();
+    }, 500); // 澧炲姞寤惰繜锛岀‘淇滵OM瀹屽叏娓叉煋
+    
+    return () => clearTimeout(timer);
+  }, [code]);
+  
+  // 褰撳叏灞忕姸鎬佸彉鍖栨椂閲嶆柊璋冩暣鍥捐〃澶у皬
+  useEffect(() => {
+    if (chartInstanceRef.current) {
+      setTimeout(() => {
+        chartInstanceRef.current.resize();
+      }, 300); // 缁橠OM涓�浜涙椂闂存潵鏇存柊
+    }
+  }, [isModalOpen]);
+  
+  // 澶勭悊鍏ㄥ睆鍒囨崲
+  const toggleModal = useCallback(() => {
+    setIsModalOpen(prev => !prev);
+  }, []);
+
+  // 澶勭悊妯℃�佺獥鍙g殑鍥捐〃
+  useEffect(() => {
+    if (!isModalOpen || !modalChartRef.current) return;
+    
+    const initModalChart = async () => {
+      try {
+        const echarts = await import('echarts');
+        
+        // 鍒濆鍖栨ā鎬佺獥鍙d腑鐨勫浘琛�
+        const modalChartInstance = echarts.init(modalChartRef.current);
+        
+        // 濡傛灉涓诲浘琛ㄥ凡缁忓垵濮嬪寲锛屽鐢ㄥ叾閰嶇疆
+        if (chartInstanceRef.current) {
+          const option = chartInstanceRef.current.getOption();
+          
+          // 閲嶆柊璁剧疆鍥捐〃閰嶇疆锛岀‘淇濆湪鏂板鍣ㄤ腑姝g‘鏄剧ず
+          modalChartInstance.setOption(option);
+          
+          // 鐩戝惉绐楀彛澶у皬鍙樺寲
+          const handleResize = () => modalChartInstance.resize();
+          window.addEventListener('resize', handleResize);
+          
+          // 娓呯悊鍑芥暟
+          return () => {
+            window.removeEventListener('resize', handleResize);
+            modalChartInstance.dispose();
+          };
+        }
+      } catch (e) {
+        console.error('妯℃�佸浘琛ㄥ垵濮嬪寲澶辫触:', e);
+      }
+    };
+    
+    initModalChart();
+  }, [isModalOpen]);
+
+  return (
+    <>
+      <div className="w-full bg-gray-50 rounded-lg overflow-hidden border border-gray-200">
+        {/* 鍥捐〃宸ュ叿鏍� */}
+        <div className="bg-white px-4 py-2 border-b border-gray-200 flex justify-between items-center">
+          <span className="text-sm font-medium text-gray-700">鏁版嵁鍥捐〃</span>
+          <div className="flex items-center space-x-2">
+            {error && (
+              <span className="text-xs text-red-500">{error}</span>
+            )}
+            <button 
+              onClick={toggleModal}
+              className="p-1 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded transition-colors"
+              title="鍏ㄥ睆鏌ョ湅"
+            >
+              <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" />
+              </svg>
+            </button>
+          </div>
+        </div>
+        
+        {/* 鍥捐〃瀹瑰櫒 */}
+        <div className="relative">
+          <div 
+            ref={chartContainerRef}
+            className="w-full"
+            style={{ height: '400px', minHeight: '400px' }}
+          />
+          {isLoading && (
+            <div className="absolute inset-0 flex items-center justify-center bg-gray-50/80">
+              <div className="flex items-center space-x-2 text-gray-500">
+                <div className="animate-spin rounded-full h-4 w-4 border-2 border-blue-500 border-t-transparent"></div>
+                <span className="text-sm">鍔犺浇涓�...</span>
+              </div>
+            </div>
+          )}
+        </div>
+      </div>
+
+      {/* 鍏ㄥ睆妯℃�佺獥鍙� */}
+      {isModalOpen && (
+        <div className="fixed inset-0 bg-black bg-opacity-80 z-50 flex items-center justify-center p-4">
+          <div className="bg-white rounded-lg w-full h-full max-w-6xl max-h-[90vh] flex flex-col">
+            {/* 妯℃�佺獥鍙eご閮� */}
+            <div className="flex justify-between items-center p-4 border-b border-gray-200">
+              <h3 className="text-lg font-semibold text-gray-900">鍥捐〃璇︾粏瑙嗗浘</h3>
+              <button 
+                onClick={toggleModal}
+                className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-full transition-colors"
+              >
+                <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
+                </svg>
+              </button>
+            </div>
+            
+            {/* 妯℃�佺獥鍙e浘琛ㄥ鍣� */}
+            <div className="flex-1 p-4">
+              <div 
+                ref={modalChartRef}
+                className="w-full h-full"
+              />
+            </div>
+          </div>
+        </div>
+      )}
+    </>
+  );
+}
+
+function CodeBlockRenderer({ language, value }: { language: string; value: string }) {
+  // 妫�鏌ユ槸鍚︽槸 ECharts 浠g爜
+  if (language === 'echarts' || language === 'javascript' && value.includes('option')) {
+    return <EchartsRenderer code={value} />;
+  }
+  
+  return (
+    <div className="relative bg-gray-50 rounded-lg overflow-hidden border border-gray-200">
+      <div className="bg-white px-4 py-2 border-b border-gray-200 flex justify-between items-center">
+        <span className="text-sm font-medium text-gray-700">{language || '浠g爜'}</span>
+        <button 
+          onClick={() => navigator.clipboard.writeText(value)}
+          className="p-1 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded transition-colors"
+          title="澶嶅埗浠g爜"
+        >
+          <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
+          </svg>
+        </button>
+      </div>
+      <pre className="p-4 overflow-x-auto">
+        <code className={`language-${language}`}>
+          {value}
+        </code>
+      </pre>
+    </div>
+  );
+}
+
+interface ChatInputProps {
+  onSendMessage: () => void;
+  isStreaming: boolean;
+  isMessageComplete: boolean;
+}
+
+function ChatInput({ onSendMessage, isStreaming, isMessageComplete }: ChatInputProps) {
+  // 鍐呴儴鐘舵�侊紝涓庡閮ㄥ畬鍏ㄩ殧绂�
+  const [inputText, setInputText] = useState('');
+  const inputRef = useRef<HTMLTextAreaElement>(null);
+  
+  // 澶勭悊杈撳叆鍙樺寲
+  const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
+    setInputText(e.target.value);
+  };
+  
+  // 澶勭悊鎸夐敭浜嬩欢
+  const handleKeyDown = (e: React.KeyboardEvent) => {
+    if (e.key === 'Enter' && !e.shiftKey) {
+      e.preventDefault();
+      handleSend();
+    }
+  };
+  
+  // 澶勭悊鍙戦��
+  const handleSend = () => {
+    if (isStreaming || !inputText.trim() || !isMessageComplete) return;
+    
+    // 閫氱煡鐖剁粍浠跺彂閫佹秷鎭墠鏇存柊娑堟伅鍐呭
+    (window as any).messageToSend = inputText.trim();
+    
+    // 娓呯┖杈撳叆
+    setInputText('');
+    
+    // 璋冪敤鐖剁粍浠剁殑鍙戦�佹柟娉�
+    onSendMessage();
+  };
+  
+  return (
+    <div className="fixed bottom-0 left-0 right-0 bg-gradient-to-t from-white via-white to-white/95 pt-4 pb-6" style={{ zIndex: 50 }}>
+      <div className="max-w-4xl mx-auto px-6">
+        <div className="relative">
+          <div className="absolute -top-6 left-1/2 -translate-x-1/2 w-48 h-[1px] bg-gradient-to-r from-transparent via-gray-200 to-transparent"></div>
+          
+          <div className="flex gap-4 items-start">
+            <div className="flex-1 relative">
+              <textarea
+                ref={inputRef}
+                value={inputText}
+                onChange={handleInputChange}
+                onKeyDown={handleKeyDown}
+                placeholder="璇锋弿杩版偍鐨勪緵搴旈摼鍦烘櫙鎴栨彁鍑洪棶棰�..."
+                disabled={isStreaming}
+                className="w-full resize-none rounded-xl border-0 bg-gray-50 px-4 py-3 text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-100/50 focus:bg-white min-h-[48px] max-h-32 shadow-inner transition-all duration-300 ease-in-out hover:bg-gray-100/70 disabled:opacity-50 disabled:cursor-not-allowed"
+                style={{ height: '48px' }}
+              />
+              <div className="absolute right-4 bottom-2 text-xs text-gray-400 bg-gray-50 px-2">
+                鎸塃nter鍙戦�侊紝Shift+Enter鎹㈣
+              </div>
+            </div>
+            <button
+              onClick={handleSend}
+              disabled={isStreaming || !inputText.trim() || !isMessageComplete}
+              className="h-12 px-5 bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white font-medium rounded-xl transition-all duration-300 flex items-center gap-2 shadow-lg shadow-blue-500/20 hover:shadow-blue-500/30 hover:scale-[1.02] active:scale-[0.98] disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none disabled:shadow-none cursor-pointer"
+            >
+              <span>{isStreaming ? '鍥炲涓�...' : (isMessageComplete ? '鍙戦��' : '澶勭悊涓�...')}</span>
+              <svg xmlns="http://www.w3.org/2000/svg" className={`h-4 w-4 transform rotate-45 ${isStreaming ? 'animate-pulse' : ''}`} viewBox="0 0 20 20" fill="currentColor">
+                <path d="M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z" />
+              </svg>
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
+
+export default function SupplyChainChatPage() {
+  const router = useRouter();
+  const searchParams = useSearchParams();
+  const [apiKey, setApiKey] = useState<string>('');
+  const [message, setMessage] = useState('');
+  const [messages, setMessages] = useState<Message[]>([]);
+  const [isStreaming, setIsStreaming] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+  const [showError, setShowError] = useState(false);
+  const [conversationId, setConversationId] = useState<string | null>(null);
+  const [isMessageComplete, setIsMessageComplete] = useState(true);
+  const [currentMessageId, setCurrentMessageId] = useState<string | null>(null);
+  
+  // 娣诲姞涓�涓柊鐨勭姸鎬佹潵鎺у埗娑堟伅鐨勬樉绀�
+  const [showMessages, setShowMessages] = useState(false);
+
+  // 鍦ㄧ粍浠堕《閮ㄥ鍔犱竴涓己鍒舵洿鏂拌鏁板櫒
+  const [forceUpdateCounter, setForceUpdateCounter] = useState(0);
+
+  // 娣诲姞鐘舵�佹潵鎺у埗鎬濊�冨唴瀹圭殑鏄剧ず/闅愯棌
+  const [expandedThinkMessages, setExpandedThinkMessages] = useState<Record<string, boolean>>({});
+
+  // 娣诲姞API瀵嗛挜鍔犺浇鐘舵��
+  const [isLoadingApiKey, setIsLoadingApiKey] = useState(false);
+
+  // 鑾峰彇URL鍙傛暟
+  const keyParam = searchParams.get('key');
+
+  const messagesEndRef = useRef<HTMLDivElement>(null);
+  const errorTimeoutRef = useRef<any>(null);
+
+  // 鍦ㄧ粍浠堕《閮ㄦ坊鍔犱竴涓紩鐢紝鐢ㄤ簬璺熻釜缁勪欢鏄惁宸插嵏杞�
+  const isMountedRef = useRef(true);
+
+  // 鍒嗙娑堟伅杈撳叆鐘舵�侊紝閬垮厤瑙﹀彂涓嶅繀瑕佺殑閲嶆覆鏌�
+  const messageInputRef = useRef<HTMLTextAreaElement>(null);
+  const [localMessage, setLocalMessage] = useState('');
+
+  // 娣诲姞鑾峰彇API瀵嗛挜鐨勫嚱鏁�
+  const fetchApiKey = async () => {
+    setIsLoadingApiKey(true);
+    try {
+      const response = await fetch('http://121.43.139.99:8080/api/secret-key', {
+        method: 'GET',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+      });
+
+      if (!response.ok) {
+        throw new Error(`鑾峰彇瀵嗛挜澶辫触: HTTP ${response.status}`);
+      }
+
+      const result = await response.json();
+      console.log('API鍝嶅簲:', result);
+      
+      // 鎸夌収鎺ュ彛鏂囨。鏍煎紡瑙f瀽鍝嶅簲
+      if (result.code === 200 && result.data && result.data.key) {
+        const apiKeyValue = result.data.key;
+        setApiKey(apiKeyValue);
+        setError(null);
+        console.log('鎴愬姛鑾峰彇API瀵嗛挜:', apiKeyValue);
+        return apiKeyValue;
+      } else {
+        throw new Error(result.message || '鑾峰彇瀵嗛挜澶辫触锛氬搷搴旀牸寮忎笉姝g‘');
+      }
+    } catch (err) {
+      console.error('鑾峰彇API瀵嗛挜澶辫触:', err);
+      const errorMessage = err instanceof Error ? err.message : '鑾峰彇瀵嗛挜鏃跺彂鐢熸湭鐭ラ敊璇�';
+      showErrorMessage(`瀵嗛挜鑾峰彇澶辫触: ${errorMessage}`);
+      return null;
+    } finally {
+      setIsLoadingApiKey(false);
+    }
+  };
+
+  const handleMessageChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
+    // 鍙洿鏂版湰鍦扮姸鎬侊紝涓嶈Е鍙戝叏灞�閲嶆覆鏌�
+    setLocalMessage(e.target.value);
+  };
+
+  // 浠呭湪鍙戦�佹椂鏇存柊鍏ㄥ眬娑堟伅鐘舵��
+  const handleKeyPress = (e: React.KeyboardEvent) => {
+    if (e.key === 'Enter' && !e.shiftKey) {
+      e.preventDefault();
+      // 鏇存柊鍏ㄥ眬鐘舵�佸苟鍙戦��
+      setMessage(localMessage);
+      setTimeout(() => handleSendMessage(), 10);
+    }
+  };
+
+  // 鐐瑰嚮鍙戦�佹寜閽椂
+  const handleSendButtonClick = () => {
+    // 妫�鏌ユ秷鎭槸鍚︿负绌�
+    if (!localMessage.trim() || !isMessageComplete) return;
+    
+    // 鏇存柊鍏ㄥ眬鐘舵�佸苟鍙戦��
+    setMessage(localMessage);
+    setTimeout(() => handleSendMessage(), 10);
+  };
+
+  // 鍚屾娑堟伅鐘舵�佸埌鏈湴鐘舵��
+  useEffect(() => {
+    setLocalMessage(message);
+  }, [message]);
+
+  useEffect(() => {
+    // 缁勪欢鍔犺浇鏃朵粠API鑾峰彇瀵嗛挜
+    const initializeApiKey = async () => {
+      await fetchApiKey();
+    };
+
+    initializeApiKey();
+  }, []);
+
+  useEffect(() => {
+    // 婊氬姩鍒版渶鏂版秷鎭�
+    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
+  }, [messages]);
+
+  // 澶勭悊閿欒鏄剧ず鍜岃嚜鍔ㄦ秷澶�
+  const showErrorMessage = useCallback((message: string) => {
+    setError(message);
+    // 鍏堣缃负false纭繚鍔ㄧ敾鑳介噸鏂拌Е鍙�
+    setShowError(false);
+    // 浣跨敤 requestAnimationFrame 纭繚鐘舵�佸彉鍖栬姝g‘娓叉煋
+    requestAnimationFrame(() => {
+      requestAnimationFrame(() => {
+        setShowError(true);
+      });
+    });
+
+    if (errorTimeoutRef.current) {
+      clearTimeout(errorTimeoutRef.current);
+    }
+
+    errorTimeoutRef.current = setTimeout(() => {
+      setShowError(false);
+      setTimeout(() => {
+        setError(null);
+      }, 400);
+    }, 3000);
+  }, []);
+
+  // 缁勪欢鍗歌浇鏃舵竻闄ゅ畾鏃跺櫒
+  useEffect(() => {
+    const cleanup = () => {
+      if (errorTimeoutRef.current) {
+        clearTimeout(errorTimeoutRef.current);
+      }
+    };
+    return cleanup;
+  }, []);
+
+  // 娣诲姞缁勪欢鍗歌浇鏃剁殑娓呯悊宸ヤ綔
+  useEffect(() => {
+    // 缁勪欢鎸傝浇鏃讹紝璁剧疆涓簍rue
+    isMountedRef.current = true;
+    
+    // 缁勪欢鍗歌浇鏃讹紝璁剧疆涓篺alse
+    return () => {
+      isMountedRef.current = false;
+      
+      // 娓呴櫎鎵�鏈夊畾鏃跺櫒
+      if (errorTimeoutRef.current) {
+        clearTimeout(errorTimeoutRef.current);
+      }
+    };
+  }, []);
+
+  const handleSendMessage = async () => {
+    // 浠巜indow瀵硅薄鑾峰彇娑堟伅鍐呭
+    const inputMessage = (window as any).messageToSend || '';
+    if (!inputMessage.trim() || !isMessageComplete) return;
+    
+    // 妫�鏌PI瀵嗛挜锛屽鏋滄病鏈夊垯灏濊瘯鑾峰彇
+    let currentApiKey = apiKey;
+    if (!currentApiKey) {
+      showErrorMessage('姝e湪鑾峰彇API瀵嗛挜...');
+      currentApiKey = await fetchApiKey();
+      if (!currentApiKey) {
+        showErrorMessage('鏃犳硶鑾峰彇API瀵嗛挜锛岃妫�鏌ョ綉缁滆繛鎺�');
+        return;
+      }
+    }
+
+    setIsStreaming(true);
+    setIsMessageComplete(false);
+
+    // 鍒涘缓鏂版秷鎭�
+    const userMessage: Message = {
+      role: 'user',
+      content: inputMessage.trim(),
+      timestamp: Date.now(),
+      id: 'user-' + Date.now().toString()
+    };
+
+    const assistantMessage: Message = {
+      role: 'assistant',
+      content: '',
+      timestamp: Date.now(),
+      id: 'temp-' + Date.now().toString()
+    };
+
+    // 浣跨敤鍑芥暟寮忔洿鏂扮‘淇濈姸鎬佹洿鏂扮殑涓�鑷存��
+    setMessages(prevMessages => {
+      const newMessages = [...prevMessages];
+      // 濡傛灉瀛樺湪鏈畬鎴愮殑鍔╂墜娑堟伅锛屽厛绉婚櫎瀹�
+      if (!isMessageComplete && currentMessageId) {
+        const lastMessage = newMessages[newMessages.length - 1];
+        if (lastMessage && lastMessage.role === 'assistant' && lastMessage.id === currentMessageId) {
+          newMessages.pop();
+        }
+      }
+      return [...newMessages, userMessage, assistantMessage];
+    });
+
+    setCurrentMessageId(assistantMessage.id);
+    setMessage('');
+    setShowMessages(true);
+
+    // 娓呴櫎杈撳叆鍐呭
+    (window as any).messageToSend = '';
+
+    let controller: AbortController | null = new AbortController();
+    
+    try {
+      const response = await fetch(`${BASE_URL}/v1/chat-messages`, {
+        method: 'POST',
+        headers: {
+          'Authorization': `Bearer ${currentApiKey}`,
+          'Content-Type': 'application/json',
+        },
+        mode: 'cors',
+        body: JSON.stringify({
+          inputs: {},
+          query: userMessage.content,
+          response_mode: 'streaming',
+          conversation_id: conversationId || '',
+          user: 'abc-123',
+          files: []
+        }),
+        signal: controller.signal // 娣诲姞涓淇″彿
+      });
+
+      console.log("API鍝嶅簲鐘舵��:", response.status, response.statusText);
+      
+      if (!response.ok) {
+        const errorText = await response.text();
+        console.error("API閿欒鍝嶅簲:", errorText);
+        let errorMessage;
+        try {
+          const errorJson = JSON.parse(errorText);
+          errorMessage = errorJson.error || `閿欒: ${response.status}`;
+        } catch {
+          errorMessage = `閿欒: ${response.status}`;
+        }
+        throw new Error(errorMessage);
+      }
+
+      // 纭繚response.body瀛樺湪
+      if (!response.body) {
+        throw new Error('鍝嶅簲娌℃湁鎻愪緵鏁版嵁娴�');
+      }
+
+      const reader = response.body.getReader();
+      const decoder = new TextDecoder();
+      let buffer = '';
+
+      while (true) {
+        try {
+          const { done, value } = await reader.read();
+          if (done) {
+            console.log("娴佸紡鍝嶅簲鎺ユ敹瀹屾瘯");
+            setIsMessageComplete(true);
+            break;
+          }
+
+          const chunk = decoder.decode(value, { stream: true });
+          console.log("鎺ユ敹鍒版暟鎹潡:", chunk);
+          buffer += chunk;
+          const lines = buffer.split('\n');
+          buffer = lines.pop() || '';
+
+          for (const line of lines) {
+            if (line.trim() === '') continue;
+            
+            console.log("澶勭悊琛屾暟鎹�:", line);
+            
+            if (line.startsWith('data: ')) {
+              try {
+                const jsonStr = line.slice(6);
+                console.log("瀹屾暣鍘熷鏁版嵁:", line);
+                console.log("瑙f瀽JSON瀛楃涓�:", jsonStr);
+                const data = JSON.parse(jsonStr);
+                console.log("瑙f瀽鍚庣殑鏁版嵁瀵硅薄:", data);
+                
+                // 蹇界暐ping浜嬩欢
+                if (data.event === 'ping') {
+                  console.log("蹇界暐ping浜嬩欢");
+                  continue;
+                }
+
+                switch (data.event) {
+                  case 'message':
+                    console.log(`鏀跺埌message浜嬩欢:`, data);
+                    
+                    // 鎻愬彇message鏁版嵁
+                    const messageId = data.message_id;
+                    const answerChunk = data.answer || '';
+                    const convId = data.conversation_id;
+                    
+                    // 濡傛灉涓嶅湪寰幆涓紝鐩存帴璋冪敤鏇存柊鍑芥暟
+                    handleMessageChunk(messageId, answerChunk, convId);
+                    break;
+
+                  case 'message_end':
+                    console.log('鏀跺埌message_end浜嬩欢:', data);
+                    
+                    // 妫�鏌ユ槸鍚︽湁鏈�缁堢瓟妗�
+                    if (data.metadata && data.id) {
+                      setIsMessageComplete(true);
+                      setConversationId(data.conversation_id || null);
+                    }
+                    break;
+                    
+                  case 'workflow_finished':
+                    console.log('宸ヤ綔娴佸畬鎴�:', data);
+                    
+                    // 妫�鏌ュ伐浣滄祦杈撳嚭鏄惁鏈夌瓟妗�
+                    if (data.data && data.data.outputs && data.data.outputs.answer) {
+                      // 濡傛灉宸ヤ綔娴佹湁鏈�缁堢瓟妗堬紝鏇存柊娑堟伅鍐呭
+                      const finalAnswer = data.data.outputs.answer;
+                      const messageId = data.message_id;
+                      
+                      if (finalAnswer) {
+                        console.log('浠庡伐浣滄祦鑾峰彇鏈�缁堢瓟妗�:', finalAnswer);
+                        handleFinalAnswer(messageId, finalAnswer, data.conversation_id);
+                      }
+                    }
+                    break;
+                    
+                  case 'node_finished':
+                    // 妫�鏌ヨ妭鐐圭被鍨嬫槸鍚︿负answer鑺傜偣
+                    if (data.data && data.data.node_type === 'answer' && data.data.outputs && data.data.outputs.answer) {
+                      console.log('浠巃nswer鑺傜偣鑾峰彇绛旀:', data.data.outputs.answer);
+                      const answer = data.data.outputs.answer;
+                      if (answer) {
+                        handleFinalAnswer(data.message_id, answer, data.conversation_id);
+                      }
+                    }
+                    break;
+                    
+                  // 澶勭悊鍏朵粬宸ヤ綔娴佷簨浠�
+                  case 'workflow_started':
+                  case 'node_started':
+                    // 杩欎簺浜嬩欢鍙渶璁板綍锛屼笉闇�瑕佹洿鏂癠I
+                    console.log(`宸ヤ綔娴佷簨浠� ${data.event}:`, data);
+                    break;
+                    
+                  case 'error':
+                    console.error('鏈嶅姟鍣ㄨ繑鍥為敊璇簨浠�:', data);
+                    setIsMessageComplete(true);
+                    throw new Error(data.message || '鍙戦�佹秷鎭椂鍑洪敊');
+                }
+              } catch (e) {
+                console.error('瑙f瀽SSE鏁版嵁鍑洪敊:', e, '鍘熷琛�:', line);
+                setIsMessageComplete(true);
+                throw e;
+              }
+            }
+          }
+        } catch (err) {
+          console.error('澶勭悊娴佸紡鍝嶅簲鏃跺嚭閿�:', err);
+          throw err;
+        }
+      }
+    } catch (err) {
+      // 妫�鏌ユ槸鍚︽槸涓閿欒
+      if (err instanceof Error && err.name === 'AbortError') {
+        console.log('璇锋眰琚腑姝紝鍙兘鏄粍浠跺嵏杞藉鑷寸殑');
+        return; // 涓閿欒涓嶉渶瑕佹樉绀虹粰鐢ㄦ埛
+      }
+      
+      console.error('鑱婂ぉ璇锋眰閿欒:', err);
+      let errorMsg = err instanceof Error ? err.message : '鍙戦�佹秷鎭椂鍑洪敊';
+      
+      // 鍙湁鍦ㄧ粍浠朵粛鐒舵寕杞芥椂鎵嶆洿鏂癠I
+      if (isMountedRef.current) {
+        showErrorMessage(errorMsg);
+        
+        setMessages(prev => {
+          const newMessages = [...prev];
+          const lastMessage = newMessages[newMessages.length - 1];
+          if (lastMessage?.role === 'assistant') {
+            lastMessage.content = `鎶辨瓑锛屾棤娉曡幏鍙栧洖澶�: ${errorMsg}`;
+          }
+          return newMessages;
+        });
+      }
+    } finally {
+      // 娓呴櫎鎺у埗鍣�
+      controller = null;
+      
+      // 鍙湁鍦ㄧ粍浠朵粛鐒舵寕杞芥椂鎵嶆洿鏂癠I
+      if (isMountedRef.current) {
+        setIsStreaming(false);
+        setIsMessageComplete(true);
+      }
+    }
+  };
+
+  // 淇敼handleMessageChunk鍑芥暟锛屾坊鍔犵粍浠舵寕杞芥鏌�
+  const handleMessageChunk = useCallback((messageId: string, answerChunk: string, convId?: string) => {
+    // 濡傛灉缁勪欢宸插嵏杞斤紝鍒欎笉鎵ц鏇存柊
+    if (!isMountedRef.current) return;
+    
+    console.log(`澶勭悊娑堟伅鐗囨: ID=${messageId}, 鐗囨="${answerChunk}"`);
+    
+    // 浣跨敤鍑芥暟寮忔洿鏂扮‘淇濊幏鍙栨渶鏂扮姸鎬�
+    setMessages(prevMessages => {
+      // 濡傛灉缁勪欢宸插嵏杞斤紝鍒欎笉鎵ц鏇存柊
+      if (!isMountedRef.current) return prevMessages;
+      
+      // 鍒涘缓娑堟伅鏁扮粍鐨勬嫹璐�
+      const newMessages = [...prevMessages];
+      
+      // 鏌ユ壘鏈�鍚庝竴鏉″姪鎵嬫秷鎭�
+      const lastMessage = newMessages[newMessages.length - 1];
+      if (lastMessage?.role !== 'assistant') {
+        console.warn('鎵句笉鍒板姪鎵嬫秷鎭潵鏇存柊');
+        return prevMessages; // 涓嶉渶瑕佹洿鏂�
+      }
+      
+      // 鏇存柊娑堟伅鍐呭鍜孖D
+      const updatedContent = (lastMessage.content || '') + answerChunk;
+      
+      // 鍒涘缓娑堟伅鐨勬柊鍓湰浠ョ‘淇漅eact妫�娴嬪埌鍙樺寲
+      const updatedMessage = {
+        ...lastMessage,
+        id: messageId,
+        content: updatedContent,
+        timestamp: Date.now()
+      };
+      
+      if (convId) {
+        updatedMessage.conversation_id = convId;
+      }
+      
+      // 鏇存柊褰撳墠姝e湪澶勭悊鐨勬秷鎭疘D
+      if (isMountedRef.current) {
+        setCurrentMessageId(messageId);
+      }
+      
+      // 鏇挎崲鏈�鍚庝竴鏉℃秷鎭�
+      newMessages[newMessages.length - 1] = updatedMessage;
+      
+      console.log(`鏇存柊鍚庣殑鍐呭闀垮害: ${updatedContent.length}`);
+      
+      // 瑙﹀彂寮哄埗鏇存柊
+      if (isMountedRef.current) {
+        setTimeout(() => {
+          if (isMountedRef.current) {
+            setForceUpdateCounter(count => count + 1);
+          }
+        }, 0);
+      }
+      
+      return newMessages;
+    });
+  }, []);
+
+  // 淇敼handleFinalAnswer鍑芥暟锛屾坊鍔犵粍浠舵寕杞芥鏌�
+  const handleFinalAnswer = useCallback((messageId: string, answer: string, convId?: string) => {
+    // 濡傛灉缁勪欢宸插嵏杞斤紝鍒欎笉鎵ц鏇存柊
+    if (!isMountedRef.current) return;
+    
+    console.log(`璁剧疆鏈�缁堢瓟妗�: ID=${messageId}, 鍐呭="${answer}"`);
+    
+    setMessages(prevMessages => {
+      // 濡傛灉缁勪欢宸插嵏杞斤紝鍒欎笉鎵ц鏇存柊
+      if (!isMountedRef.current) return prevMessages;
+      
+      const newMessages = [...prevMessages];
+      const lastMessage = newMessages[newMessages.length - 1];
+      
+      if (lastMessage?.role !== 'assistant') {
+        console.warn('鎵句笉鍒板姪鎵嬫秷鎭潵鏇存柊鏈�缁堢瓟妗�');
+        return prevMessages;
+      }
+      
+      // 鍒涘缓娑堟伅鐨勬柊鍓湰锛岃缃渶缁堢瓟妗�
+      const updatedMessage = {
+        ...lastMessage,
+        id: messageId,
+        content: answer,
+        timestamp: Date.now()
+      };
+      
+      if (convId) {
+        updatedMessage.conversation_id = convId;
+      }
+      
+      // 鏇存柊鐘舵��
+      if (isMountedRef.current) {
+        setIsMessageComplete(true);
+        setCurrentMessageId(messageId);
+      }
+      
+      // 鏇挎崲鏈�鍚庝竴鏉℃秷鎭�
+      newMessages[newMessages.length - 1] = updatedMessage;
+      
+      // 瑙﹀彂寮哄埗鏇存柊
+      if (isMountedRef.current) {
+        setTimeout(() => {
+          if (isMountedRef.current) {
+            setForceUpdateCounter(count => count + 1);
+          }
+        }, 0);
+      }
+      
+      return newMessages;
+    });
+  }, []);
+
+  const parseMessageContent = (content: string | null) => {
+    if (!content) return { mainContent: null, thinkContent: null };
+    
+    // 妫�鏌ユ槸鍚﹀寘鍚�濊�冨唴瀹�
+    const thinkMatch = content.match(/<think>([\s\S]*?)<\/think>/);
+    const thinkContent = thinkMatch ? thinkMatch[1].trim() : null;
+    const mainContent = content.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
+    
+    return { mainContent, thinkContent };
+  };
+
+  const toggleThinkContent = (messageId: string) => {
+    setExpandedThinkMessages(prev => ({
+      ...prev,
+      [messageId]: !prev[messageId]
+    }));
+  };
+
+  useEffect(() => {
+    // 椤甸潰鍔犺浇鍚庡欢杩熸樉绀烘秷鎭垪琛紝閬垮厤闂儊
+    const timer = setTimeout(() => {
+      setShowMessages(true);
+    }, 100);
+    return () => clearTimeout(timer);
+  }, []);
+
+  useEffect(() => {
+    return () => {
+      // 缁勪欢鍗歌浇鏃剁殑娓呯悊宸ヤ綔
+      console.log('渚涘簲閾捐亰澶╃粍浠跺嵏杞斤紝娓呯悊璧勬簮');
+    };
+  }, []);
+
+  return (
+    <div className="min-h-screen bg-gradient-to-b from-gray-50 to-white text-gray-900 flex flex-col">
+      {/* 椤堕儴瀵艰埅鏍� */}
+      <div className="fixed top-16 left-0 right-0 bg-white border-b border-gray-200 z-40">
+        <div className="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between">
+          <div className="flex items-center space-x-4">
+            <button
+              onClick={() => router.push('/ai-scene')}
+              className="group inline-flex items-center text-sm text-gray-500 hover:text-red-500 transition-all duration-300 cursor-pointer"
+            >
+              <svg 
+                xmlns="http://www.w3.org/2000/svg" 
+                className="h-4 w-4 transition-transform duration-300 group-hover:-translate-x-0.5" 
+                fill="none" 
+                viewBox="0 0 24 24" 
+                stroke="currentColor"
+              >
+                <path 
+                  strokeLinecap="round" 
+                  strokeLinejoin="round" 
+                  strokeWidth={2} 
+                  d="M10 19l-7-7m0 0l7-7m-7 7h18" 
+                />
+              </svg>
+              <span className="ml-1.5">杩斿洖</span>
+            </button>
+            <div className="h-4 w-px bg-gray-200"></div>
+            <h1 className="text-xl font-semibold text-gray-900">
+              渚涘簲閾惧叏鏅礊瀵�
+            </h1>
+          </div>
+          <div className="flex items-center space-x-4">
+            <div className="px-3 py-1 bg-green-100 text-green-700 text-sm rounded-full">
+              AI鏅鸿兘鍒嗘瀽
+            </div>
+            {keyParam && (
+              <div className="text-xs text-gray-500">
+                ID: {keyParam}
+              </div>
+            )}
+          </div>
+        </div>
+      </div>
+
+      {/* 閿欒鎻愮ず */}
+      {error && (
+        <div 
+          className={`fixed top-36 left-1/2 transform -translate-x-1/2 
+            flex items-center gap-2 px-4 py-2 text-sm text-white
+            transition-all duration-400 ease-out
+            ${showError 
+              ? 'opacity-100 translate-y-0 scale-100' 
+              : 'opacity-0 -translate-y-2 scale-95'
+            }
+            before:content-[''] before:absolute before:inset-0 before:bg-red-500 
+            before:rounded-lg before:opacity-90 before:-z-10
+            after:content-[''] after:absolute after:inset-0 after:bg-red-500/50
+            after:blur-md after:rounded-lg after:-z-20`}
+        >
+          <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
+            <path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
+          </svg>
+          <span className="relative">{error}</span>
+        </div>
+      )}
+
+      {/* 鑱婂ぉ鍖哄煙 */}
+      <div className="flex-1 flex flex-col h-screen">
+        <div className="flex-1 overflow-y-auto pt-36 pb-32">
+          <div className="max-w-4xl mx-auto px-6">
+            <div className={`space-y-6 ${showMessages ? 'opacity-100' : 'opacity-0'} transition-opacity duration-200`}>
+              {messages.length === 0 ? (
+                <div className="flex flex-col items-center justify-center h-[400px] text-center">
+                  <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4">
+                    <svg xmlns="http://www.w3.org/2000/svg" className="h-8 w-8 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                      <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2-2V7a2 2 0 012-2h2a2 2 0 002-2V3a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 002 2h2a2 2 0 012 2v2a2 2 0 00-2 2h-2a2 2 0 00-2 2v6a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
+                    </svg>
+                  </div>
+                  <h3 className="text-lg font-medium text-gray-900 mb-2">渚涘簲閾惧叏鏅礊瀵�</h3>
+                  <p className="text-gray-500 max-w-md">
+                    娆㈣繋浣跨敤渚涘簲閾惧叏鏅礊瀵熺郴缁燂紒鎮ㄥ彲浠ュ挩璇㈡彃鍗曞奖鍝嶅垎鏋愩�佺敓浜ц鍒掍紭鍖栥�佷緵搴旈摼椋庨櫓璇勪及绛夐棶棰樸��
+                  </p>
+                </div>
+              ) : (
+                messages.map((msg, index) => (
+                  <div
+                    key={msg.id}
+                    className={`flex items-start gap-4 ${msg.role === 'user' ? 'flex-row-reverse' : ''}`}
+                  >
+                    <div className="relative flex-shrink-0">
+                      <div className="w-8 h-8 rounded-lg overflow-hidden shadow-inner bg-gray-50">
+                        <Image 
+                          src={msg.role === 'assistant' ? "/images/logo.jpg" : DEFAULT_USER_AVATAR}
+                          alt={msg.role === 'assistant' ? "AI鍔╂墜" : "鐢ㄦ埛"}
+                          width={32}
+                          height={32}
+                          className="w-full h-full object-cover"
+                        />
+                      </div>
+                    </div>
+                    <div className={`flex-1 min-w-0 ${msg.role === 'user' ? 'text-right' : ''}`}>
+                      <div className={`${
+                        msg.role === 'assistant' 
+                          ? 'bg-white rounded-xl shadow-sm border border-gray-100' 
+                          : 'bg-[#E8F4FF] rounded-xl'
+                        } inline-block max-w-[85%] relative overflow-hidden`}>
+                        
+                        {msg.role === 'assistant' && (
+                          <>{(() => {
+                            // 瑙f瀽娑堟伅鍐呭锛屾彁鍙栨�濊�冮儴鍒�
+                            const { mainContent, thinkContent } = parseMessageContent(msg.content);
+                            const isExpanded = expandedThinkMessages[msg.id] || false;
+                            const thinkingDuration = 8; // 鎬濊�冩椂闂�(绉�)
+                            
+                            return (
+                              <>
+                                {/* 鎬濊�冨唴瀹瑰尯鍩� (濡傛灉瀛樺湪) */}
+                                {thinkContent && (
+                                  <div className="border-b border-gray-200">
+                                    <button 
+                                      onClick={() => toggleThinkContent(msg.id)}
+                                      className="w-full flex items-center justify-between px-3 py-2 bg-gray-50 hover:bg-gray-100 transition-colors text-sm text-gray-700"
+                                    >
+                                      <div className="flex items-center space-x-2">
+                                        <span>宸叉繁搴︽�濊�� (鐢ㄦ椂 {thinkingDuration} 绉�)</span>
+                                      </div>
+                                      <svg 
+                                        className={`w-4 h-4 transform transition-transform ${isExpanded ? 'rotate-180' : ''}`}
+                                        fill="none" 
+                                        stroke="currentColor" 
+                                        viewBox="0 0 24 24"
+                                      >
+                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
+                                      </svg>
+                                    </button>
+                                    
+                                    {/* 鍙姌鍙犵殑鎬濊�冨唴瀹� */}
+                                    {isExpanded && (
+                                      <div className="bg-gray-50 px-4 py-3 text-sm text-gray-700 border-t border-gray-200 whitespace-pre-wrap">
+                                        {thinkContent}
+                                      </div>
+                                    )}
+                                  </div>
+                                )}
+                                
+                                {/* 涓昏鍐呭 */}
+                                <div className="p-3">
+                                  <div className="text-gray-800 leading-relaxed">
+                                    {mainContent ? (
+                                      <MessageCompletionContext.Provider 
+                                        value={msg.id !== currentMessageId || isMessageComplete}
+                                      >
+                                        <ReactMarkdown
+                                          remarkPlugins={[remarkGfm]}
+                                          rehypePlugins={[rehypeRaw, rehypeSanitize]}
+                                          components={{
+                                            // @ts-ignore - ReactMarkdown 缁勪欢绫诲瀷瀹氫箟鐨勫吋瀹规�ч棶棰�
+                                            code: ({ node, inline, className, children, ...props }) => {
+                                              const match = /language-(\w+)/.exec(className || '');
+                                              const language = match ? match[1] : '';
+                                              const value = String(children).replace(/\n$/, '');
+                                              
+                                              if (!inline && match) {
+                                                return <CodeBlockRenderer language={language} value={value} />;
+                                              }
+                                              
+                                              return (
+                                                <code className={className} {...props}>
+                                                  {children}
+                                                </code>
+                                              );
+                                            },
+                                            // 娣诲姞琛ㄦ牸鏍峰紡缁勪欢
+                                            table: ({ node, ...props }) => (
+                                              <div className="overflow-x-auto my-4 rounded-lg border border-gray-100 shadow-sm" style={{ width: '100%', minWidth: '100%' }}>
+                                                <table className="min-w-full divide-y divide-gray-100" style={{ tableLayout: 'auto', width: 'max-content', minWidth: '100%' }} {...props} />
+                                              </div>
+                                            ),
+                                            thead: ({ node, ...props }) => (
+                                              <thead className="bg-gray-50/70" {...props} />
+                                            ),
+                                            th: ({ node, children, ...props }) => (
+                                              <th className="px-4 py-3 text-sm font-semibold text-gray-700 border-b border-gray-100 text-center" style={{ whiteSpace: 'nowrap', minWidth: 'max-content' }} {...props}>
+                                                {children}
+                                              </th>
+                                            ),
+                                            td: ({ node, ...props }) => (
+                                              <td className="px-4 py-3 text-sm text-gray-600 border-t border-gray-100 text-center" style={{ whiteSpace: 'nowrap' }} {...props} />
+                                            ),
+                                            tr: ({ node, ...props }) => (
+                                              <tr className="hover:bg-gray-50/70 transition-colors duration-150" {...props} />
+                                            )
+                                          }}
+                                        >
+                                          {mainContent}
+                                        </ReactMarkdown>
+                                      </MessageCompletionContext.Provider>
+                                    ) : (
+                                      msg.role === 'assistant' && !isMessageComplete ? '澶勭悊鍥炲涓�...' : ''
+                                    )}
+                                  </div>
+                                </div>
+                                
+                                {/* 鍔犺浇鎸囩ず鍣� */}
+                                {msg.role === 'assistant' && 
+                                  !isMessageComplete && 
+                                  msg.id === currentMessageId && ( // 鍙湪褰撳墠澶勭悊鐨勬秷鎭樉绀哄姞杞芥寚绀哄櫒
+                                  <div className="absolute bottom-1 right-2">
+                                    <div className="flex space-x-1">
+                                      <div className="w-1.5 h-1.5 rounded-full bg-blue-400 animate-pulse delay-0"></div>
+                                      <div className="w-1.5 h-1.5 rounded-full bg-blue-400 animate-pulse delay-150"></div>
+                                      <div className="w-1.5 h-1.5 rounded-full bg-blue-400 animate-pulse delay-300"></div>
+                                    </div>
+                                  </div>
+                                )}
+                              </>
+                            );
+                          })()}</>
+                        )}
+                        
+                        {/* 鐢ㄦ埛娑堟伅绠�鍗曟樉绀� */}
+                        {msg.role === 'user' && (
+                          <div className="p-3">
+                            <div className="text-gray-800 leading-relaxed whitespace-pre-wrap">
+                              {msg.content}
+                            </div>
+                          </div>
+                        )}
+                      </div>
+                      <div className="mt-0.5 text-xs text-gray-400">
+                        {msg.role === 'user' && new Date(msg.timestamp).toLocaleTimeString()}
+                      </div>
+                    </div>
+                  </div>
+                ))
+              )}
+              <div ref={messagesEndRef} />
+            </div>
+          </div>
+        </div>
+
+        {/* 杈撳叆鍖哄煙 - 鎶藉彇涓虹嫭绔嬬粍浠� */}
+        <ChatInput 
+          onSendMessage={handleSendMessage} 
+          isStreaming={isStreaming} 
+          isMessageComplete={isMessageComplete} 
+        />
+      </div>
+    </div>
+  );
+} 
\ No newline at end of file
diff --git a/src/components/DataPreviewDialog.tsx b/src/components/DataPreviewDialog.tsx
index aa15e73..6ba4d1e 100644
--- a/src/components/DataPreviewDialog.tsx
+++ b/src/components/DataPreviewDialog.tsx
@@ -10,7 +10,7 @@
   isOpen: boolean;
   onClose: () => void;
   markdownContent: string;
-  sceneType?: 'chadan' | 'buliao';  // 娣诲姞鍦烘櫙绫诲瀷灞炴��
+  sceneType?: 'chadan' | 'buliao' | 'panorama';  // 娣诲姞鍦烘櫙绫诲瀷灞炴��
 }
 
 export default function DataPreviewDialog({
@@ -101,6 +101,80 @@
           </div>
         </div>
       );
+    } else if (sceneType === 'panorama') {
+      return (
+        <div className="space-y-6">
+          <div className="bg-white/50 rounded-lg p-4 backdrop-blur-sm border border-blue-100/50">
+            <div className="flex items-center gap-3 mb-3">
+              <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center">
+                <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
+                </svg>
+              </div>
+              <h4 className="text-lg font-semibold text-blue-900">璁㈠崟闇�姹傛暟鎹�</h4>
+            </div>
+            <div className="ml-11">
+              <p className="text-blue-800">鏍稿績鏉ユ簮绯荤粺锛歄MS锛堣鍗曠鐞嗙郴缁燂級</p>
+            </div>
+          </div>
+
+          <div className="bg-white/50 rounded-lg p-4 backdrop-blur-sm border border-blue-100/50">
+            <div className="flex items-center gap-3 mb-3">
+              <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center">
+                <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 7v10c0 2 1 3 3 3h10c2 0 3-1 3-3V7c0-2-1-3-3-3H7C5 4 4 5 4 7z" />
+                </svg>
+              </div>
+              <h4 className="text-lg font-semibold text-blue-900">鐢熶骇宸ュ崟鏁版嵁</h4>
+            </div>
+            <div className="ml-11">
+              <p className="text-blue-800">鏍稿績鏉ユ簮绯荤粺锛欵RP锛堜紒涓氳祫婧愯鍒掞級</p>
+            </div>
+          </div>
+
+          <div className="bg-white/50 rounded-lg p-4 backdrop-blur-sm border border-blue-100/50">
+            <div className="flex items-center gap-3 mb-3">
+              <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center">
+                <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
+                </svg>
+              </div>
+              <h4 className="text-lg font-semibold text-blue-900">搴撳瓨鏁版嵁</h4>
+            </div>
+            <div className="ml-11">
+              <p className="text-blue-800">鏍稿績鏉ユ簮绯荤粺锛歐MS锛堜粨鍌ㄧ鐞嗙郴缁燂級</p>
+            </div>
+          </div>
+
+          <div className="bg-white/50 rounded-lg p-4 backdrop-blur-sm border border-blue-100/50">
+            <div className="flex items-center gap-3 mb-3">
+              <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center">
+                <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
+                </svg>
+              </div>
+              <h4 className="text-lg font-semibold text-blue-900">渚涘簲鍟嗙哗鏁堟暟鎹�</h4>
+            </div>
+            <div className="ml-11">
+              <p className="text-blue-800">鏍稿績鏉ユ簮绯荤粺锛歋RM锛堜緵搴斿晢鍏崇郴绠$悊锛夈�佽川閲忕鐞嗙郴缁�</p>
+            </div>
+          </div>
+
+          <div className="bg-white/50 rounded-lg p-4 backdrop-blur-sm border border-blue-100/50">
+            <div className="flex items-center gap-3 mb-3">
+              <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center">
+                <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
+                </svg>
+              </div>
+              <h4 className="text-lg font-semibold text-blue-900">浜ц兘鏁版嵁</h4>
+            </div>
+            <div className="ml-11">
+              <p className="text-blue-800">鏍稿績鏉ユ簮绯荤粺锛歁ES锛堝埗閫犳墽琛岀郴缁燂級銆佽澶囩洃鎺х郴缁�</p>
+            </div>
+          </div>
+        </div>
+      );
     }
     return null;
   };
diff --git a/src/components/SceneIntroDialog.tsx b/src/components/SceneIntroDialog.tsx
index fea9b41..15ae804 100644
--- a/src/components/SceneIntroDialog.tsx
+++ b/src/components/SceneIntroDialog.tsx
@@ -44,11 +44,66 @@
 
   const handleStartChat = () => {
     onClose();
-    document.body.classList.add('page-transitioning');
-    setTimeout(() => {
-      window.location.href = `/ai-scene/chat?scene=${scene.chatbotId}`;
-    }, 100);
+    // 渚涘簲閾惧叏鏅礊瀵熷満鏅娇鐢ㄤ笓鐢ㄧ殑鑱婂ぉ椤甸潰
+    if (scene.chatbotId === 'SCPanoramaInsight') {
+      window.location.href = `/supply-chain-chat?key=app-6IZEwVNGfHrlLFlgLauLHtHo`;
+    } else {
+      window.location.href = `/ai-scene/chat?chatbotId=${scene.chatbotId}`;
+    }
   };
+
+  // 瑙f瀽鍦烘櫙鑳屾櫙鍐呭
+  const parseBackground = (background: string): { simple: string } | { intro: string; sections: Array<{ title: string; items: string[] }> } | null => {
+    if (!background) return null;
+    
+    // 妫�鏌ユ槸鍚﹀寘鍚粨鏋勫寲鍐呭锛堝渚涘簲閾惧叏鏅礊瀵熺殑鏍煎紡锛�
+    if (background.includes('**') && background.includes('锛�')) {
+      const sections = background.split('\n\n').filter(section => section.trim());
+      const intro = sections[0];
+      const detailSections = sections.slice(1);
+      
+      return {
+        intro,
+        sections: detailSections.map(section => {
+          const lines = section.split('\n');
+          const title = lines[0].replace(/\*\*/g, '').replace('锛�', '');
+          const items = lines.slice(1).filter(line => line.trim().startsWith('-')).map(line => line.replace('- ', ''));
+          return { title, items };
+        })
+      };
+    }
+    
+    return { simple: background };
+  };
+
+  // 瑙f瀽浣跨敤璇存槑鍐呭
+  const parseInstructions = (instructions: string): { simple: string } | { intro: string; scenarios: Array<{ title: string; description: string }>; conclusion: string } | null => {
+    if (!instructions) return null;
+    
+    // 妫�鏌ユ槸鍚﹀寘鍚満鏅牸寮�
+    if (instructions.includes('**鍦烘櫙') && instructions.includes('锛�')) {
+      const sections = instructions.split('\n\n').filter(section => section.trim());
+      const intro = sections[0];
+      const scenarios = sections.slice(1, -1).map(section => {
+        const lines = section.split('\n');
+        const title = lines[0].replace(/\*\*/g, '').replace('锛�', '');
+        const description = lines[1] || '';
+        return { title, description };
+      });
+      const conclusion = sections[sections.length - 1];
+      
+      return {
+        intro,
+        scenarios,
+        conclusion
+      };
+    }
+    
+    return { simple: instructions };
+  };
+
+  const backgroundData = parseBackground(scene.background || '');
+  const instructionsData = parseInstructions(scene.instructions || '');
 
   return (
     <AnimatePresence>
@@ -202,10 +257,36 @@
                                 }}
                                 className="bg-[#1A2547] rounded-lg p-6 border border-[#6ADBFF]/10"
                               >
-                                <h3 className="text-lg font-medium text-[#6ADBFF] mb-3">鍦烘櫙鑳屾櫙</h3>
-                                <p className="text-gray-300 leading-relaxed">
-                                  {scene.background}
-                                </p>
+                                <h3 className="text-lg font-medium text-[#6ADBFF] mb-4">鍦烘櫙鑳屾櫙</h3>
+                                {backgroundData && 'simple' in backgroundData ? (
+                                  <p className="text-gray-300 leading-relaxed">
+                                    {backgroundData.simple}
+                                  </p>
+                                ) : backgroundData && 'sections' in backgroundData && (
+                                  <div className="space-y-4">
+                                    <p className="text-gray-300 leading-relaxed">
+                                      {backgroundData.intro}
+                                    </p>
+                                    <div className="grid gap-4">
+                                      {backgroundData.sections.map((section, index) => (
+                                        <div key={index} className="bg-[#0F1629] rounded-lg p-4 border border-[#6ADBFF]/5">
+                                          <h4 className="text-[#FF6A88] font-medium mb-3 flex items-center">
+                                            <div className="w-2 h-2 rounded-full bg-[#FF6A88] mr-2"></div>
+                                            {section.title}
+                                          </h4>
+                                          <ul className="space-y-2">
+                                            {section.items.map((item, itemIndex) => (
+                                              <li key={itemIndex} className="text-gray-300 text-sm flex items-start">
+                                                <div className="w-1 h-1 rounded-full bg-[#6ADBFF]/60 mt-2 mr-3 flex-shrink-0"></div>
+                                                <span>{item}</span>
+                                              </li>
+                                            ))}
+                                          </ul>
+                                        </div>
+                                      ))}
+                                    </div>
+                                  </div>
+                                )}
                               </motion.div>
 
                               {/* 浣跨敤璇存槑 */}
@@ -219,10 +300,40 @@
                                 }}
                                 className="bg-[#1A2547] rounded-lg p-6 border border-[#6ADBFF]/10"
                               >
-                                <h3 className="text-lg font-medium text-[#6ADBFF] mb-3">浣跨敤璇存槑</h3>
-                                <p className="text-gray-300 leading-relaxed">
-                                  {scene.instructions}
-                                </p>
+                                <h3 className="text-lg font-medium text-[#6ADBFF] mb-4">浣跨敤璇存槑</h3>
+                                {instructionsData && 'simple' in instructionsData ? (
+                                  <p className="text-gray-300 leading-relaxed">
+                                    {instructionsData.simple}
+                                  </p>
+                                ) : instructionsData && 'scenarios' in instructionsData && (
+                                  <div className="space-y-4">
+                                    <p className="text-gray-300 leading-relaxed">
+                                      {instructionsData.intro}
+                                    </p>
+                                    <div className="grid gap-3">
+                                      {instructionsData.scenarios.map((scenario, index) => (
+                                        <div key={index} className="bg-[#0F1629] rounded-lg p-4 border border-[#6ADBFF]/5 hover:border-[#6ADBFF]/20 transition-colors duration-300">
+                                          <div className="flex items-center mb-2">
+                                            <div className="w-6 h-6 rounded-full bg-gradient-to-r from-[#6ADBFF] to-[#5E72EB] flex items-center justify-center mr-3">
+                                              <span className="text-white text-xs font-medium">{index + 1}</span>
+                                            </div>
+                                            <h4 className="text-[#F5A800] font-medium">
+                                              {scenario.title}
+                                            </h4>
+                                          </div>
+                                          <p className="text-gray-300 text-sm ml-9">
+                                            {scenario.description}
+                                          </p>
+                                        </div>
+                                      ))}
+                                    </div>
+                                    <div className="mt-4 p-4 bg-[#0F1629] rounded-lg border border-[#6ADBFF]/5">
+                                      <p className="text-gray-300 text-sm">
+                                        {instructionsData.conclusion}
+                                      </p>
+                                    </div>
+                                  </div>
+                                )}
                               </motion.div>
 
                               {/* 鏁版嵁璇存槑鍖哄潡 - 鍙湪鐗瑰畾鍦烘櫙鏄剧ず */}
@@ -265,7 +376,8 @@
                                   onClose={() => setShowDataPreview(false)}
                                   markdownContent={scene.exampleData}
                                   sceneType={scene.chatbotId === 'RhMYLHI1SZNiX4kl' || scene.chatbotId === 'zO9YQDEHdIApG9zC' ? 'chadan' :
-                                           scene.chatbotId === 'JELkWpPLHQfRNhEH' ? 'buliao' : undefined}
+                                           scene.chatbotId === 'JELkWpPLHQfRNhEH' ? 'buliao' :
+                                           scene.chatbotId === 'SCPanoramaInsight' ? 'panorama' : undefined}
                                 />
                               )}
                             </div>
diff --git a/src/components/layout/ClientLayoutContent.tsx b/src/components/layout/ClientLayoutContent.tsx
index 64b02f9..a859df6 100644
--- a/src/components/layout/ClientLayoutContent.tsx
+++ b/src/components/layout/ClientLayoutContent.tsx
@@ -23,6 +23,7 @@
   const isAIScenePage = pathname === '/ai-scene';
   const isAISceneChatPage = pathname.startsWith('/ai-scene/chat');
   const isChatPage = pathname === '/chat'; // 娣诲姞鑱婂ぉ椤甸潰鍒ゆ柇
+  const isSupplyChainChatPage = pathname === '/supply-chain-chat'; // 娣诲姞渚涘簲閾捐亰澶╅〉闈㈠垽鏂�
 
   // 璁剧疆瀹㈡埛绔姸鎬�
   useEffect(() => {
@@ -99,7 +100,7 @@
         <main className={`flex-1 ${isHomePage || isAIScenePage ? '' : 'bg-gradient-to-b from-[var(--ai-surface)] to-white'} pt-0 mt-0`}>
           {children}
         </main>
-        {!isLoginPage && !isRegisterPage && !isAISceneChatPage && !isChatPage && (
+        {!isLoginPage && !isRegisterPage && !isAISceneChatPage && !isChatPage && !isSupplyChainChatPage && (
           <footer className="relative z-20 bg-gradient-to-br from-[#0A1033] via-[#1E2B63] to-[#131C41] text-white py-10 overflow-hidden">
             {/* 绉戞妧鎰熷姩鎬佽儗鏅厓绱� */}
             <div className="absolute inset-0 overflow-hidden pointer-events-none">

--
Gitblit v1.9.3