From 61795d0ddb2406e13363aaabe25f34ca158ce23b Mon Sep 17 00:00:00 2001 From: moux1024 <403053463@qq.com> Date: Mon, 29 Sep 2025 14:54:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=8E=A7=E5=88=B6=E6=BF=80=E6=B4=BB=E9=82=AE?= =?UTF-8?q?=E4=BB=B6=E5=BC=B9=E7=AA=97=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/serversetting.ts | 20 +++++++++++++ app/signup/page.tsx | 45 ++++++++++++++++++++++++++--- lib/store/serverSettingHooks.ts | 41 ++++++++++++++++++++++++++ lib/store/serverSettingSlice.ts | 51 +++++++++++++++++++++++++++++++++ lib/store/store.ts | 2 ++ 5 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 lib/store/serverSettingHooks.ts create mode 100644 lib/store/serverSettingSlice.ts diff --git a/api/serversetting.ts b/api/serversetting.ts index 2a2f198..ba2e360 100644 --- a/api/serversetting.ts +++ b/api/serversetting.ts @@ -116,3 +116,23 @@ export const fetchTabsByCode = async (code: string): Promise => { return []; } }; + +/** + * 通用:按 code 获取服务端配置,并解析为指定类型 + * 最简约实现:仅解析 res.data.value(JSON 字符串),失败返回默认值 + */ +export const fetchSettingByCode = async ( + code: string, + defaultValue?: T +): Promise => { + try { + const res = await post(`/api/server-setting/find_by_code`, { code }); + if (!res || res.code !== 0 || !res.successful || !res.data) return defaultValue; + const raw = res.data.value; + if (typeof raw !== 'string' || raw.length === 0) return defaultValue; + const parsed: T = JSON.parse(raw); + return parsed; + } catch { + return defaultValue; + } +}; diff --git a/app/signup/page.tsx b/app/signup/page.tsx index 33a17e1..7662553 100644 --- a/app/signup/page.tsx +++ b/app/signup/page.tsx @@ -6,8 +6,9 @@ import Link from "next/link"; import { signInWithGoogle, sendVerificationLink, registerUserWithInvite } from "@/lib/auth"; import { GradientText } from "@/components/ui/gradient-text"; import { GoogleLoginButton } from "@/components/ui/google-login-button"; -import { Eye, EyeOff, Mail } from "lucide-react"; +import { Eye, EyeOff, Mail, PartyPopper } from "lucide-react"; import { isGoogleLoginEnabled } from "@/lib/server-config"; +import { fetchSettingByCode } from "@/api/serversetting"; export default function SignupPage() { const [name, setName] = useState(""); @@ -28,6 +29,7 @@ export default function SignupPage() { const [emailFocused, setEmailFocused] = useState(false); const [passwordFocused, setPasswordFocused] = useState(false); const [showGoogleLogin, setShowGoogleLogin] = useState(false); + const [showRedirectModal, setShowRedirectModal] = useState(false); const router = useRouter(); // Handle scroll indicator for small screens and load SSO config @@ -211,9 +213,19 @@ export default function SignupPage() { sessionStorage.removeItem("inviteCode"); } catch {} - // Show activation modal instead of redirecting to login - setShowActivationModal(true); - setResendCooldown(60); + // 根据服务端配置是否展示激活弹窗 + try { + const showActivation = await fetchSettingByCode<{show: boolean}>("showActivation", {show: true}); + if (showActivation?.show === true) { + setShowActivationModal(true); + setResendCooldown(60); + } else { + setShowRedirectModal(true); + setTimeout(() => { + router.push("/login"); + }, 1500); + } + } catch {} } catch (error: any) { console.error("Signup error:", error); setFormError(error.message || "Registration failed, please try again"); @@ -636,6 +648,31 @@ export default function SignupPage() { )} + {showRedirectModal && ( +
+
+
+
+
+
+
+ +
+
+

注册成功,正在为您跳转到登录页

+

+ Please wait a moment, redirecting to login... +

+
+
+
+ )} ); } diff --git a/lib/store/serverSettingHooks.ts b/lib/store/serverSettingHooks.ts new file mode 100644 index 0000000..0245d19 --- /dev/null +++ b/lib/store/serverSettingHooks.ts @@ -0,0 +1,41 @@ +import { useCallback, useEffect } from 'react'; +import { useAppDispatch, useAppSelector } from './hooks'; +import { setError, setLoading, setValue } from './serverSettingSlice'; +import { fetchSettingByCode } from '@/api/serversetting'; + +/** + * 使用服务端配置(按 code) + * - 自动拉取并存入 store + * - 返回 loading/error/value 状态 + */ +export function useServerSetting(code: string, defaultValue?: T) { + const dispatch = useAppDispatch(); + const entry = useAppSelector((s) => s.serverSetting.byCode[code]); + + const load = useCallback(async () => { + if (!code) return; + dispatch(setLoading({ code, loading: true })); + try { + const value = await fetchSettingByCode(code, defaultValue as T | undefined); + dispatch(setValue({ code, value: value as T })); + } catch (e: any) { + dispatch(setError({ code, error: e?.message || 'Load failed' })); + } + }, [code, defaultValue, dispatch]); + + useEffect(() => { + // 仅当未加载过或无值时加载 + if (!entry || (entry && entry.value === undefined && !entry.loading)) { + load(); + } + }, [entry, load]); + + return { + loading: entry?.loading ?? false, + error: entry?.error, + value: (entry?.value as T | undefined) ?? defaultValue, + reload: load, + } as const; +} + + diff --git a/lib/store/serverSettingSlice.ts b/lib/store/serverSettingSlice.ts new file mode 100644 index 0000000..e90ecaa --- /dev/null +++ b/lib/store/serverSettingSlice.ts @@ -0,0 +1,51 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; + +interface ServerSettingEntry { + /** 是否加载中 */ + loading: boolean; + /** 错误信息(可选) */ + error?: string; + /** 解析后的配置值 */ + value?: T; +} + +export interface ServerSettingState { + /** 以 code 为 key 存放配置 */ + byCode: Record>; +} + +const initialState: ServerSettingState = { + byCode: {}, +}; + +export const serverSettingSlice = createSlice({ + name: 'serverSetting', + initialState, + reducers: { + setLoading(state, action: PayloadAction<{ code: string; loading: boolean }>) { + const { code, loading } = action.payload; + const current = state.byCode[code] || {}; + state.byCode[code] = { ...current, loading, error: loading ? undefined : current.error }; + }, + setValue(state, action: PayloadAction<{ code: string; value: T }>) { + const { code, value } = action.payload as { code: string; value: unknown }; + const current = state.byCode[code] || {}; + state.byCode[code] = { ...current, loading: false, error: undefined, value }; + }, + setError(state, action: PayloadAction<{ code: string; error: string }>) { + const { code, error } = action.payload; + const current = state.byCode[code] || {}; + state.byCode[code] = { ...current, loading: false, error }; + }, + clear(state, action: PayloadAction<{ code: string }>) { + const { code } = action.payload; + delete state.byCode[code]; + }, + }, +}); + +export const { setLoading, setValue, setError, clear } = serverSettingSlice.actions; + +export default serverSettingSlice.reducer; + + diff --git a/lib/store/store.ts b/lib/store/store.ts index c0dd802..c2c5815 100644 --- a/lib/store/store.ts +++ b/lib/store/store.ts @@ -1,9 +1,11 @@ import { configureStore } from '@reduxjs/toolkit'; import workflowReducer from './workflowSlice'; +import serverSettingReducer from './serverSettingSlice'; export const store = configureStore({ reducer: { workflow: workflowReducer, + serverSetting: serverSettingReducer, }, });