feat:大更新
This commit is contained in:
parent
b231b77043
commit
a29bba3406
2
.env
2
.env
@ -1 +1 @@
|
|||||||
VITE_API_BASE_URL=http://your-api-url.com
|
VITE_API_BASE_URL=http://localhost:3000
|
1
auto-imports.d.ts
vendored
1
auto-imports.d.ts
vendored
@ -22,6 +22,7 @@ declare global {
|
|||||||
const isReadonly: typeof import('vue')['isReadonly']
|
const isReadonly: typeof import('vue')['isReadonly']
|
||||||
const isRef: typeof import('vue')['isRef']
|
const isRef: typeof import('vue')['isRef']
|
||||||
const login: typeof import('./src/api/loginApi')['login']
|
const login: typeof import('./src/api/loginApi')['login']
|
||||||
|
const loginApiTest: typeof import('./src/api/loginApi')['loginApiTest']
|
||||||
const markRaw: typeof import('vue')['markRaw']
|
const markRaw: typeof import('vue')['markRaw']
|
||||||
const nextTick: typeof import('vue')['nextTick']
|
const nextTick: typeof import('vue')['nextTick']
|
||||||
const onActivated: typeof import('vue')['onActivated']
|
const onActivated: typeof import('vue')['onActivated']
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import http from "@/utils/request";
|
import http from "@/utils/request";
|
||||||
|
|
||||||
//demo
|
//demo
|
||||||
export const login = () => {
|
export const loginApiTest = () => {
|
||||||
return http.get('/get-user')
|
return http({
|
||||||
|
url:'/search',
|
||||||
|
method:'get'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
src/assets/images/home_bg.webp
Normal file
BIN
src/assets/images/home_bg.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 130 KiB |
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,16 @@
|
|||||||
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
|
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 Login from "@/views/login/index.vue"; //登录组件
|
||||||
import Layout from "@/views/layout/index.vue"; //首页布局
|
import Layout from "@/views/layout/index.vue"; //首页布局
|
||||||
import CallBack from "@/views/login/OauthCallBack.vue"; //反馈页面
|
import CallBack from "@/views/login/OauthCallBack.vue"; //反馈页面
|
||||||
import Home from '@/views/home/index.vue'; //家
|
import Home from "@/views/home/index.vue"; //家
|
||||||
import Auth from '@/views/role/pages/Auth.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<RouteRecordRaw> = [
|
const routes: Array<RouteRecordRaw> = [
|
||||||
{
|
{
|
||||||
@ -20,19 +27,24 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
path: "/layout",
|
path: "/layout",
|
||||||
name: "Layout",
|
name: "Layout",
|
||||||
component: Layout,
|
component: Layout,
|
||||||
children:[
|
children: [
|
||||||
{
|
{
|
||||||
path:'',
|
path: "",
|
||||||
name:'home',
|
name: "home",
|
||||||
component:Home,
|
component: Home,
|
||||||
},
|
},
|
||||||
// 后续用动态菜单
|
// 后续用动态菜单
|
||||||
{
|
{
|
||||||
path:'role',
|
path: "role",
|
||||||
name:'roleAuth',
|
name: "roleAuth",
|
||||||
component:Auth
|
component: Auth,
|
||||||
}
|
},
|
||||||
]
|
{
|
||||||
|
path: "menu",
|
||||||
|
name: "menu",
|
||||||
|
component: Menu,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -41,10 +53,20 @@ const router = createRouter({
|
|||||||
routes,
|
routes,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 在这里添加路由的导航守卫
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
console.log("Navigating to:", to.path);
|
const token = getToken();
|
||||||
next();
|
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;
|
export default router;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
|
||||||
import { getToken, removeToken } from './auth';
|
import { getToken, removeToken } from "./auth";
|
||||||
|
|
||||||
// 定义后端返回的统一数据结构
|
// 定义后端返回的统一数据结构
|
||||||
interface ApiResponse<T = any> {
|
interface ApiResponse<T = any> {
|
||||||
@ -8,21 +8,19 @@ interface ApiResponse<T = any> {
|
|||||||
msg: string;
|
msg: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建 Axios 实例
|
const instance = axios.create({
|
||||||
const createAxiosInstance = (): AxiosInstance => {
|
baseURL: `${import.meta.env.VITE_API_BASE_URL as string}/api`, // 从 Vite 环境变量获取 baseURL
|
||||||
const instance = axios.create({
|
|
||||||
baseURL: import.meta.env.VITE_API_BASE_URL as string, // 从 Vite 环境变量获取 baseURL
|
|
||||||
timeout: 10000, // 请求超时时间
|
timeout: 10000, // 请求超时时间
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 请求拦截器
|
// 请求拦截器
|
||||||
instance.interceptors.request.use(
|
instance.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
// 添加 token 等请求头
|
// 添加 token 等请求头
|
||||||
const token = getToken()
|
const token = getToken();
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
@ -31,29 +29,29 @@ const createAxiosInstance = (): AxiosInstance => {
|
|||||||
(error) => {
|
(error) => {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
instance.interceptors.response.use(
|
instance.interceptors.response.use(
|
||||||
(response: AxiosResponse<ApiResponse>) => {
|
(response: AxiosResponse<ApiResponse>) => {
|
||||||
const { code, msg } = response.data;
|
const { code, msg } = response.data;
|
||||||
|
|
||||||
// 401 未授权,跳转首页
|
// 401 未授权,跳转首页
|
||||||
if (code === 401) {
|
if (code === 401) {
|
||||||
// 这里调用退出登录的逻辑
|
// 这里调用退出登录的逻辑
|
||||||
console.log('未授权,跳转首页');
|
console.log("未授权,跳转首页");
|
||||||
// 清除用户信息
|
// 清除用户信息
|
||||||
removeToken();
|
removeToken();
|
||||||
// 跳转首页
|
// 跳转首页
|
||||||
window.location.href = '/'; //后续用发布订阅模式修改
|
window.location.href = "/"; //后续用发布订阅模式修改
|
||||||
return Promise.reject(new Error(msg || '未授权'));
|
return Promise.reject(new Error(msg || "未授权"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 其他非 200 状态码
|
// 其他非 200 状态码
|
||||||
if (code !== 200) {
|
if (code !== 200) {
|
||||||
console.error(`请求错误 ${code}: ${msg}`);
|
console.error(`请求错误 ${code}: ${msg}`);
|
||||||
// 这里可以根据需要弹出错误提示
|
// 这里可以根据需要弹出错误提示
|
||||||
return Promise.reject(new Error(msg || '请求错误'));
|
return Promise.reject(new Error(msg || "请求错误"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回数据部分
|
// 返回数据部分
|
||||||
@ -65,49 +63,10 @@ const createAxiosInstance = (): AxiosInstance => {
|
|||||||
const { status, data } = error.response;
|
const { status, data } = error.response;
|
||||||
console.error(`HTTP 错误 ${status}:`, data);
|
console.error(`HTTP 错误 ${status}:`, data);
|
||||||
} else {
|
} else {
|
||||||
console.error('请求错误:', error.message);
|
console.error("请求错误:", error.message);
|
||||||
}
|
}
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return instance;
|
export default instance;
|
||||||
};
|
|
||||||
|
|
||||||
const http = createAxiosInstance();
|
|
||||||
|
|
||||||
// 封装通用的 request 函数
|
|
||||||
async function request<T = any>(config: AxiosRequestConfig): Promise<T> {
|
|
||||||
try {
|
|
||||||
const { data } = await http.request<ApiResponse<T>>(config);
|
|
||||||
return data.data;
|
|
||||||
} catch (error) {
|
|
||||||
// 这里可以统一处理错误,或者让调用者自己处理
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 封装常用的 HTTP 方法
|
|
||||||
const httpClient = {
|
|
||||||
get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
|
||||||
return request<T>({ ...config, method: 'GET', url });
|
|
||||||
},
|
|
||||||
|
|
||||||
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
|
||||||
return request<T>({ ...config, method: 'POST', url, data });
|
|
||||||
},
|
|
||||||
|
|
||||||
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
|
||||||
return request<T>({ ...config, method: 'PUT', url, data });
|
|
||||||
},
|
|
||||||
|
|
||||||
delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
|
||||||
return request<T>({ ...config, method: 'DELETE', url });
|
|
||||||
},
|
|
||||||
|
|
||||||
patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
|
||||||
return request<T>({ ...config, method: 'PATCH', url, data });
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default httpClient;
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>我老家</div>
|
<div class="main__container">我老家</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang='scss'>
|
<style scoped lang='scss'>
|
||||||
|
.main__container{
|
||||||
|
background:url('../../assets/images/home_bg.webp');
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -24,6 +24,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
|
import { removeToken } from '@/utils/auth';
|
||||||
import { useAuth0 } from '@auth0/auth0-vue';
|
import { useAuth0 } from '@auth0/auth0-vue';
|
||||||
import {
|
import {
|
||||||
Pencil as EditIcon,
|
Pencil as EditIcon,
|
||||||
@ -60,7 +61,8 @@ const options = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const handleSelect = (key: string | number) => {
|
const handleSelect = (key: string | number) => {
|
||||||
if(key === 'logout'){
|
if (key === 'logout') {
|
||||||
|
removeToken()
|
||||||
logout({ logoutParams: { returnTo: window.location.origin } });
|
logout({ logoutParams: { returnTo: window.location.origin } });
|
||||||
router.push('/');
|
router.push('/');
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,14 @@ import {
|
|||||||
CaretDownOutline,
|
CaretDownOutline,
|
||||||
HomeSharp,
|
HomeSharp,
|
||||||
PersonCircleSharp,
|
PersonCircleSharp,
|
||||||
Layers
|
Layers,
|
||||||
|
Settings,
|
||||||
|
Menu
|
||||||
} from '@vicons/ionicons5'
|
} from '@vicons/ionicons5'
|
||||||
import { MenuOption, NIcon } from 'naive-ui';
|
import { MenuOption, NIcon } from 'naive-ui';
|
||||||
import { useAppStore } from '@/store/app';
|
import { useAppStore } from '@/store/app';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { RouterLink } from 'vue-router';
|
import { RouterLink } from 'vue-router';
|
||||||
import { h } from 'vue'
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const activeKey = ref('default');
|
const activeKey = ref('default');
|
||||||
const { menuApp } = storeToRefs(appStore)
|
const { menuApp } = storeToRefs(appStore)
|
||||||
@ -77,6 +78,29 @@ const menuOptions: MenuOption[] = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '系统配置',
|
||||||
|
key: 'system',
|
||||||
|
icon: renderIcon(Settings),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: () => h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
name: 'menu',
|
||||||
|
params: {
|
||||||
|
lang: 'zh-CN'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ default: () => '菜单管理' }
|
||||||
|
),
|
||||||
|
key: 'system',
|
||||||
|
icon: renderIcon(Menu)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang='scss'>
|
<style scoped lang='scss'>
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
<LayoutHeader />
|
<LayoutHeader />
|
||||||
<n-layout has-sider style="height: calc(100vh - 60px);">
|
<n-layout has-sider style="height: calc(100vh - 60px);">
|
||||||
<LayoutNav />
|
<LayoutNav />
|
||||||
<n-layout-content
|
<n-layout-content content-style="padding: 16px; height: calc(100vh - 60px);" :native-scrollbar="false">
|
||||||
content-style="padding: 24px; min-height: calc(100vh - 60px);"
|
<router-view v-slot="{ Component }">
|
||||||
:native-scrollbar="false"
|
<transition name="slide-fade" mode="out-in">
|
||||||
>
|
<component :is="Component" />
|
||||||
<RouterView></RouterView>
|
</transition>
|
||||||
|
</router-view>
|
||||||
</n-layout-content>
|
</n-layout-content>
|
||||||
</n-layout>
|
</n-layout>
|
||||||
</n-layout>
|
</n-layout>
|
||||||
@ -24,6 +25,24 @@ import LayoutNav from './components/LayoutNav.vue';
|
|||||||
.n-layout-content {
|
.n-layout-content {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background:#f5f7f9
|
background: #f5f7f9
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-fade-enter-active {
|
||||||
|
transition: all 0.6s cubic-bezier(0.68, -0.55, 0.27, 1.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-fade-leave-active {
|
||||||
|
transition: all 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-fade-enter-from {
|
||||||
|
transform: translate(30px, 30px) scale(0.9);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-fade-leave-to {
|
||||||
|
transform: translate(30px, 30px) scale(0.9);
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -20,7 +20,7 @@ const oSomethingWithToken = async () => {
|
|||||||
router.push('/layout');
|
router.push('/layout');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
router.push('/');
|
router.push('/');
|
||||||
message.error('错误!');
|
message.error(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
科技赋能 <span class="highlight">第五人格</span> 陪玩产业链
|
科技赋能 <span class="highlight">第五人格</span> 陪玩产业链
|
||||||
</h1>
|
</h1>
|
||||||
<p class="zn-hero__subtitle">
|
<p class="zn-hero__subtitle">
|
||||||
基于.NET9 + Vue3的智能管理系统,为您提供全方位的数字化解决方案
|
基于.NET9 + Vue3技术栈研发的智能管理系统,为您提供全方位的数字化解决方案
|
||||||
</p>
|
</p>
|
||||||
<div class="zn-hero__cta">
|
<div class="zn-hero__cta">
|
||||||
<n-button type="primary" size="large" @click="handleLogin">
|
<n-button type="primary" size="large" @click="handleLogin">
|
||||||
@ -67,7 +67,7 @@
|
|||||||
<div class="zn-features__grid">
|
<div class="zn-features__grid">
|
||||||
<div class="zn-feature-card">
|
<div class="zn-feature-card">
|
||||||
<div class="feature-icon">
|
<div class="feature-icon">
|
||||||
<n-icon color="#3d8eff">
|
<n-icon color="$primaryColor">
|
||||||
<GitCompare />
|
<GitCompare />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
@ -87,7 +87,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="zn-feature-card">
|
<div class="zn-feature-card">
|
||||||
<div class="feature-icon">
|
<div class="feature-icon">
|
||||||
<n-icon color="#3d8eff">
|
<n-icon color="$primaryColor">
|
||||||
<Server />
|
<Server />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
@ -136,7 +136,7 @@
|
|||||||
<div class="testimonial-author">
|
<div class="testimonial-author">
|
||||||
<img src="@/assets/images/luolan_avatar.jpg" alt="杨某人" />
|
<img src="@/assets/images/luolan_avatar.jpg" alt="杨某人" />
|
||||||
<div>
|
<div>
|
||||||
<div class="author-name">杨嚣张</div>
|
<div class="author-name">杨校长</div>
|
||||||
<div class="author-title">X电竞 校长</div>
|
<div class="author-title">X电竞 校长</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -205,16 +205,24 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ChevronForward, GitCompare, BarChartSharp, Server } from '@vicons/ionicons5';
|
import { ChevronForward, GitCompare, BarChartSharp, Server } from '@vicons/ionicons5';
|
||||||
import { useAuth0 } from '@auth0/auth0-vue';
|
import { useAuth0 } from '@auth0/auth0-vue';
|
||||||
import { useDialog } from 'naive-ui';
|
import { useDialog, useMessage } from 'naive-ui';
|
||||||
|
// import { loginApiTest } from '@/api/loginApi'
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const handleDemo = () => {
|
const message = useMessage();
|
||||||
console.log('观看演示');
|
const handleDemo = async () => {
|
||||||
|
// try {
|
||||||
|
// const data = await loginApiTest(); //data 就是 后端返回: { data:data,code:200,msg:'ok' } 的data
|
||||||
|
// } catch (error) {
|
||||||
|
// message.error(error.message); //error.message 就是 后端返回: { data:null,code:400,msg:'报错' }的msg
|
||||||
|
// }
|
||||||
|
console.log('代码演示一下!!!');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { loginWithRedirect } = useAuth0();
|
const { loginWithRedirect } = useAuth0();
|
||||||
const handleLogin = () => {
|
const handleLogin = () => {
|
||||||
loginWithRedirect();
|
loginWithRedirect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 联系我们
|
// 联系我们
|
||||||
const handleContact = () => {
|
const handleContact = () => {
|
||||||
dialog.warning({
|
dialog.warning({
|
||||||
@ -260,7 +268,7 @@ const handleContact = () => {
|
|||||||
&__text {
|
&__text {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #3d8eff;
|
color: $primaryColor;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +290,7 @@ const handleContact = () => {
|
|||||||
transition: color 0.3s;
|
transition: color 0.3s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #3d8eff;
|
color: $primaryColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,7 +330,7 @@ const handleContact = () => {
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
|
||||||
.highlight {
|
.highlight {
|
||||||
color: #3d8eff;
|
color: $primaryColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +355,7 @@ const handleContact = () => {
|
|||||||
.stat-number {
|
.stat-number {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #3d8eff;
|
color: $primaryColor;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,7 +409,7 @@ const handleContact = () => {
|
|||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
|
||||||
&.highlight {
|
&.highlight {
|
||||||
background: linear-gradient(135deg, #3d8eff, #6a5acd);
|
background: linear-gradient(135deg, $primaryColor, #6a5acd);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
.feature-link {
|
.feature-link {
|
||||||
@ -437,12 +445,12 @@ const handleContact = () => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: #3d8eff;
|
color: $primaryColor;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature-link {
|
.feature-link {
|
||||||
color: #3d8eff;
|
color: $primaryColor;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@ -551,7 +559,7 @@ const handleContact = () => {
|
|||||||
transition: color 0.3s;
|
transition: color 0.3s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #3d8eff;
|
color: $primaryColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,7 +593,7 @@ const handleContact = () => {
|
|||||||
transition: color 0.3s;
|
transition: color 0.3s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #3d8eff;
|
color: $primaryColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>权限管理菜单内容</div>
|
<div class="main__container white-bg table">权限管理菜单内容</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
|
8
src/views/system/menu/index.vue
Normal file
8
src/views/system/menu/index.vue
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main__container white-bg table">动态权限菜单</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts'>
|
||||||
|
</script>
|
||||||
|
<style scoped lang='scss'>
|
||||||
|
</style>
|
@ -17,6 +17,15 @@ export default defineConfig({
|
|||||||
dirs: ["./src/api"],
|
dirs: ["./src/api"],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
server:{
|
||||||
|
proxy:{
|
||||||
|
'/api':{
|
||||||
|
target:'http://localhost:3000/api',
|
||||||
|
changeOrigin:true,
|
||||||
|
rewrite:(path) => path.replace(/^\api/,'')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
css: {
|
css: {
|
||||||
preprocessorOptions: {
|
preprocessorOptions: {
|
||||||
scss: {
|
scss: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user