diff --git a/src/lib/api/services/authService.ts b/src/lib/api/services/authService.ts index f11c76e..c060a4d 100644 --- a/src/lib/api/services/authService.ts +++ b/src/lib/api/services/authService.ts @@ -1,8 +1,8 @@ import { api } from '$lib/api/httpClient'; // 通常不需要 .ts 后缀 import type { AuthResponse, LoginPayload } from '$lib/types/auth'; import { authStore } from '$lib/stores/authStore'; -import { userService } from '$lib/api/services/userService'; import { toast } from '$lib/stores/toastStore'; +import { ResponseError } from '$lib/types/error.ts'; export const authService = { /** @@ -13,33 +13,16 @@ export const authService = { const response = await api.post('/auth/login', payload); if (response.code !== 200 || !response.data) { - throw new Error(response.msg || '登录失败'); + throw new ResponseError(response); } - const { token, tokenHead } = response.data; + const { token, tokenHead,userProfile } = response.data; - authStore.update(s => ({ ...s, token, tokenHead, isAuthenticated: true })); + authStore.update(s => ({ ...s, token, tokenHead, isAuthenticated: true,user: userProfile })); - try { - // 3. 获取用户信息 - const userProfile = await userService.getUserProfile({tokenHead,token}); - // 4. 最终确认登录状态(更新完整信息并持久化) - // 这里调用 Store 封装好的 login 方法,它会负责写入 localStorage - authStore.login({ - token, - tokenHead, - user: userProfile - }); + return response.data; - return response.data; - - } catch (error) { - - console.error('获取用户信息失败,回滚登录状态', error); - authStore.logout(); - throw error; // 继续抛出错误给 UI 层处理 - } }, /** diff --git a/src/lib/types/api.ts b/src/lib/types/api.ts index c9caed6..6acf1f5 100644 --- a/src/lib/types/api.ts +++ b/src/lib/types/api.ts @@ -1,5 +1,18 @@ +import type { ActionResult } from '@sveltejs/kit'; + export interface ApiResult { code: number, msg: string, data: T | null; +} + + +export type EnhanceResult = ActionResult & { + status: number; + type: "failure" | "success" | "redirect" | "error"; + data: T; +} +export interface LoginFailure { + message: string; + username: string; } \ No newline at end of file diff --git a/src/lib/types/auth.ts b/src/lib/types/auth.ts index e12d952..8275c0d 100644 --- a/src/lib/types/auth.ts +++ b/src/lib/types/auth.ts @@ -1,4 +1,6 @@ import type { JsonObject } from '$lib/types/http.ts'; +import type { UserProfile } from '$lib/types/user.ts'; + export interface LoginPayload extends JsonObject { username: string; @@ -8,4 +10,6 @@ export interface LoginPayload extends JsonObject { export interface AuthResponse { token: string; tokenHead: string; -} \ No newline at end of file + userProfile: UserProfile; +} + diff --git a/src/lib/types/error.ts b/src/lib/types/error.ts index e56081a..504ae94 100644 --- a/src/lib/types/error.ts +++ b/src/lib/types/error.ts @@ -1,3 +1,5 @@ +import type { ApiResult } from '$lib/types/api.ts'; + export interface ApiError { status: number; details: { @@ -5,4 +7,16 @@ export interface ApiError { msg: string; }; name: string; -} \ No newline at end of file +} + +export class ResponseError extends Error { + code: number; + msg: string; + + constructor(response: ApiResult) { + super(response.msg); + this.code = response.code; + this.msg = response.msg; + } +} + diff --git a/src/lib/utils/auth.ts b/src/lib/utils/auth.ts deleted file mode 100644 index 73c1745..0000000 --- a/src/lib/utils/auth.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {user} from '$lib/stores/userStore'; -import {get} from 'svelte/store'; - -export const hasRole = (role: string[]) => { - const userProfile = get(user); - - if (!userProfile){ - return false; - } - return role.some(r => userProfile.roles.includes(r)) -}; \ No newline at end of file diff --git a/src/lib/utils/errorUtils.ts b/src/lib/utils/errorUtils.ts new file mode 100644 index 0000000..9f1e12f --- /dev/null +++ b/src/lib/utils/errorUtils.ts @@ -0,0 +1,14 @@ +import { HttpError } from '$lib/api/httpClient.ts'; +import { fail } from '@sveltejs/kit'; + +export const handleError = (error: Error) => { + if (error instanceof HttpError) { + return fail(error.s, { + message: error.details?.msg || '认证失败,请检查凭证' + }); + + + if (error instanceof TypeError || (error instanceof Error && error.message.includes('fetch'))) { + return { message: '无法连接服务器,请检查网络' }; + } +}; \ No newline at end of file diff --git a/src/routes/auth/login/+page.server.ts b/src/routes/auth/login/+page.server.ts index 9325408..6f4555d 100644 --- a/src/routes/auth/login/+page.server.ts +++ b/src/routes/auth/login/+page.server.ts @@ -1,39 +1,82 @@ import type { Actions } from './$types'; import { fail } from '@sveltejs/kit'; import { authService } from '$lib/api/services/authService.ts'; +import { resolve } from '$app/paths'; import { HttpError } from '$lib/api/httpClient.ts'; -import type { ApiError } from '$lib/types/error.ts'; +import { type ApiError, ResponseError } from '$lib/types/error.ts'; export const actions:Actions = { - default: async ({ request,cookies }) => { + default: async ({ request,cookies ,url}) => { const formData = await request.formData(); - const username = formData.get('username') as string; - const password = formData.get('password') as string; + const username = formData.get('username'); + const password = formData.get('password'); - if (!username || !password) { - return fail(400, {missing:true}) + if ( + typeof username !== 'string' || + typeof password !== 'string' || + !username.trim() || + !password.trim() + ){ + return fail(400,{ + missing: true, + message: '请填写用户名和密码', + username: username?.toString() ?? '' + }) } + try{ + const response = await authService.login({username,password}); - try { - const authResponse = await authService.login({username, password}); - - - cookies.set('auth_token', authResponse.token, { + cookies.set('Authorization',`${response.tokenHead} ${response.token}`,{ path: '/', httpOnly: true, sameSite: 'strict', - secure: import.meta.env.PROD, - maxAge: 60 * 60 * 24 * 7 // 7 days + secure: process.env.NODE_ENV === 'production', + maxAge: 60 * 60 * 24 * 7 }); - return {success:true}; - }catch ( error){ - if (error instanceof HttpError){ - const apiError = error as unknown as ApiError; - return fail(400, {message:apiError.details.msg}); + + return { + success: true, + message: '登录成功', + redirectTo: url.searchParams.get('redirectTo') ?? resolve("/app/dashboard") + }; + + }catch (error){ + if (error instanceof HttpError) { + + const msg = (error as unknown as ApiError)?.details?.msg || '登录失败,请检查账号密码'; + + return fail(400, { + incorrect: true, + message: msg, + username // 返回用户名供用户修改 + }); } + + if (error instanceof TypeError || (error instanceof Error && error.message.includes('fetch'))) { + return fail(503, { + message: '网络连接失败,无法连接到服务器', + username + }); + } + + if (error instanceof ResponseError ){ + return fail(error.code, { + message: error.msg, + username + }); + } + // 4. 兜底的未知错误处理 + console.error('Login unexpected error:', error); + return fail(500, { + message: '系统内部错误,请稍后再试', + username + }); + + + } } diff --git a/src/routes/auth/login/+page.svelte b/src/routes/auth/login/+page.svelte index cff56a7..ad0f499 100644 --- a/src/routes/auth/login/+page.svelte +++ b/src/routes/auth/login/+page.svelte @@ -1,8 +1,11 @@ @@ -17,16 +20,25 @@ IT DTMS登录 - {#if form?.message} -
- {form.message} -
- {/if} -
+ + + { + return async ({ result , update }) => { + const res = result as EnhanceResult; + if (res.status === 200) { + toast.success('登录成功'); + update(); + } else { + toast.error(res.data.message); + } + }; + }} + class="space-y-4">
-