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