文章目录

  • 注意
  • 效果图
  • 目录结构
  • 代码
    • vite.config.ts需要配置路径别名@符号
    • main.ts
    • App.vue
    • Breadcrumb.vue面包屑组件
    • menus.ts
    • // src/router/index.ts
    • 其他文件

注意

  • 目录结构仅供参考
  • DefaultLayout.vue 没有用到,我直接写在APP文件中
  • vux-store我也没有用到,单独写了一个配置文件存储菜单数据
  • 详细代码需要参考后面贴出来的实际代码

效果图

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

目录结构

src/
├── views/
│   ├── user/                     # 用户管理模块
│   │   ├── UserList.vue          # 用户列表页面(主页面)
│   │   ├── UserDetails.vue       # 用户详情页面(子页面)
│   │   ├── UserEdit.vue          # 用户编辑页面(子页面)
│   │   └── UserSettings.vue      # 用户设置页面(子页面)
│   │
│   ├── role/                     # 用户角色管理模块
│   │   └── UserRole.vue          # 用户角色管理页面
│   │
│   ├── permission/               # 权限管理模块
│   │   ├── PermissionList.vue    # 权限列表页面(主页面)
│   │   ├── PermissionAdd.vue     # 权限添加页面(子页面)
│   │   └── PermissionSetting.vue # 权限设置页面(子页面)
│   │
│   └── layout/                   # 布局组件
│       └── DefaultLayout.vue (没有)    # 主布局,包含菜单和面包屑导航
│
├── router/
│   └── index.js                  # 路由配置文件
│
├── store/
│   └── modules/
│       └── menu.js  (没有)             # 动态菜单状态管理
│
└── components/└── breadcrumb/               # 面包屑组件└── Breadcrumb.vue
用户管理└── 用户列表(含详情、编辑)└── 用户角色管理└── 用户设置└── 偏好设置(有编辑页)└── 安全设置(有修改页)
src/
├── pages/
│   ├── user/
│   │   ├── UserList.vue
│   │   ├── UserDetails.vue
│   │   ├── UserEdit.vue
│   │   ├── UserSettings.vue         # 用户设置主页面
│   │   ├── preferences/
│   │   │   ├── PreferenceSettings.vue  # 偏好设置页面
│   │   │   └── PreferenceEdit.vue      # 偏好编辑页面
│   │   └── security/
│   │       ├── SecuritySettings.vue    # 安全设置页面
│   │       └── SecurityModify.vue      # 安全修改页面
│   ├── role/
│   │   └── UserRole.vue
│   └── permission/
│       └── ...

代码

vite.config.ts需要配置路径别名@符号

import path from 'node:path'
import Vue from '@vitejs/plugin-vue'import Unocss from 'unocss/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
import VueRouter from 'unplugin-vue-router/vite'import { defineConfig } from 'vite'// https://vitejs.dev/config/
export default defineConfig({resolve: {alias: {'@/': `${path.resolve(__dirname, 'src')}/`,},},css: {preprocessorOptions: {scss: {additionalData: `@use "@/styles/element/index.scss" as *;`,api: 'modern-compiler',},},},plugins: [Vue(),// https://github.com/posva/unplugin-vue-routerVueRouter({extensions: ['.vue', '.md'],dts: 'src/typed-router.d.ts',}),Components({// allow auto load markdown components under `./src/components/`extensions: ['vue', 'md'],// allow auto import and register components used in markdowninclude: [/\.vue$/, /\.vue\?vue/, /\.md$/],resolvers: [ElementPlusResolver({importStyle: 'sass',}),],dts: 'src/components.d.ts',}),// https://github.com/antfu/unocss// see uno.config.ts for configUnocss(),],ssr: {// TODO: workaround until they support native ESMnoExternal: ['element-plus'],},
})

main.ts

import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import '@/styles/index.scss'
import 'uno.css'// If you want to use ElMessage, import it.
import 'element-plus/theme-chalk/src/message.scss'
import 'element-plus/theme-chalk/src/message-box.scss'const app = createApp(App)app.use(router)
app.use(ElementPlus)app.mount('#app')

App.vue

<!-- src/App.vue -->
<template><el-container class="layout-container"><!-- 左侧侧边栏 --><el-aside width="200px" class="layout-aside"><el-menudefault-active="$route.path"routerclass="side-menu"background-color="#ffffff"text-color="#333"active-text-color="#409EFF"><!-- 动态生成菜单 --><div v-for="menu in menus" :key="menu.title"><el-sub-menu :index="menu.title" v-if="menu.children && menu.children.length"><template #title>{{ menu.title }}</template><el-menu-itemv-for="child in menu.children":key="child.path":index="child.path">{{ child.title || child.path }}</el-menu-item></el-sub-menu></div></el-menu></el-aside><!-- 右侧主内容区域 --><el-container class="layout-main"><!-- 顶部栏 --><el-header class="layout-header"><div class="header-title">智能控制器后台系统</div><div class="header-right"><span>管理员</span><el-avatar icon="UserFilled" size="small" /></div></el-header><!-- 面包屑导航 --><el-header class="layout-breadcrumb"><Breadcrumb /></el-header><!-- 页面主体内容 --><el-main class="layout-content"><router-view /></el-main></el-container></el-container>
</template><script setup>import Breadcrumb from './components/breadcrumb/Breadcrumb.vue';
import {  menus } from '@/config/menu';</script><style scoped>
.layout-container {height: 100vh;
}.layout-aside {background-color: #fff;border-right: 1px solid #e4e7ed;
}.layout-main {flex-direction: column;
}.layout-header {display: flex;justify-content: space-between;align-items: center;background-color: #ffffff;box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);padding: 0 20px;
}.header-title {font-size: 18px;font-weight: bold;
}.layout-breadcrumb {padding: 10px 20px;background-color: #f5f7fa;border-bottom: 1px solid #e4e7ed;
}.layout-content {padding: 20px;background-color: #f9fafb;
}
</style>

Breadcrumb.vue面包屑组件

<template><el-breadcrumb separator="/"><el-breadcrumb-item v-for="item in breadcrumbs" :to="item.path" :key="item.path">{{ item.meta?.title }}</el-breadcrumb-item></el-breadcrumb>
</template><script setup>
import { ref, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router';const route = useRoute();
const breadcrumbs = ref([]);const getBreadcrumbs = () => {const matched = route.matched.filter(item => item.meta?.title);breadcrumbs.value = matched;console.log('breadcrumbs:', breadcrumbs.value);
};// 页面加载时获取一次
onMounted(() => {getBreadcrumbs();
});// 监听路由路径变化,动态更新面包屑
watch(() => route.path,() => {getBreadcrumbs();}
);
</script>

menus.ts

export const menus = [{title: '用户管理',children: [{ title: '用户列表', path: '/user/list' },{ title: '用户角色管理', path: '/user/role' }]},{title: '权限管理',children: [{ title: '权限列表', path: '/permission/list' }]}]

// src/router/index.ts

// src/router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
// import { CustomRoute } from '@/types/router';
export interface CustomRouteMeta {title: string;
}export type CustomRoute = Omit<RouteRecordRaw, 'meta' | 'children'> & {meta: CustomRouteMeta;children?: CustomRoute[];
};
const routes: CustomRoute[] = [{path: '/',redirect: '/user/list',meta: { title: '首页' },children: [// 用户管理 - 父级{path: '/user',redirect: '/user/list',meta: { title: '用户管理' },children: [{path: 'list',component: () => import('@/pages/user/UserList.vue'),meta: { title: '用户列表' }},{path: 'details/:id',component: () => import('@/pages/user/UserDetails.vue'),meta: { title: '用户详情' }},{path: 'edit/:id',component: () => import('@/pages/user/UserEdit.vue'),meta: { title: '用户编辑' }},{path: 'settings',component: () => import('@/pages/user/UserSettings.vue'),meta: { title: '用户设置' }},{path: 'role',component: () => import('@/pages/role/UserRole.vue'),meta: { title: '用户角色管理' }},{path: 'preferences',redirect: '/user/preferences/settings',meta: { title: '偏好设置' },children: [{path: 'settings',component: () => import('@/pages/user/preferences/PreferenceSettings.vue'),meta: { title: '偏好设置' }},{path: 'edit',component: () => import('@/pages/user/preferences/PreferenceEdit.vue'),meta: { title: '偏好编辑' }}]},{path: 'security',redirect: '/user/security/settings',meta: { title: '安全设置' },children: [{path: 'settings',component: () => import('@/pages/user/security/SecuritySettings.vue'),meta: { title: '安全设置' }},{path: 'modify',component: () => import('@/pages/user/security/SecurityModify.vue'),meta: { title: '安全修改' }}]}]},// 权限管理 - 父级{path: '/permission',redirect: '/permission/list',meta: { title: '权限管理' },children: [{path: 'list',component: () => import('@/pages/permission/PermissionList.vue'),meta: { title: '权限列表' }},{path: 'add',component: () => import('@/pages/permission/PermissionAdd.vue'),meta: { title: '权限添加' }},{path: 'setting',component: () => import('@/pages/permission/PermissionSetting.vue'),meta: { title: '权限设置' }}]}]},{path: '/:pathMatch(.*)*',name: 'NotFound',component: () => import('@/pages/error/404.vue'),meta: { title: '页面不存在' }}
];const router = createRouter({history: createWebHistory(),routes:routes as unknown as RouteRecordRaw[]
});export default router;

其他文件

│ │ ├── UserList.vue
│ │ ├── UserDetails.vue
│ │ ├── UserEdit.vue
│ │ ├── UserSettings.vue # 用户设置主页面
│ │ ├── preferences/
│ │ │ ├── PreferenceSettings.vue # 偏好设置页面
│ │ │ └── PreferenceEdit.vue # 偏好编辑页面
│ │ └── security/
│ │ ├── SecuritySettings.vue # 安全设置页面
│ │ └── SecurityModify.vue # 安全修改页面

│   │   ├── UserList.vue
<template><div><h2>用户列表</h2><button @click="goToDetail">查看用户详情</button><button @click="goToEdit">编辑用户信息</button><button @click="goToSettings">用户设置</button></div>
</template><script setup>
import { useRouter } from 'vue-router';const router = useRouter();
const goToDetail = () => router.push('/user/details/1');
const goToEdit = () => router.push('/user/edit/1');
const goToSettings = () => router.push('/user/settings');
</script>
│   │   ├── UserDetails.vue
<template><h1>用户详情</h1>
</template>
│   │   ├── UserEdit.vue
<template><h1>用户编辑</h1>
</template>
│   │   ├── UserSettings.vue         # 用户设置主页面
<template><div><h2>用户设置</h2><router-link to="/user/preferences/settings"><el-button>进入偏好设置</el-button></router-link><router-link to="/user/security/settings"><el-button>进入安全设置</el-button></router-link><router-view /></div>
</template>
<script setup></script>
│   │   ├── preferences/
│   │   │   ├── PreferenceSettings.vue  # 偏好设置页面
<template><div><h3>偏好设置</h3><router-link to="/user/preferences/edit"><el-button>编辑偏好设置</el-button></router-link></div>
</template>
│   │   │   └── PreferenceEdit.vue      # 偏好编辑页面
<template><h1>偏好编辑页面</h1>
</template>
│   │   └── security/
│   │       ├── SecuritySettings.vue    # 安全设置页面
<template><h1>安全设置页面</h1>
</template>
│   │       └── SecurityModify.vue      # 安全修改页面
<template><h1>安全修改页面</h1>
</template>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/90872.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/90872.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/90872.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Selenium自动化获取抖音创作者平台视频数据

前言 在当今短视频盛行的时代&#xff0c;抖音作为国内领先的短视频平台&#xff0c;吸引了大量内容创作者。对于创作者而言&#xff0c;了解自己发布的视频表现&#xff08;如播放量、发布时间等&#xff09;至关重要。本文将介绍如何使用Python的Selenium库来自动化获取抖音…

SpringCloud之Eureka

SpringCloud之Eureka 推荐参考&#xff1a;https://www.springcloud.cc/spring-cloud-dalston.html#_service_discovery_eureka_clients 1. 什么是Eureka Eureka 用于简化分布式系统的服务治理&#xff0c;基于REST的服务&#xff0c;用于服务的注册与发现。通过注册发现、客户…

squash压缩合并

要将test分支的多次提交合并到dev分支并压缩为一个commit&#xff0c;核心是使用 git merge --squash 命令&#xff08;压缩合并&#xff09;&#xff0c;具体步骤如下&#xff1a; 详细步骤&#xff1a; 1. 切换到dev分支并拉取最新代码先确保本地dev分支是最新的&#xff0c;…

飞书CEO谢欣:挑战巨头,打造AI新时代的Office

引言&#xff1a;飞书要做AI时代办公协作的逐梦者与破局者。文 | 大力财经在AI浪潮席卷的当下&#xff0c;企业对AI既满怀期待又充满焦虑。“AI到底能不能用&#xff1f;AI到底怎么用&#xff1f;”成为萦绕在众多企业心头的难题。7月9日召开的飞书未来无限大会&#xff0c;飞书…

React 组件中怎么做事件代理?它的原理是什么?

在 React 组件中&#xff0c;**事件代理&#xff08;Event Delegation&#xff09;**其实是 React 内部实现的一部分&#xff0c;开发者通常无需手动实现事件代理&#xff0c;但理解它的原理和使用方式对于优化性能和掌握底层机制非常重要。一、React 中事件代理的原理React 使…

Vue 2现代模式打包:双包架构下的性能突围战

文章目录一、场景痛点&#xff1a;兼容性与性能的撕裂二、技术解析&#xff1a;Modern Mode的双引擎驱动1. 基础认知&#xff1a;什么是Modern Mode&#xff1f;2. 原理深入&#xff1a;HTML智能分发与Safari 10修复3. 性能收益对比表三、Vue 2项目实战&#xff1a;启用Modern模…

UniHttp中HttpApiProcessor生命周期钩子介绍以及公共参数填充-以百度天气接口为例

目录 引言 一、UniHttp与HttpApiProcessor简介 1、生命周期钩子的重要性 2、公共参数填充的需求 3、生命周期钩子相关介绍 二、HttpApiProcessor的实际应用 1、在Yml中定义相关参数 2、自定义HttpAPI注解 3、对接接口的定义 4、HttpApiProcessor的具体实现 5、实际调…

pytorch深度学习—RNN-循环神经网络

结合生活实例&#xff0c;先简单认识一下什么是循环神经网络先想个问题&#xff1a;为什么需要 “循环”&#xff1f;你平时看句子、听语音、看视频&#xff0c;都是 “按顺序” 来的吧&#xff1f;比如 “我吃苹果” 和 “苹果吃我”&#xff0c;字一样但顺序不同&#xff0c;…

深度学习常见名词解释、评价指标

目录 一、鲁棒性(robustness) 二、泛化能力&#xff08;Generalization Ability&#xff09; 核心含义&#xff1a; 如何衡量泛化能力&#xff1f; 三、先验信息&#xff08;Prior Information&#xff09; 四、mIoU &#xff08;Mean Intersection over Union&#xff0…

docker-compose安装常用中间件

分为3大部分&#xff1a;数据库&#xff1a;mysql&#xff0c;redis&#xff0c;mongodb&#xff0c;elasticsearch&#xff0c;neo4j&#xff0c;minio&#xff0c;influxdb&#xff0c;canal-server应用中间件&#xff1a;nacos&#xff0c;apollo&#xff0c;zookeeper&…

基于无人机 RTK 和 yolov8 的目标定位算法

目录 背景 算法思路 代码实现 验证 背景 在城市交通巡检中如何进行车辆违停判断很重要&#xff0c;一个方法是通过精确坐标判断车辆中心是否位于违停框中&#xff0c;我们假设无人机坐标已知&#xff0c;并且无人机云台镜头垂直地面朝下&#xff0c;可根据图像分辨率、无人机参…

go入门 - day1 - 环境搭建

0. 介绍 go语言可以做什么&#xff1f; a. 区块链 b. 分布式/微服务/云原生 c. 服务器/游戏软件go的优势 a. 代码量比C和Java少 b. 编译速度比Java或者C快上5到6倍&#xff0c;比Scale块10被 c. 性能比C慢20%&#xff0c;但是比Java、python等快上5到10倍 d. 内存管理和C媲美&a…

【华为OD】MVP争夺战(C++、Java、Python)

文章目录题目描述输入描述输出描述示例解题思路算法思路核心步骤代码实现C实现Java实现Python实现算法要点复杂度分析解题总结题目描述 在星球争霸篮球赛对抗赛中&#xff0c;最大的宇宙战队希望每个人都能拿到MVP&#xff0c;MVP的条件是单场最高分得分获得者。可以并列所以宇…

Datawhale 2025 AI夏令营 MCP Server Task2

魔搭MCP &Agent赛事&#xff08;MCP Server开发&#xff09;/夏令营&#xff1a;动手开发MCP Server学习链接&#xff1a;魔搭MCP &Agent赛事&#xff08;MCP Server开发&#xff09; - Datawhale Task1回顾 1.task1应用功能 luner_info每日黄历 这是一个可以获取某天…

敏捷开发方法全景解析

核心理念:敏捷开发是以快速响应变化为核心的项目管理方法论,通过迭代式交付、自组织团队和持续反馈,实现高质量软件的高效交付。其本质是拥抱变化优于遵循计划,强调"可工作的软件高于详尽的文档"。 一、敏捷核心思想体系 #mermaid-svg-y7iyWsQGVWn3IpEi {font-fa…

Socket到底是什么(简单来说)

简单来说&#xff1a; Socket 抽象了网络通信的复杂底层细节&#xff0c;让应用程序开发者可以专注于发送和接收数据&#xff0c;而不用去操心数据在网络上是如何传输的。 它就像一个“黑盒子”&#xff0c;你只需要把数据扔进去&#xff0c;或者从里面取数据&#xff0c;至于数…

linux系统mysql性能优化

1、系统最大打开文件描述符数查看限制 ulimit -n更改配置 # 第一步 sudo vim /etc/security/limits.conf* soft nofile 1048576 * hard nofile 1048576# 第二步 sudo vim /etc/sysctl.conffs.file-max 1048576# 第三步&#xff08;重启系统&#xff09; sudo reboot验证生效 u…

免费的需要尝试claude code的API安利,截至今天可用(7月13号)

安装方法放最后&#xff08;很简单&#xff0c;但是你得搞定网络&#xff09; 注册如下&#xff1a; 链接如下&#xff08;有详细说明&#xff09;&#xff1a; &#x1f680; AnyRouter&#xff5c;Claude Code 免费共享平台 安装&#xff08;windows用户特殊点&#xff0…

Java 属性配置文件读取方法详解

Java 属性配置文件读取方法详解 一、配置文件基础概念 1. 配置文件类型对比类型格式优点缺点适用场景Propertieskeyvalue简单易读&#xff0c;Java原生支持不支持层级结构简单配置&#xff0c;JDBC参数XML标签层级结构结构化强&#xff0c;支持复杂数据类型冗余&#xff0c;解析…

NW728NW733美光固态闪存NW745NW746

美光NW系列固态闪存深度解析&#xff1a;NW728、NW733、NW745与NW746的全方位评测技术架构与核心创新美光NW系列固态闪存&#xff08;包括NW728、NW733、NW745、NW746&#xff09;的技术根基源于其先进的G9 NAND架构。该架构通过5纳米制程工艺和多层3D堆叠技术&#xff0c;在单…