From cc1fdc5a40f1139baba767d4f7735ba8439a361b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sun, 28 Sep 2025 22:00:35 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E9=83=A8=E7=BD=B2=E7=94=9F=E4=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.production | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.env.production b/.env.production index 1720734..24e6f58 100644 --- a/.env.production +++ b/.env.production @@ -1,16 +1,16 @@ # 测试 -NEXT_PUBLIC_JAVA_URL = https://auth.test.movieflow.ai -NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com -NEXT_PUBLIC_CUT_URL = https://77.smartcut.py.qikongjian.com -NEXT_PUBLIC_GOOGLE_REDIRECT_URI=https://www.movieflow.net/api/auth/google/callback -NEXT_PUBLIC_CUT_URL_TO = https://smartcut.huiying.video +# NEXT_PUBLIC_JAVA_URL = https://auth.test.movieflow.ai +# NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com +# NEXT_PUBLIC_CUT_URL = https://77.smartcut.py.qikongjian.com +# NEXT_PUBLIC_GOOGLE_REDIRECT_URI=https://www.movieflow.net/api/auth/google/callback +# NEXT_PUBLIC_CUT_URL_TO = https://smartcut.huiying.video # 生产 -# NEXT_PUBLIC_JAVA_URL = https://auth.movieflow.ai -# NEXT_PUBLIC_BASE_URL = https://api.video.movieflow.ai -# NEXT_PUBLIC_CUT_URL = https://smartcut.api.movieflow.ai -# NEXT_PUBLIC_GOOGLE_REDIRECT_URI=https://www.movieflow.ai/api/auth/google/callback -# NEXT_PUBLIC_CUT_URL_TO = https://smartcut.movieflow.ai +NEXT_PUBLIC_JAVA_URL = https://auth.movieflow.ai +NEXT_PUBLIC_BASE_URL = https://api.video.movieflow.ai +NEXT_PUBLIC_CUT_URL = https://smartcut.api.movieflow.ai +NEXT_PUBLIC_GOOGLE_REDIRECT_URI=https://www.movieflow.ai/api/auth/google/callback +NEXT_PUBLIC_CUT_URL_TO = https://smartcut.movieflow.ai # 通用 # 当前域名配置 NEXT_PUBLIC_FRONTEND_URL = https://www.movieflow.ai 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 2/2] =?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, }, });