From 3a2d67fa9b765a3cad6306a0369976d4b0a0a892 Mon Sep 17 00:00:00 2001
From: hongjli <3117313295@qq.com>
Date: 星期二, 27 五月 2025 14:11:04 +0800
Subject: [PATCH] 实现对key值的功能

---
 src/app/chatroom/page.tsx |  247 +++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 205 insertions(+), 42 deletions(-)

diff --git a/src/app/chatroom/page.tsx b/src/app/chatroom/page.tsx
index 0978f9d..e6e67b4 100644
--- a/src/app/chatroom/page.tsx
+++ b/src/app/chatroom/page.tsx
@@ -4,10 +4,13 @@
 
 export default function ChatRoomPage() {
   const [apiKey, setApiKey] = useState<string>('');
+  const [originalApiKey, setOriginalApiKey] = useState<string>(''); // 瀛樺偍浠嶢PI鑾峰彇鐨勫師濮嬪瘑閽�
   const [showApiKeyInput, setShowApiKeyInput] = useState(false);
   const [showApiKey, setShowApiKey] = useState(false);
   const [error, setError] = useState<string | null>(null);
   const [showError, setShowError] = useState(false);
+  const [isLoading, setIsLoading] = useState(false);
+  const [isUpdating, setIsUpdating] = useState(false);
 
   useEffect(() => {
     // 鑾峰彇瀛樺偍鐨凙PI Key
@@ -17,82 +20,242 @@
     }
   }, []);
 
-  const handleApiKeySubmit = () => {
-    if (apiKey.trim()) {
-      localStorage.setItem('api-key', apiKey);
-      setShowApiKeyInput(false);
-      setError(null);
+  // 鏄剧ず閿欒娑堟伅
+  const showErrorMessage = (message: string) => {
+    setError(message);
+    setShowError(true);
+    setTimeout(() => {
+      setShowError(false);
+      setTimeout(() => setError(null), 300);
+    }, 3000);
+  };
+
+  // 鑾峰彇褰撳墠瀵嗛挜
+  const fetchCurrentApiKey = async () => {
+    setIsLoading(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 keyValue = result.data.key;
+        setOriginalApiKey(keyValue);
+        setApiKey(keyValue);
+        console.log('鎴愬姛鑾峰彇API瀵嗛挜:', keyValue);
+        return keyValue;
+      } 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 {
+      setIsLoading(false);
     }
   };
 
-  // 娣诲姞鍑芥暟鏉ユ樉绀篈PI Key璁剧疆妯℃�佹锛屽悓鏃堕噸鏂拌幏鍙杔ocalStorage涓殑鍊�
-  const handleShowApiKeyModal = () => {
-    // 閲嶆柊鑾峰彇瀛樺偍鐨凙PI Key
-    const storedApiKey = localStorage.getItem('api-key');
-    if (storedApiKey) {
-      setApiKey(storedApiKey);
+  // 鏇存柊瀵嗛挜
+  const updateApiKey = async (newKey: string) => {
+    if (!newKey.trim()) {
+      showErrorMessage('瀵嗛挜涓嶈兘涓虹┖');
+      return false;
     }
+
+    setIsUpdating(true);
+    try {
+      const response = await fetch(`http://121.43.139.99:8080/api/secret-key/update/${encodeURIComponent(newKey)}`, {
+        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 updatedKey = result.data.key;
+        setOriginalApiKey(updatedKey);
+        setApiKey(updatedKey);
+        localStorage.setItem('api-key', updatedKey);
+        console.log('鎴愬姛鏇存柊API瀵嗛挜:', updatedKey);
+        showErrorMessage('瀵嗛挜鏇存柊鎴愬姛锛�');
+        return true;
+      } else {
+        throw new Error(result.message || '鏇存柊瀵嗛挜澶辫触锛氬搷搴旀牸寮忎笉姝g‘');
+      }
+    } catch (err) {
+      console.error('鏇存柊API瀵嗛挜澶辫触:', err);
+      const errorMessage = err instanceof Error ? err.message : '鏇存柊瀵嗛挜鏃跺彂鐢熸湭鐭ラ敊璇�';
+      showErrorMessage(`瀵嗛挜鏇存柊澶辫触: ${errorMessage}`);
+      return false;
+    } finally {
+      setIsUpdating(false);
+    }
+  };
+
+  const handleApiKeySubmit = async () => {
+    if (apiKey.trim()) {
+      // 濡傛灉瀵嗛挜鏈夊彉鍖栵紝鍒欒皟鐢ㄦ洿鏂癆PI
+      if (apiKey.trim() !== originalApiKey) {
+        const success = await updateApiKey(apiKey.trim());
+        if (success) {
+          setShowApiKeyInput(false);
+          setError(null);
+        }
+      } else {
+        // 瀵嗛挜娌℃湁鍙樺寲锛岀洿鎺ュ叧闂ā鎬佹
+        localStorage.setItem('api-key', apiKey);
+        setShowApiKeyInput(false);
+        setError(null);
+      }
+    }
+  };
+
+  // 娣诲姞鍑芥暟鏉ユ樉绀篈PI Key璁剧疆妯℃�佹锛屽悓鏃朵粠API鑾峰彇褰撳墠瀵嗛挜
+  const handleShowApiKeyModal = async () => {
     setShowApiKeyInput(true);
+    // 浠嶢PI鑾峰彇褰撳墠瀵嗛挜
+    await fetchCurrentApiKey();
   };
 
   return (
     <div className="min-h-screen bg-gradient-to-b from-[#1E2B63] to-[#0A1033] flex items-center justify-center relative">
+      {/* 閿欒鎻愮ず */}
+      {error && (
+        <div 
+          className={`fixed top-20 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 z-[60]
+            ${showError 
+              ? 'opacity-100 translate-y-0 scale-100' 
+              : 'opacity-0 -translate-y-2 scale-95'
+            }
+            before:content-[''] before:absolute before:inset-0 before:bg-blue-500 
+            before:rounded-lg before:opacity-90 before:-z-10
+            after:content-[''] after:absolute after:inset-0 after:bg-blue-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 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" />
+          </svg>
+          <span className="relative">{error}</span>
+        </div>
+      )}
+
       {/* API Key Modal */}
       {showApiKeyInput && (
         <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
-          <div className="bg-white rounded-2xl p-6 w-[400px] space-y-4 shadow-xl">
+          <div className="bg-white rounded-2xl p-6 w-[450px] space-y-4 shadow-xl">
             <div className="flex justify-between items-center">
-              <h2 className="text-xl font-semibold">璁剧疆 API Key</h2>
+              <h2 className="text-xl font-semibold">绠$悊 API Key</h2>
               <button
                 onClick={() => setShowApiKeyInput(false)}
                 className="text-gray-400 hover:text-gray-600"
+                disabled={isLoading || isUpdating}
               >
                 <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                   <path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
                 </svg>
               </button>
             </div>
+
+            {/* 褰撳墠瀵嗛挜鏄剧ず */}
+            {originalApiKey && (
+              <div className="bg-gray-50 rounded-lg p-3">
+                <label className="text-sm font-medium text-gray-700 mb-1 block">褰撳墠瀵嗛挜</label>
+                <div className="text-sm text-gray-600 font-mono break-all">
+                  {showApiKey ? originalApiKey : '鈥⑩�⑩�⑩�⑩�⑩�⑩�⑩�⑩�⑩�⑩�⑩�⑩�⑩�⑩�⑩��'}
+                </div>
+              </div>
+            )}
             
-            <div className="relative">
-              <input
-                type={showApiKey ? "text" : "password"}
-                value={apiKey}
-                onChange={(e) => setApiKey(e.target.value)}
-                placeholder="璇疯緭鍏ユ偍鐨� API Key"
-                className="w-full px-4 py-2 rounded-xl border border-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-100/50 text-gray-900"
-              />
-              <button
-                type="button"
-                onClick={() => setShowApiKey(!showApiKey)}
-                className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
-              >
-                {showApiKey ? (
-                  // 鐪肩潧鍏抽棴鍥炬爣
-                  <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
-                    <path fillRule="evenodd" d="M3.707 2.293a1 1 0 00-1.414 1.414l14 14a1 1 0 001.414-1.414l-1.473-1.473A10.014 10.014 0 0019.542 10C18.268 5.943 14.478 3 10 3a9.958 9.958 0 00-4.512 1.074l-1.78-1.781zm4.261 4.26l1.514 1.515a2.003 2.003 0 012.45 2.45l1.514 1.514a4 4 0 00-5.478-5.478z" clipRule="evenodd" />
-                    <path d="M12.454 16.697L9.75 13.992a4 4 0 01-3.742-3.741L2.335 6.578A9.98 9.98 0 00.458 10c1.274 4.057 5.065 7 9.542 7 .847 0 1.669-.105 2.454-.303z" />
-                  </svg>
-                ) : (
-                  // 鐪肩潧鍥炬爣
-                  <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
-                    <path d="M10 12a2 2 0 100-4 2 2 0 000 4z" />
-                    <path fillRule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clipRule="evenodd" />
-                  </svg>
+            <div className="space-y-2">
+              <label className="text-sm font-medium text-gray-700">鏂板瘑閽�</label>
+              <div className="relative">
+                <input
+                  type={showApiKey ? "text" : "password"}
+                  value={apiKey}
+                  onChange={(e) => setApiKey(e.target.value)}
+                  placeholder={isLoading ? "姝e湪鑾峰彇褰撳墠瀵嗛挜..." : "璇疯緭鍏ユ柊鐨� API Key"}
+                  disabled={isLoading || isUpdating}
+                  className="w-full px-4 py-2 rounded-xl border border-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-100/50 text-gray-900 disabled:bg-gray-100 disabled:cursor-not-allowed"
+                />
+                <button
+                  type="button"
+                  onClick={() => setShowApiKey(!showApiKey)}
+                  disabled={isLoading || isUpdating}
+                  className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 disabled:cursor-not-allowed"
+                >
+                  {showApiKey ? (
+                    // 鐪肩潧鍏抽棴鍥炬爣
+                    <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
+                      <path fillRule="evenodd" d="M3.707 2.293a1 1 0 00-1.414 1.414l14 14a1 1 0 001.414-1.414l-1.473-1.473A10.014 10.014 0 0019.542 10C18.268 5.943 14.478 3 10 3a9.958 9.958 0 00-4.512 1.074l-1.78-1.781zm4.261 4.26l1.514 1.515a2.003 2.003 0 012.45 2.45l1.514 1.514a4 4 0 00-5.478-5.478z" clipRule="evenodd" />
+                      <path d="M12.454 16.697L9.75 13.992a4 4 0 01-3.742-3.741L2.335 6.578A9.98 9.98 0 00.458 10c1.274 4.057 5.065 7 9.542 7 .847 0 1.669-.105 2.454-.303z" />
+                    </svg>
+                  ) : (
+                    // 鐪肩潧鍥炬爣
+                    <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
+                      <path d="M10 12a2 2 0 100-4 2 2 0 000 4z" />
+                      <path fillRule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clipRule="evenodd" />
+                    </svg>
+                  )}
+                </button>
+                
+                {/* 鍔犺浇鎸囩ず鍣� */}
+                {isLoading && (
+                  <div className="absolute right-12 top-1/2 -translate-y-1/2">
+                    <div className="w-4 h-4 border-2 border-blue-500/30 border-t-blue-500 rounded-full animate-spin"></div>
+                  </div>
                 )}
-              </button>
+              </div>
+              
+              {/* 鎻愮ず淇℃伅 */}
+              <div className="text-xs text-gray-500">
+                {apiKey.trim() !== originalApiKey && apiKey.trim() !== '' ? (
+                  <span className="text-orange-600">瀵嗛挜宸蹭慨鏀癸紝鐐瑰嚮纭畾灏嗘洿鏂板埌鏈嶅姟鍣�</span>
+                ) : (
+                  <span>淇敼瀵嗛挜鍚庡皢鑷姩鍚屾鍒版湇鍔″櫒</span>
+                )}
+              </div>
             </div>
+
             <div className="flex justify-end gap-2">
               <button
                 onClick={() => setShowApiKeyInput(false)}
-                className="px-4 py-2 text-gray-600 hover:text-gray-900"
+                disabled={isLoading || isUpdating}
+                className="px-4 py-2 text-gray-600 hover:text-gray-900 disabled:cursor-not-allowed disabled:opacity-50"
               >
                 鍙栨秷
               </button>
               <button
                 onClick={handleApiKeySubmit}
-                className="px-4 py-2 bg-blue-500 text-white rounded-xl hover:bg-blue-600"
+                disabled={isLoading || isUpdating || !apiKey.trim()}
+                className="px-4 py-2 bg-blue-500 text-white rounded-xl hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-50 flex items-center gap-2"
               >
-                纭畾
+                {isUpdating && (
+                  <div className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin"></div>
+                )}
+                {isUpdating ? '鏇存柊涓�...' : '纭畾'}
               </button>
             </div>
           </div>

--
Gitblit v1.9.3