diff --git a/src/shared/api/auth.ts b/src/shared/api/auth.ts index 813db66..8369f67 100644 --- a/src/shared/api/auth.ts +++ b/src/shared/api/auth.ts @@ -13,9 +13,18 @@ export interface UserInfo { user_type: string } +// 辅助函数:从cookie字符串中读取指定名称的cookie值 +function getCookie(name: string): string | null { + const value = `; ${document.cookie}` + const parts = value.split(`; ${name}=`) + if (parts.length === 2) { + return parts.pop()?.split(';').shift() || null + } + return null +} + export function getSessionUser(): string | null { - const cookies = new URLSearchParams(document.cookie.split('; ').join('&')) - const sessionUser = cookies.get('user_id') + const sessionUser = getCookie('user_id') if (!sessionUser || sessionUser === 'Guest') { return null } @@ -23,8 +32,34 @@ export function getSessionUser(): string | null { } export function getSessionCookie(): string | null { - const cookies = new URLSearchParams(document.cookie.split('; ').join('&')) - return cookies.get('sid') + return getCookie('sid') +} + +// 从cookie中获取用户信息 +export function getUserInfoFromCookies(): UserInfo | null { + const userId = getCookie('user_id') + const fullName = getCookie('full_name') || '' + const userImage = getCookie('user_image') || '' + const systemUser = getCookie('system_user') + + if (!userId || userId === 'Guest') { + return null + } + + // 解析 full_name 为 first_name 和 last_name + const nameParts = fullName.split(' ') + const firstName = nameParts[0] || '' + const lastName = nameParts.slice(1).join(' ') || '' + + return { + id: userId, + username: userId, + email: '', + avatar: userImage, + first_name: firstName, + last_name: lastName, + user_type: systemUser === 'yes' ? 'System User' : 'Website User' + } } // 检查cookie是否过期(通过检查session cookie是否存在) @@ -34,72 +69,142 @@ export function isCookieExpired(): boolean { } export const loginApi = async (username: string, password: string): Promise => { - const response = await fetch(`/jingrow/login`, { + // 使用表单编码格式,匹配后端期望的格式 + const formData = new URLSearchParams() + formData.append('cmd', 'login') + formData.append('usr', username) + formData.append('pwd', password) + + const response = await fetch(`/api/action/login`, { method: 'POST', headers: { - 'Content-Type': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json' }, credentials: 'include', - body: JSON.stringify({ - username: username, - password: password - }) + body: formData }) if (!response.ok) { const errorData = await response.json().catch(() => ({})) - throw new Error(errorData.detail || errorData.message || '登录请求失败') + throw new Error(errorData.detail || errorData.message || errorData.exc || '登录请求失败') } const data = await response.json() - if (data.success && data.user) { - return { message: data.message || 'Logged In', user: data.user } + // 后端登录成功会返回 message: "Logged In" 或 "No App" + // "No App" 表示登录成功但用户类型是 Website User + if (response.status === 200 && (data.message === 'Logged In' || data.message === 'No App')) { + // 直接从登录响应构建用户信息 + // 解析 full_name 为 first_name 和 last_name + const nameParts = (data.full_name || '').split(' ') + const firstName = nameParts[0] || '' + const lastName = nameParts.slice(1).join(' ') || '' + + // 使用登录时的用户名作为用户ID和用户名 + const userInfo: UserInfo = { + id: username, + username: username, + email: '', + avatar: '', + first_name: firstName, + last_name: lastName, + user_type: data.message === 'No App' ? 'Website User' : 'System User' + } + + // 尝试获取更完整的用户信息(可选,如果失败也不影响登录) + try { + // 等待一小段时间让session建立 + await new Promise(resolve => setTimeout(resolve, 200)) + const detailedUserInfo = await getUserInfoApi() + // 如果API返回的用户信息有效(不是Guest),使用它 + if (detailedUserInfo.id && detailedUserInfo.id !== 'Guest') { + return { message: data.message || 'Logged In', user: detailedUserInfo } + } + } catch (error) { + // API调用失败不影响登录,使用基本用户信息 + } + + // 使用从登录响应构建的用户信息 + return { message: data.message || 'Logged In', user: userInfo } } else { - throw new Error(data.message || data.detail || '登录失败') + throw new Error(data.message || data.detail || data.exc || '登录失败') } } // 获取用户信息 export const getUserInfoApi = async (): Promise => { - const response = await fetch(`/jingrow/user-info`, { - method: 'GET', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - credentials: 'include' - }) + try { + const response = await fetch(`/api/action/jingrow.realtime.get_user_info`, { + method: 'GET', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + credentials: 'include' + }) - if (!response.ok) { - // 401或403表示cookie过期或未授权 - if (response.status === 401 || response.status === 403) { - const error = new Error('Cookie已过期,请重新登录') - // @ts-ignore - error.status = response.status - throw error + if (!response.ok) { + // 401或403表示cookie过期或未授权 + if (response.status === 401 || response.status === 403) { + const error = new Error('Cookie已过期,请重新登录') + // @ts-ignore + error.status = response.status + throw error + } + // 其他错误,尝试从cookie获取 + const fallbackInfo = getUserInfoFromCookies() + if (fallbackInfo) { + return fallbackInfo + } + const errorData = await response.json().catch(() => ({})) + throw new Error(errorData.detail || errorData.message || '获取用户信息失败') } - const errorData = await response.json().catch(() => ({})) - throw new Error(errorData.detail || errorData.message || '获取用户信息失败') - } - const data = await response.json() - - if (data.success && data.user_info) { - return data.user_info - } else { - throw new Error(data.message || data.detail || '获取用户信息失败') + const data = await response.json() + + // 根据Python代码,用户信息在 message 字段中,如果没有则使用整个 data + const userInfo = data.message || data + + // 格式化用户信息,匹配Python代码的逻辑 + const formattedUserInfo: UserInfo = { + id: userInfo.user || userInfo.name || userInfo.username || '', + username: userInfo.user || userInfo.name || userInfo.username || '', + email: userInfo.email || '', + avatar: userInfo.user_image || '', + first_name: userInfo.first_name || '', + last_name: userInfo.last_name || '', + user_type: userInfo.user_type || 'System User' + } + + // 如果格式化后的用户信息有效,返回它 + if (formattedUserInfo.id && formattedUserInfo.id !== 'Guest') { + return formattedUserInfo + } + + // 如果格式化失败,尝试从cookie获取 + const fallbackInfo = getUserInfoFromCookies() + if (fallbackInfo) { + return fallbackInfo + } + + throw new Error('无法解析用户信息') + } catch (error: any) { + // 网络错误或其他异常,尝试从cookie获取 + const fallbackInfo = getUserInfoFromCookies() + if (fallbackInfo) { + return fallbackInfo + } + throw error } } // 登出 export const logoutApi = async (): Promise => { - const response = await fetch(`/jingrow/logout`, { - method: 'POST', + const response = await fetch(`/api/action/logout`, { + method: 'GET', headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' + 'Accept': 'application/json' }, credentials: 'include' }) diff --git a/vite.config.ts b/vite.config.ts index 6f6b2c8..f3b5460 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -14,6 +14,7 @@ const appsDir = path.resolve(currentDir, '..', '..') export default defineConfig(({ mode, command }) => { const env = loadEnv(mode, process.cwd(), '') const BACKEND_URL = env.VITE_BACKEND_SERVER_URL || 'https://api.jingrow.com' + const JCLOUD_URL = env.VITE_JCLOUD_SERVER_URL || 'https://cloud.jingrow.com' const FRONTEND_HOST = env.VITE_FRONTEND_HOST || '0.0.0.0' const FRONTEND_PORT = Number(env.VITE_FRONTEND_PORT) || 3100 const ALLOWED_HOSTS = (env.VITE_ALLOWED_HOSTS || '').split(',').map((s) => s.trim()).filter(Boolean) @@ -65,12 +66,12 @@ export default defineConfig(({ mode, command }) => { }, proxy: { '/api': { - target: BACKEND_URL, + target: JCLOUD_URL, changeOrigin: true, secure: true, }, '/jingrow': { - target: BACKEND_URL, + target: JCLOUD_URL, changeOrigin: true, secure: true, },