From 92d64253334ddb528c2a1aed24904cf44753f714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E9=BE=99?= Date: Thu, 28 Aug 2025 22:18:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=8D=E6=AC=A1=E4=BF=AE=E5=A4=8D=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 1 + .env.production | 1 + app/signup/page.tsx | 237 +++++++++++++++++++------------- components/auth/auth-guard.tsx | 2 +- components/pages/home-page2.tsx | 68 ++++----- lib/auth.ts | 193 ++++++++++++++++++++++---- 6 files changed, 344 insertions(+), 158 deletions(-) diff --git a/.env.development b/.env.development index b224243..e9c8845 100644 --- a/.env.development +++ b/.env.development @@ -1,2 +1,3 @@ +NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com NEXT_PUBLIC_API_BASE_URL = https://77.api.qikongjian.com diff --git a/.env.production b/.env.production index f08d3ab..8cbf1fd 100644 --- a/.env.production +++ b/.env.production @@ -1,3 +1,4 @@ # NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com NEXT_PUBLIC_BASE_URL = https://pre.movieflow.api.huiying.video NEXT_PUBLIC_API_BASE_URL = https://77.api.qikongjian.com +NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com diff --git a/app/signup/page.tsx b/app/signup/page.tsx index 4d6864d..c170c7d 100644 --- a/app/signup/page.tsx +++ b/app/signup/page.tsx @@ -3,12 +3,14 @@ import React, { useState } from 'react'; import { useRouter } from 'next/navigation'; import Link from 'next/link'; -import { signInWithGoogle } from '@/lib/auth'; +import { signInWithGoogle, registerUser } from '@/lib/auth'; +import { GradientText } from '@/components/ui/gradient-text'; export default function SignupPage() { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); + const [inviteCode, setInviteCode] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); const [formError, setFormError] = useState(''); const router = useRouter(); @@ -17,19 +19,21 @@ export default function SignupPage() { e.preventDefault(); setIsSubmitting(true); setFormError(''); - + try { - // Here you would connect to your backend API for registration - console.log('Signing up', { name, email, password }); - - // Simulate successful registration - setTimeout(() => { - // Redirect to login page with success message - router.push('/login?registered=true'); - }, 1500); - } catch (error) { + // Use new registration API + await registerUser({ + userName: name, + email, + password, + inviteCode: inviteCode || undefined, + }); + + // Redirect to login page after successful registration + router.push('/login?registered=true'); + } catch (error: any) { console.error('Signup error:', error); - setFormError('Something went wrong. Please try again.'); + setFormError(error.message || 'Registration failed, please try again'); } finally { setIsSubmitting(false); } @@ -40,92 +44,137 @@ export default function SignupPage() { }; return ( -
-
-

Sign Up, for free

- -
-
- - setName(e.target.value)} - required - className="w-full px-4 py-3 rounded-lg bg-[#1c1e29] border border-gray-700 text-white focus:outline-none focus:ring-2 focus:ring-purple-500" - /> +
+ {/* 背景视频 */} + + + {/* 视频遮罩层 */} +
+ + {/* Logo */} +
+ + + + {/* beta标签 */} + + Beta + +
+ + {/* 注册框 - 居中显示 */} +
+
+
+

Sign Up, for free

+

Create your account to get started

- -
- - setEmail(e.target.value)} - required - className="w-full px-4 py-3 rounded-lg bg-[#1c1e29] border border-gray-700 text-white focus:outline-none focus:ring-2 focus:ring-purple-500" - /> + + +
+ + setName(e.target.value)} + required + className="w-full px-4 py-3 rounded-lg bg-black/30 border border-white/20 text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent" + /> +
+ +
+ + setEmail(e.target.value)} + required + className="w-full px-4 py-3 rounded-lg bg-black/30 border border-white/20 text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent" + /> +
+ +
+ + setPassword(e.target.value)} + required + className="w-full px-4 py-3 rounded-lg bg-black/30 border border-white/20 text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent" + /> +
+ +
+ + setInviteCode(e.target.value)} + className="w-full px-4 py-3 rounded-lg bg-black/30 border border-white/20 text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent" + /> +
+ + {formError && ( +
+ {formError} +
+ )} + +
+ + Back to login + + +
+ + +
+
+ or +
- -
- - setPassword(e.target.value)} - required - className="w-full px-4 py-3 rounded-lg bg-[#1c1e29] border border-gray-700 text-white focus:outline-none focus:ring-2 focus:ring-purple-500" - /> + + + +
+

+ Already have an account? Login +

- - {formError && ( -
{formError}
- )} - -
- - Back to home - - -
- - -
-
- or -
-
- - - - {/* Success message */} -
- Thank you! Your submission has been received! -
- - {/* Error message */} -
- Oops! Something went wrong while submitting the form.
); -} \ No newline at end of file +} diff --git a/components/auth/auth-guard.tsx b/components/auth/auth-guard.tsx index c5f7a38..4430fbb 100644 --- a/components/auth/auth-guard.tsx +++ b/components/auth/auth-guard.tsx @@ -16,7 +16,7 @@ export default function AuthGuard({ children }: AuthGuardProps) { const pathname = usePathname(); // 不需要鉴权的页面 - const publicPaths = ['/login', '/signup', '/forgot-password']; + const publicPaths = ['/','/login', '/signup', '/forgot-password']; const isPublicPath = publicPaths.includes(pathname); useEffect(() => { diff --git a/components/pages/home-page2.tsx b/components/pages/home-page2.tsx index 65828e1..19bad29 100644 --- a/components/pages/home-page2.tsx +++ b/components/pages/home-page2.tsx @@ -85,7 +85,7 @@ function HomeModule1() { return (
{/* 3x3网格布局 */}
-
+
))}
))} -
-
+
+
); } /**电影制作工序介绍 */ @@ -312,25 +312,25 @@ function HomeModule4() { title: "The Narrative Engine", description: " From a single thought, it builds entire worlds and compelling plots.", - video: "/assets/module4 (3).mp4", + video: "https://cdn.qikongjian.com/videos/module4 (3).mp4", }, { title: "AI Character Engine", description: "Cast your virtual actors. Lock them in once, for the entire story.", - video: "/assets/module4 (1).mp4", + video: "https://cdn.qikongjian.com/videos/module4 (1).mp4", }, { title: "AI vision engine", description: "It translates your aesthetic into art, light, and cinematography for every single shot.", - video: "/assets/module4 (4).mp4", + video: "https://cdn.qikongjian.com/videos/module4 (4).mp4", }, { title: "Intelligent Editing Engine", description: "An editing AI drives the final cut, for a story told seamlessly.", - video: "/assets/module4 (2).mp4", + video: "https://cdn.qikongjian.com/videos/module4 (2).mp4", }, ]; @@ -350,7 +350,7 @@ function HomeModule4() {

Edit like you think

- +
{/* 左侧四个切换tab */} @@ -476,8 +476,8 @@ function HomeModule5() { throw new Error("create checkout session failed"); } - setShowCallbackModal(true) - window.open(result.data.checkout_url, '_blank'); + setShowCallbackModal(true); + window.open(result.data.checkout_url, "_blank"); } catch (error) { throw new Error("create checkout session failed, please try again later"); } @@ -518,7 +518,7 @@ function HomeModule5() { Yearly - 10%
- + {/* 主要价格卡片 */}
diff --git a/lib/auth.ts b/lib/auth.ts index 1e111fa..b411296 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -1,10 +1,11 @@ import { BASE_URL } from "@/api/constants"; +import { post } from "@/api/request"; // API配置 -const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || ''; - +const API_BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || ''; +const JAVA_BASE_URL = process.env.NEXT_PUBLIC_JAVA_URL || ''; // Token存储键 -const TOKEN_KEY = 'X-EASE-ADMIN-TOKEN'; +const TOKEN_KEY = 'token'; const USER_KEY = 'currentUser'; /** @@ -12,37 +13,26 @@ const USER_KEY = 'currentUser'; */ export const loginUser = async (email: string, password: string) => { try { - const response = await fetch(`${API_BASE_URL}/admin/login/signIn`, { + const response = await fetch(`${JAVA_BASE_URL}/api/user/login`, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ - userName: email, + username: email, password: password, }), }); const data = await response.json(); + console.log('data', data) + // 保存token到本地存储 + setToken(data.token); - if (data.code === '200' && data.status === 200) { - // 保存token到本地存储 - setToken(data.body.token); + const user = await getUserProfile(); - // 保存用户信息 - const user = { - id: data.body.userId, - name: data.body.userName, - email: email, - token: data.body.token, - }; - setUser(user); - - return user; - } else { - throw new Error(data.msg || '登录失败'); - } + return user; } catch (error) { console.error('Login failed:', error); throw error; @@ -59,7 +49,7 @@ export const checkAuth = async (): Promise => { } try { - const response = await fetch(`${API_BASE_URL}/admin/login/auth`, { + const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/admin/login/auth`, { method: 'POST', headers: { 'Accept': 'application/json', @@ -69,14 +59,14 @@ export const checkAuth = async (): Promise => { }); const data = await response.json(); + return true; + // if (data.code === '401' || data.status === 401) { + // // Token无效,清除本地存储 + // // clearAuthData(); + // // return false; + // } - if (data.code === '401' || data.status === 401) { - // Token无效,清除本地存储 - clearAuthData(); - return false; - } - - return data.code === '200' && data.status === 200; + // return data.code === '200' && data.status === 200; } catch (error) { console.error('Auth check failed:', error); return false; @@ -250,3 +240,148 @@ export const validateOAuthState = (state: string): boolean => { // Validate that the returned state matches what we stored return state === storedState; }; + +/** + * 获取用户信息 + * @returns {Promise} 用户信息对象 + */ +export const getUserProfile = async (): Promise => { + try { + const token = getToken(); + if (!token) { + throw new Error('No token available'); + } + + const response = await fetch(`${API_BASE_URL}/java-auth/profile`, { + method: 'GET', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}`, + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + + if (data.code === 0 && data.successful) { + // 更新本地存储的用户信息 + const userInfo = { + id: data.data.user_id, + userId: data.data.user_id, + username: data.data.username, + name: data.data.name, + email: data.data.email, + role: data.data.role, + isActive: data.data.is_active, + authType: data.data.auth_type, + lastLogin: data.data.last_login, + }; + + setUser(userInfo); + return userInfo; + } else { + throw new Error(data.message || 'Failed to get user profile'); + } + } catch (error) { + console.error('Get user profile failed:', error); + throw error; + } +}; + +/** + * 刷新用户信息 + * @returns {Promise} 最新的用户信息 + */ +export const refreshUserProfile = async (): Promise => { + try { + const profile = await getUserProfile(); + return profile; + } catch (error) { + console.error('Refresh user profile failed:', error); + // 如果刷新失败,返回本地存储的用户信息 + return getCurrentUser(); + } +}; + +/** + * 检查用户权限 + * @param {string} requiredRole 需要的角色权限 + * @returns {boolean} 是否有权限 + */ +export const checkUserPermission = (requiredRole: string): boolean => { + const user = getCurrentUser(); + if (!user || !user.role) { + return false; + } + + // 角色权限等级 + const roleHierarchy = { + 'ADMIN': 3, + 'MODERATOR': 2, + 'USER': 1, + }; + + const userRoleLevel = roleHierarchy[user.role as keyof typeof roleHierarchy] || 0; + const requiredRoleLevel = roleHierarchy[requiredRole as keyof typeof roleHierarchy] || 0; + + return userRoleLevel >= requiredRoleLevel; +}; + +/** + * 检查用户是否激活 + * @returns {boolean} 用户是否激活 + */ +export const isUserActive = (): boolean => { + const user = getCurrentUser(); + return user?.isActive === 1; +}; +/** + * 用户注册 + * @param {Object} params - 注册参数 + * @param {string} params.userName - 用户名 + * @param {string} params.password - 密码 + * @param {string} params.email - 邮箱 + * @param {string} [params.inviteCode] - 邀请码(可选) + * @returns {Promise} 注册结果 + * @throws {Error} 注册失败时抛出异常 + */ +export const registerUser = async ({ + userName, + password, + email, + inviteCode, +}: { + userName: string; + password: string; + email: string; + inviteCode?: string; +}): Promise => { + try { + const response = await fetch(`${JAVA_BASE_URL}/api/user/register`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + userName, + password, + email, + inviteCode, + }), + }); + + const data = await response.json(); + + return data as { + success: boolean; + }; + } catch (error) { + console.error('Register failed:', error); + throw error; + } +};