diff --git a/.env b/.env index 7518860..2ae3c1c 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -VITE_API_BASE_URL=http://your-api-url.com \ No newline at end of file +VITE_API_BASE_URL=http://localhost:3000 \ No newline at end of file diff --git a/auto-imports.d.ts b/auto-imports.d.ts index 319befa..8c26771 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -22,6 +22,7 @@ declare global { const isReadonly: typeof import('vue')['isReadonly'] const isRef: typeof import('vue')['isRef'] const login: typeof import('./src/api/loginApi')['login'] + const loginApiTest: typeof import('./src/api/loginApi')['loginApiTest'] const markRaw: typeof import('vue')['markRaw'] const nextTick: typeof import('vue')['nextTick'] const onActivated: typeof import('vue')['onActivated'] diff --git a/src/api/loginApi.ts b/src/api/loginApi.ts index e54c37a..331132c 100644 --- a/src/api/loginApi.ts +++ b/src/api/loginApi.ts @@ -1,7 +1,10 @@ import http from "@/utils/request"; //demo -export const login = () => { - return http.get('/get-user') +export const loginApiTest = () => { + return http({ + url:'/search', + method:'get' + }) } diff --git a/src/assets/images/home_bg.webp b/src/assets/images/home_bg.webp new file mode 100644 index 0000000..171283f Binary files /dev/null and b/src/assets/images/home_bg.webp differ diff --git a/src/assets/styles/common.scss b/src/assets/styles/common.scss index e69de29..b6dded2 100644 --- a/src/assets/styles/common.scss +++ b/src/assets/styles/common.scss @@ -0,0 +1,12 @@ +.main__container { + height: 100%; + width: 100%; + &.table { + overflow: hidden; //表格需要hidden + } + &.white-bg { + background: #fff; + border-radius: 8px; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); + } +} diff --git a/src/router/index.ts b/src/router/index.ts index a13814c..7543d49 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,9 +1,16 @@ import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router"; +import NProgress from "nprogress"; // progress bar +import "nprogress/nprogress.css"; // progress bar style + import Login from "@/views/login/index.vue"; //登录组件 import Layout from "@/views/layout/index.vue"; //首页布局 import CallBack from "@/views/login/OauthCallBack.vue"; //反馈页面 -import Home from '@/views/home/index.vue'; //家 -import Auth from '@/views/role/pages/Auth.vue'; //权限管理 +import Home from "@/views/home/index.vue"; //家 +import Auth from "@/views/role/pages/Auth.vue"; //权限管理 +import Menu from '@/views/system/menu/index.vue'; //动态权限菜单 +import { getToken } from "@/utils/auth"; + +const whiteList = ["/callback"]; const routes: Array = [ { @@ -20,19 +27,24 @@ const routes: Array = [ path: "/layout", name: "Layout", component: Layout, - children:[ + children: [ { - path:'', - name:'home', - component:Home, + path: "", + name: "home", + component: Home, }, // 后续用动态菜单 { - path:'role', - name:'roleAuth', - component:Auth - } - ] + path: "role", + name: "roleAuth", + component: Auth, + }, + { + path: "menu", + name: "menu", + component: Menu, + }, + ], }, ]; @@ -41,10 +53,20 @@ const router = createRouter({ routes, }); -// 在这里添加路由的导航守卫 router.beforeEach((to, from, next) => { - console.log("Navigating to:", to.path); - next(); + const token = getToken(); + NProgress.start(); + + if (to.path === "/") { + token ? next("/callback") : next(); // 有 token 直接去 /layout + } else if (whiteList.includes(to.path)) { + next(); // 放行 /callback + } else { + token ? next() : next("/"); // 其他页面检查 token + } +}); +router.afterEach(() => { + NProgress.done(); // finish progress bar }); export default router; diff --git a/src/utils/request.ts b/src/utils/request.ts index 531b08a..2f82c7f 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,5 +1,5 @@ -import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; -import { getToken, removeToken } from './auth'; +import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; +import { getToken, removeToken } from "./auth"; // 定义后端返回的统一数据结构 interface ApiResponse { @@ -8,106 +8,65 @@ interface ApiResponse { msg: string; } -// 创建 Axios 实例 -const createAxiosInstance = (): AxiosInstance => { - const instance = axios.create({ - baseURL: import.meta.env.VITE_API_BASE_URL as string, // 从 Vite 环境变量获取 baseURL - timeout: 10000, // 请求超时时间 - headers: { - 'Content-Type': 'application/json', - }, - }); +const instance = axios.create({ + baseURL: `${import.meta.env.VITE_API_BASE_URL as string}/api`, // 从 Vite 环境变量获取 baseURL + timeout: 10000, // 请求超时时间 + headers: { + "Content-Type": "application/json", + }, +}); - // 请求拦截器 - instance.interceptors.request.use( - (config) => { - // 添加 token 等请求头 - const token = getToken() - if (token) { - config.headers.Authorization = `Bearer ${token}`; - } - return config; - }, - (error) => { - return Promise.reject(error); +// 请求拦截器 +instance.interceptors.request.use( + (config) => { + // 添加 token 等请求头 + const token = getToken(); + if (token) { + config.headers.Authorization = `Bearer ${token}`; } - ); - - // 响应拦截器 - instance.interceptors.response.use( - (response: AxiosResponse) => { - const { code, msg } = response.data; - - // 401 未授权,跳转首页 - if (code === 401) { - // 这里调用退出登录的逻辑 - console.log('未授权,跳转首页'); - // 清除用户信息 - removeToken(); - // 跳转首页 - window.location.href = '/'; //后续用发布订阅模式修改 - return Promise.reject(new Error(msg || '未授权')); - } - - // 其他非 200 状态码 - if (code !== 200) { - console.error(`请求错误 ${code}: ${msg}`); - // 这里可以根据需要弹出错误提示 - return Promise.reject(new Error(msg || '请求错误')); - } - - // 返回数据部分 - return response.data.data; - }, - (error) => { - // 处理 HTTP 状态码不是 200 的情况 - if (error.response) { - const { status, data } = error.response; - console.error(`HTTP 错误 ${status}:`, data); - } else { - console.error('请求错误:', error.message); - } - return Promise.reject(error); - } - ); - - return instance; -}; - -const http = createAxiosInstance(); - -// 封装通用的 request 函数 -async function request(config: AxiosRequestConfig): Promise { - try { - const { data } = await http.request>(config); - return data.data; - } catch (error) { - // 这里可以统一处理错误,或者让调用者自己处理 - throw error; + return config; + }, + (error) => { + return Promise.reject(error); } -} +); -// 封装常用的 HTTP 方法 -const httpClient = { - get(url: string, config?: AxiosRequestConfig): Promise { - return request({ ...config, method: 'GET', url }); +// 响应拦截器 +instance.interceptors.response.use( + (response: AxiosResponse) => { + const { code, msg } = response.data; + + // 401 未授权,跳转首页 + if (code === 401) { + // 这里调用退出登录的逻辑 + console.log("未授权,跳转首页"); + // 清除用户信息 + removeToken(); + // 跳转首页 + window.location.href = "/"; //后续用发布订阅模式修改 + return Promise.reject(new Error(msg || "未授权")); + } + + // 其他非 200 状态码 + if (code !== 200) { + console.error(`请求错误 ${code}: ${msg}`); + // 这里可以根据需要弹出错误提示 + return Promise.reject(new Error(msg || "请求错误")); + } + + // 返回数据部分 + return response.data.data; }, + (error) => { + // 处理 HTTP 状态码不是 200 的情况 + if (error.response) { + const { status, data } = error.response; + console.error(`HTTP 错误 ${status}:`, data); + } else { + console.error("请求错误:", error.message); + } + return Promise.reject(error); + } +); - post(url: string, data?: any, config?: AxiosRequestConfig): Promise { - return request({ ...config, method: 'POST', url, data }); - }, - - put(url: string, data?: any, config?: AxiosRequestConfig): Promise { - return request({ ...config, method: 'PUT', url, data }); - }, - - delete(url: string, config?: AxiosRequestConfig): Promise { - return request({ ...config, method: 'DELETE', url }); - }, - - patch(url: string, data?: any, config?: AxiosRequestConfig): Promise { - return request({ ...config, method: 'PATCH', url, data }); - }, -}; - -export default httpClient; \ No newline at end of file +export default instance; diff --git a/src/views/home/index.vue b/src/views/home/index.vue index ea74d7c..9885d76 100644 --- a/src/views/home/index.vue +++ b/src/views/home/index.vue @@ -1,8 +1,12 @@ \ No newline at end of file diff --git a/src/views/layout/components/LayoutHeader.vue b/src/views/layout/components/LayoutHeader.vue index 24db979..62d6c54 100644 --- a/src/views/layout/components/LayoutHeader.vue +++ b/src/views/layout/components/LayoutHeader.vue @@ -24,6 +24,7 @@ \ No newline at end of file diff --git a/src/views/login/OauthCallBack.vue b/src/views/login/OauthCallBack.vue index fddc735..0051db1 100644 --- a/src/views/login/OauthCallBack.vue +++ b/src/views/login/OauthCallBack.vue @@ -20,7 +20,7 @@ const oSomethingWithToken = async () => { router.push('/layout'); } catch (error) { router.push('/'); - message.error('错误!'); + message.error(error.message); } } diff --git a/src/views/login/index.vue b/src/views/login/index.vue index b3527c4..ef7806b 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -28,7 +28,7 @@ 科技赋能 第五人格 陪玩产业链

- 基于.NET9 + Vue3的智能管理系统,为您提供全方位的数字化解决方案 + 基于.NET9 + Vue3技术栈研发的智能管理系统,为您提供全方位的数字化解决方案

@@ -67,7 +67,7 @@
- +
@@ -87,7 +87,7 @@
- +
@@ -136,7 +136,7 @@
杨某人
-
杨嚣张
+
杨校长
X电竞 校长
@@ -205,16 +205,24 @@ + \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index a5b21f8..4e12aa0 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -17,6 +17,15 @@ export default defineConfig({ dirs: ["./src/api"], }), ], + server:{ + proxy:{ + '/api':{ + target:'http://localhost:3000/api', + changeOrigin:true, + rewrite:(path) => path.replace(/^\api/,'') + } + }, + }, css: { preprocessorOptions: { scss: {