From 1e64ef96f78bc5cd159e6edb38a17561de49119e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BF=97=E5=BC=BA?= <357099073@qq.com> Date: Mon, 5 Jan 2026 20:16:30 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/controller/LoginController.php | 28 +++- app/admin/controller/SystemController.php | 96 +++++++++++++ app/admin/model/System/SystemMenu.php | 25 ++++ app/index/controller/UserController.php | 27 +++- frontend/src/config/env.ts | 4 +- frontend/src/store/modules/user.ts | 157 ++++++++++++---------- route/app.php | 7 + 7 files changed, 264 insertions(+), 80 deletions(-) create mode 100644 app/admin/controller/SystemController.php create mode 100644 app/admin/model/System/SystemMenu.php diff --git a/app/admin/controller/LoginController.php b/app/admin/controller/LoginController.php index 775df20..7e215b8 100644 --- a/app/admin/controller/LoginController.php +++ b/app/admin/controller/LoginController.php @@ -137,9 +137,35 @@ class LoginController extends Base AdminUser::where('uid', $aUser['uid'])->update( ['login_count' => $aUser['login_count'] + 1, 'update_time' => time()] ); + // 生成token(简单的base64编码,包含用户ID和时间戳) + $tokenData = [ + 'user_id' => $aUser['uid'], + 'timestamp' => time(), + 'random' => rand(100000, 999999) + ]; + $token = base64_encode(json_encode($tokenData)); + // 记录登录成功日志 $this->recordLoginLog($account, 1); - return json(['code' => 0, 'msg' => '登录成功', 'data' => []]); + + return json([ + 'code' => 0, + 'msg' => '登录成功', + 'data' => [ + 'token' => $token, + 'user_info' => [ + 'id' => $aUser['uid'], + 'account' => $aUser['account'], + 'name' => $aUser['name'], + 'avatar' => $aUser['avatar'] ?? '/static/images/avatar.png', + 'phone' => $aUser['phone'] ?? '', + 'sex' => $aUser['sex'] ?? 1, + 'qq' => $aUser['qq'] ?? '', + 'wechat' => $aUser['wechat'] ?? '', + 'create_time' => $aUser['create_time'] ?? 0 + ] + ] + ]); } } diff --git a/app/admin/controller/SystemController.php b/app/admin/controller/SystemController.php new file mode 100644 index 0000000..9387a69 --- /dev/null +++ b/app/admin/controller/SystemController.php @@ -0,0 +1,96 @@ +order('sort', 'asc') + ->order('id', 'asc') + ->select() + ->toArray(); + + // 按父子关系组织菜单 + $menuTree = $this->buildMenuTree($menus); + + // 直接输出JSON响应 + header('Content-type: application/json'); + echo json_encode([ + 'code' => 0, + 'msg' => '获取菜单列表成功', + 'data' => $menuTree + ]); + exit; + + } catch (\Exception $e) { + header('Content-type: application/json'); + echo json_encode([ + 'code' => 1, + 'msg' => '获取菜单列表失败:' . $e->getMessage() + ]); + exit; + } + } + + // 递归构建菜单树 + private function buildMenuTree($menus, $parentId = 0) + { + $tree = []; + + foreach ($menus as $menu) { + if ($menu['pid'] == $parentId) { + $children = $this->buildMenuTree($menus, $menu['id']); + + $menuItem = [ + 'id' => $menu['id'], + 'pid' => $menu['pid'], + 'name' => $menu['name'] ?? '', + 'title' => $menu['title'] ?? '', + 'icon' => $menu['icon'] ?? '', + 'path' => $menu['path'] ?? '', + 'component' => $menu['component'] ?? '', + 'redirect' => $menu['redirect'] ?? '', + 'sort' => $menu['sort'] ?? 0, + 'status' => $menu['status'] ?? 1, + 'type' => $menu['type'] ?? 0 + ]; + + if (!empty($children)) { + $menuItem['children'] = $children; + } + + $tree[] = $menuItem; + } + } + + return $tree; + } +} \ No newline at end of file diff --git a/app/admin/model/System/SystemMenu.php b/app/admin/model/System/SystemMenu.php new file mode 100644 index 0000000..e153fde --- /dev/null +++ b/app/admin/model/System/SystemMenu.php @@ -0,0 +1,25 @@ +account, 'info'); + // 生成token(简单的base64编码,包含用户ID和时间戳) + $tokenData = [ + 'user_id' => $user->id, + 'timestamp' => time(), + 'random' => rand(100000, 999999) + ]; + $token = base64_encode(json_encode($tokenData)); + // 返回用户信息给前端缓存 return json([ 'code' => 0, 'msg' => '登录成功', 'data' => [ - 'uid' => $user->uid, - 'user_name' => $user->name, - 'user_account' => $user->account, - 'user_avatar' => $user->avatar ?? '/static/images/avatar.png', - 'login_time' => time() + 'token' => $token, + 'user_info' => [ + 'id' => $user->id, + 'account' => $user->account, + 'name' => $user->name, + 'avatar' => $user->avatar ?? '/static/images/avatar.png', + 'phone' => $user->phone ?? '', + 'sex' => $user->sex ?? 1, + 'qq' => $user->qq ?? '', + 'wechat' => $user->wechat ?? '', + 'create_time' => $user->create_time ?? 0 + ] ] ]); @@ -183,6 +198,8 @@ class UserController extends BaseController $cookies = [ 'user_id', 'user_account', + 'user-store', + 'appfastnav', 'user_name', 'user_avatar', 'expire_time', diff --git a/frontend/src/config/env.ts b/frontend/src/config/env.ts index 8e5976b..4ae542e 100644 --- a/frontend/src/config/env.ts +++ b/frontend/src/config/env.ts @@ -2,7 +2,7 @@ const ENV_CONFIG = { // API配置 - API_BASE_URL: import.meta.env.VITE_APP_API_BASE_URL || (import.meta.env.DEV ? 'http://localhost:8000/api' : 'https://www.yunzer.cn/api'), + API_BASE_URL: import.meta.env.VITE_APP_API_BASE_URL, REQUEST_TIMEOUT: 10000, // 应用配置 @@ -11,6 +11,8 @@ const ENV_CONFIG = { // 本地存储key TOKEN_KEY: 'admin_token', USER_INFO_KEY: 'admin_user_info', + USER_STORE_KEY: 'user-store', + APPFASTNAV_KEY: 'appfastnav', // 是否为开发环境 IS_DEV: import.meta.env.DEV, diff --git a/frontend/src/store/modules/user.ts b/frontend/src/store/modules/user.ts index 9414796..e47da83 100644 --- a/frontend/src/store/modules/user.ts +++ b/frontend/src/store/modules/user.ts @@ -1,36 +1,40 @@ -import { defineStore } from 'pinia' -import { login as loginApi, getUserInfo as getUserInfoApi, logout as logoutApi } from '@/api/user' -import ENV_CONFIG from '@/config/env' +import { defineStore } from "pinia"; +import { + login as loginApi, + getUserInfo as getUserInfoApi, + logout as logoutApi, +} from "@/api/user"; +import ENV_CONFIG from "@/config/env"; interface LoginForm { - account: string - password: string + account: string; + password: string; } interface UserInfo { - id: number - account: string - name: string - avatar?: string - phone?: string - sex?: number - qq?: string - wechat?: string - create_time?: number + id: number; + account: string; + name: string; + avatar?: string; + phone?: string; + sex?: number; + qq?: string; + wechat?: string; + create_time?: number; } interface LoginResponse { - token: string - user_info: UserInfo + token: string; + user_info: UserInfo; } -const useUserStore = defineStore('user', { +const useUserStore = defineStore("user", { state: () => { return { - token: '', + token: "", userInfo: null as UserInfo | null, - isLogin: false - } + isLogin: false, + }; }, getters: { @@ -39,40 +43,45 @@ const useUserStore = defineStore('user', { // 获取token getToken: (state) => state.token, // 是否已登录 - getIsLogin: (state) => state.isLogin + getIsLogin: (state) => state.isLogin, }, actions: { // 用户登录 async userLogin(loginForm: LoginForm) { try { - const response = await loginApi(loginForm) as unknown as LoginResponse - + const response = (await loginApi( + loginForm + )) as unknown as LoginResponse; + // 后端返回格式为 { token: string, user_info: UserInfo } if (response && response.token && response.user_info) { - const { token, user_info } = response - + const { token, user_info } = response; + // 保存登录状态 - this.token = token - this.userInfo = user_info - this.isLogin = true - + this.token = token; + this.userInfo = user_info; + this.isLogin = true; + // 保存到 localStorage - localStorage.setItem(ENV_CONFIG.TOKEN_KEY, token) - localStorage.setItem(ENV_CONFIG.USER_INFO_KEY, JSON.stringify(user_info)) - - return user_info + localStorage.setItem(ENV_CONFIG.TOKEN_KEY, token); + localStorage.setItem( + ENV_CONFIG.USER_INFO_KEY, + JSON.stringify(user_info) + ); + + return user_info; } else { - throw new Error('登录响应数据格式错误') + throw new Error("登录响应数据格式错误"); } } catch (error: any) { // 处理不同类型的错误 if (error.response?.data?.msg) { - throw new Error(error.response.data.msg) + throw new Error(error.response.data.msg); } else if (error.message) { - throw new Error(error.message) + throw new Error(error.message); } else { - throw new Error('登录失败,请稍后重试') + throw new Error("登录失败,请稍后重试"); } } }, @@ -80,54 +89,54 @@ const useUserStore = defineStore('user', { // 用户登出 async userLogout() { try { - await logoutApi() + await logoutApi(); } catch (error) { - console.error('登出API调用失败:', error) + console.error("登出API调用失败:", error); } finally { - this.token = '' - this.userInfo = null - this.isLogin = false - + this.token = ""; + this.userInfo = null; + this.isLogin = false; + // 清除 localStorage - localStorage.removeItem(ENV_CONFIG.TOKEN_KEY) - localStorage.removeItem(ENV_CONFIG.USER_INFO_KEY) + localStorage.removeItem(ENV_CONFIG.TOKEN_KEY); + localStorage.removeItem(ENV_CONFIG.USER_INFO_KEY); } }, // 初始化用户状态(从 localStorage 恢复) async initUserState() { - const token = localStorage.getItem(ENV_CONFIG.TOKEN_KEY) - const userInfoStr = localStorage.getItem(ENV_CONFIG.USER_INFO_KEY) - + const token = localStorage.getItem(ENV_CONFIG.TOKEN_KEY); + const userInfoStr = localStorage.getItem(ENV_CONFIG.USER_INFO_KEY); + if (token && userInfoStr) { try { // 验证token是否有效 - const response = await getUserInfoApi() as unknown as UserInfo - + const response = (await getUserInfoApi()) as unknown as UserInfo; + if (response && response.id) { - this.token = token - this.userInfo = response - this.isLogin = true + this.token = token; + this.userInfo = response; + this.isLogin = true; } else { // token无效,清除本地存储但不调用logout API - this.clearUserState() + this.clearUserState(); } } catch (error: any) { - console.error('获取用户信息失败:', error) + console.error("获取用户信息失败:", error); // 如果有本地token和用户信息,先保持登录状态 // 只有在明确知道token无效时才清除 if (error.response?.status === 401) { - this.clearUserState() + this.clearUserState(); } else { // 网络错误或其他错误,使用本地存储的数据 try { - const userInfo = JSON.parse(userInfoStr) - this.token = token - this.userInfo = userInfo - this.isLogin = true + const userInfo = JSON.parse(userInfoStr); + this.token = token; + this.userInfo = userInfo; + this.isLogin = true; } catch (parseError) { // 本地数据解析失败,清除状态 - this.clearUserState() + this.clearUserState(); } } } @@ -136,21 +145,23 @@ const useUserStore = defineStore('user', { // 清除用户状态(不调用API) clearUserState() { - this.token = '' - this.userInfo = null - this.isLogin = false - + this.token = ""; + this.userInfo = null; + this.isLogin = false; + // 清除 localStorage - localStorage.removeItem(ENV_CONFIG.TOKEN_KEY) - localStorage.removeItem(ENV_CONFIG.USER_INFO_KEY) - } + localStorage.removeItem(ENV_CONFIG.TOKEN_KEY); + localStorage.removeItem(ENV_CONFIG.USER_INFO_KEY); + localStorage.removeItem(ENV_CONFIG.USER_STORE_KEY); + localStorage.removeItem(ENV_CONFIG.APPFASTNAV_KEY); + }, }, persist: { - key: 'user-store', + key: "user-store", storage: localStorage, - paths: ['token', 'userInfo', 'isLogin'] - } -}) + paths: ["token", "userInfo", "isLogin"], + }, +}); -export default useUserStore \ No newline at end of file +export default useUserStore; diff --git a/route/app.php b/route/app.php index c848346..99639e1 100644 --- a/route/app.php +++ b/route/app.php @@ -66,3 +66,10 @@ Route::group('api', function () { // 发布文章接口 Route::post('articles/publish', 'index/Articles/publishArticle'); })->middleware(\app\middleware\Cors::class); + + +// ADMIN路由组 +Route::group('admin', function () { + // 系统管理 + Route::get('system/getMenuList', 'admin/System/getMenuList'); +})->middleware(\app\middleware\Cors::class); \ No newline at end of file