From f9e3cb0cebf135fce1845b4b6351a1ad604f1990 Mon Sep 17 00:00:00 2001 From: "mula.liu" Date: Tue, 2 Dec 2025 19:20:33 +0800 Subject: [PATCH] 1.0.1 --- frontend/src/components/FocusInfo.tsx | 24 ++-- frontend/src/components/Header.tsx | 4 +- frontend/src/components/TerminalModal.tsx | 2 + frontend/src/contexts/ToastContext.tsx | 2 +- frontend/src/pages/admin/AdminLayout.tsx | 157 +++++++++++++++++++++- 5 files changed, 170 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/FocusInfo.tsx b/frontend/src/components/FocusInfo.tsx index b27856b..74e5634 100644 --- a/frontend/src/components/FocusInfo.tsx +++ b/frontend/src/components/FocusInfo.tsx @@ -56,7 +56,7 @@ export function FocusInfo({ body, onClose, toast }: FocusInfoProps) {
{/* Main Info Card */} -
+
{/* Close Button */} -
+
{/* Conditional Probe Status Card (if isProbe is true, this goes in a new row) */} @@ -135,7 +133,7 @@ export function FocusInfo({ body, onClose, toast }: FocusInfoProps) {
{/* Connecting Line/Triangle pointing down to the body */} -
+
-
- 🌌 -
+ 🌌

Cosmo

DEEP SPACE EXPLORER

diff --git a/frontend/src/components/TerminalModal.tsx b/frontend/src/components/TerminalModal.tsx index a0cf854..5b420c9 100644 --- a/frontend/src/components/TerminalModal.tsx +++ b/frontend/src/components/TerminalModal.tsx @@ -67,6 +67,8 @@ export function TerminalModal({ } .terminal-modal .ant-modal-close { color: #2ea043 !important; + top: 24px !important; + inset-inline-end: 20px !important; } .terminal-modal .ant-modal-close:hover { background-color: rgba(35, 134, 54, 0.2) !important; diff --git a/frontend/src/contexts/ToastContext.tsx b/frontend/src/contexts/ToastContext.tsx index bd49420..47a85ae 100644 --- a/frontend/src/contexts/ToastContext.tsx +++ b/frontend/src/contexts/ToastContext.tsx @@ -96,7 +96,7 @@ export function ToastProvider({ children }: { children: React.ReactNode }) { {children} {/* Toast Container - Top Right */} -
+
{toasts.map((toast) => (
([]); const [loading, setLoading] = useState(true); + const [profileModalOpen, setProfileModalOpen] = useState(false); + const [passwordModalOpen, setPasswordModalOpen] = useState(false); + const [profileForm] = Form.useForm(); + const [passwordForm] = Form.useForm(); + const [userProfile, setUserProfile] = useState(null); const navigate = useNavigate(); const location = useLocation(); const user = auth.getUser(); @@ -96,11 +101,57 @@ export function AdminLayout() { } }; + const handleProfileClick = async () => { + try { + const { data } = await request.get('/users/me'); + setUserProfile(data); + profileForm.setFieldsValue({ + username: data.username, + email: data.email || '', + full_name: data.full_name || '', + }); + setProfileModalOpen(true); + } catch (error) { + toast.error('获取用户信息失败'); + } + }; + + const handleProfileUpdate = async (values: any) => { + try { + await request.put('/users/me/profile', { + full_name: values.full_name, + email: values.email || null, + }); + toast.success('个人信息更新成功'); + setProfileModalOpen(false); + // Update local user info + const updatedUser = { ...user, full_name: values.full_name, email: values.email }; + auth.setUser(updatedUser); + } catch (error: any) { + toast.error(error.response?.data?.detail || '更新失败'); + } + }; + + const handlePasswordChange = async (values: any) => { + try { + await request.put('/users/me/password', { + old_password: values.old_password, + new_password: values.new_password, + }); + toast.success('密码修改成功'); + setPasswordModalOpen(false); + passwordForm.resetFields(); + } catch (error: any) { + toast.error(error.response?.data?.detail || '密码修改失败'); + } + }; + const userMenuItems: MenuProps['items'] = [ { key: 'profile', icon: , label: '个人信息', + onClick: handleProfileClick, }, { type: 'divider', @@ -174,6 +225,108 @@ export function AdminLayout() { + + {/* Profile Modal */} + setProfileModalOpen(false)} + footer={null} + width={500} + > +
+ + + + + + + + + + + + + +
+
+ + {/* Password Change Modal */} + { + setPasswordModalOpen(false); + passwordForm.resetFields(); + }} + footer={null} + width={450} + > +
+ + + + + + + ({ + validator(_, value) { + if (!value || getFieldValue('new_password') === value) { + return Promise.resolve(); + } + return Promise.reject(new Error('两次输入的密码不一致')); + }, + }), + ]} + > + + + + + +
+
); }