通用权限管理系统+vue3项目实战(一)

news2024/11/29 20:34:42

1.创建项目

在某个工程文件夹下创建项目

npm init vue@latest

各种工具选择都选是,并且安装环境node_modules之后,显示如图:
在这里插入图片描述

1.1 引入element-plus

在vue2的时候常用的ui框架是element-ui,在vue3时应该使用它的继承者element-plus。
同时,为保证能自动引入插件,可以使用插件unplugin-vue-components和unplugin-auto-import。
接下来下载插件。

npm install element-plus --save
npm install -D unplugin-vue-components unplugin-auto-import

在配置文件中修改成以下配置:

import Components from "unplugin-vue-components/vite"
const { ElementPlusResolver } = require("unplugin-vue-components/resolvers")
import AutoImport from 'unplugin-auto-import/vite'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(),
  vueJsx(), 
  AutoImport({ resolvers: [ElementPlusResolver()] }), 
  Components({ resolvers: [ElementPlusResolver()] })],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

1.1.1 引入Element Plus图标集

由于本项目还使用了Element Plus的图标,像左侧导航的图标是根据后台数据配置确定的,因此使用什么图标是不确定的。

npm install @element-plus/icons-vue
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

1.2 安装SCSS依赖

npm install -D sass

在package.json的文件,如图所示:
在这里插入图片描述

2. 添加页面路由

在views目录下新建Login.vue 404.vue Home.vue页面等3个简单页面

<template>
<div class='page'>
    <h2>登录页</h2>
</div>
</template>

在router/index.ts中

import Login from '@/views/Login.vue'
import Home from '@/views/Home.vue'
import NotFound from '@/views/404.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/login',
      name: 'Login',
      component: Login
    },
    {
      path: '/404',
      name: 'NotFound',
      component: NotFound
    },
  ]
})

运行后,如图所示:
在这里插入图片描述

2.1 改进页面路由

将router/index.ts文件修改成以下代码:

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/login',
    name: 'Login',
    component: Login
  },
  {
    path: '/404',
    name: 'NotFound',
    component: NotFound
  },
]
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

export default router

3. 设计页面布局

3.1 修改App.vue

<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
import zhCn from 'element-plus/dist/locale/zh-cn'
</script>
<template>
  <el-config-provider :locale="zhCn">
    <RouterView />
  </el-config-provider>
</template>

3.2 布局文件

在src/views/layout下创建index.vue文件,用于存放总体布局。

<template>
    <div class="app-wrapper">
        <page-header class="app-header"></page-header>
        <div class="app-container">
            <page-sidebar class="sidebar-container"></page-sidebar>
            <div class="main-wrapper">
                <main-content></main-content>
            </div>
        </div>
    </div>
</template>

<script>
import PageHeader from '@/views/layout/components/PageHeader.vue'
import PageSidebar from '@/views/layout/components/PageSidebar.vue'
import MainContent from '@/views/layout/components/MainContent.vue'
export default {
    name: "layout",
    components: {
        PageHeader,
        PageSidebar,
        MainContent,
    },
}
</script>

Wrapper(整体布局):包裹整个页面或页面的一部分,通常用于设置背景、边框等样式。
Container(容器):包裹页面的主要内容,通常用于设置宽度、居中等样式。
Content(内容):包裹页面的具体内容,通常用于设置字体、颜色等样式。
Main(主要内容):包裹页面的主要内容,通常用于设置页面的主要样式。

在在src/views/layout/compnents下创建各布局组件。文件,用于存放总体布局。

//PageHeader.vue
<template>
    <div class="app-wrapper">
        首栏
    </div>
</template>
//PageSidebar.vue
<template>
    <div>
        侧边栏
    </div>
</template>
//MainContent.vue
<template>
    <div>
        <router-view></router-view>
    </div>
</template>

在router文件中,修改代码将布局Layout应该到界面中。我们可以在views/personal下创建个人中心页面文件index.vue,将其设置为Layout的子路由。

import Layout from '@/views/layout/index.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Layout,
    children: [
      {
        path: 'personal',
        name: 'personal',
        component: () => import('@/views/personal/index.vue')
      },
    ]
  },
  {
    path: '/login',
    name: 'Login',
    component: Login
  },
  {
    path: '/404',
    name: 'NotFound',
    component: NotFound
  },
]

如上所示,其实布局Layout.vue、Login登录页和404错误页都挂载到App.vue的router-view标签中。而子路由children挂载到MainContent.vue的router-view标签中,它们都应用了Layout的布局。

再根据需要调整CSS样式,访问http://localhost:5173/personal 的链接,最终设计的布局如图:
在这里插入图片描述

4.完善登录流程

登录流程分析:
(1)登录表单需要将用户信息提交到后台进行校验处理,所以这里涉及发送请求axios的操作,为便于重用代码,axios需要重新封装。
(2)在前后端分离项目中,为追求效率,可使用mockjs进行模拟数据的测试。
(3)当请求发送成功时,需要保留登录状态,登录状态将在整个项目中使用
(4)任何操作都需要在已登录状态下完成,这样才能保证用户数据或网站数据的安全
(5)如果登录状态失效,则需要更新状态并退出系统,用户需要重新登录,才可以重新执行相应操作,所以需要考虑状态管理。

4.1 封装axios

4.1.1 安装axios

先安装axios插件

npm install axios

在package.json的文件,如图所示:
在这里插入图片描述

4.1.2 设置配置文件

首先,后台的返回规则有一个通用的规则,前端的请求也有统一的规则,所以可以考虑设置一个通用的配置文件。

在src/http下创建一个config.js文件,将Axios通用配置写入文件中。

export default {
  method: 'get',
  // 基础url前缀
  baseUrl: 'http://localhost:8001',
  // 请求头信息
  headers: {
    'Content-Type': 'application/json;charset=UTF-8'
  },
  // 参数
  data: {},
  // 设置超时时间
  timeout: 10000,
  // 携带凭证
  withCredentials: true,
  // 返回数据类型
  responseType: 'json'
}

4.1.3 设置拦截器

现在 统一API请求,并设置拦截器。
在src/http下创建一个request.js文件,引入Axios,再引入上一步创建的config.js文件,然后创建一个request方法,返回Promise,并导出这个方法,以便在其他文件中使用。在这个方法中通过axios.create创建一个Axios实例,代码如下:

import axios from 'axios'
import config from './config'

export default function request(options) {
    return new Promise((resolve, reject) => {
        //创建axios实例
        const instance = axios.create({
            baseURL: config.baseUrl,
            headers: config.headers,
            timeout: config.timeout,
            withCredentials: config.withCredentials
        })
        // request 请求拦截器
        instance.interceptors.request.use(
            config => {
                // todo : 请求必须携带身份信息的逻辑
                return config
            },
            error => {
                console.log(error) // 请求发生错误时,通过控制台查看报错的逻辑
                return Promise.reject(error) // 在调用的那边可以拿到(catch)你想返回的错误信息
            }
        )

        // response 响应拦截器
        instance.interceptors.response.use(
            response => {
                //返回响应的逻辑
                const res = response.data
				if (res.errcode !== "00000") {
					console.log("错误")
				}                
                return response.data
            },
            err => {
                //todo: 返回响应出现错误的逻辑              
                console.error(err)
                return Promise.reject(err) // 返回接口返回的错误信息
            }
        )
        // 请求处理
        instance(options).then(res => {
            resolve(res)
            return false
        }).catch(error => {
            reject(error)
        })
    })
}

分析:
(1)请求方式正确时,应该校验访问者的token信息,token信息校验正确则进入访问页面,若校验错误则重定向到登录页面。
(2)请求方式错误时,应该提示报错信息。
(3)返回正确的响应时,不做处理
(4)返回错误的响应时,应该提示报错信息。

携带的token信息跟实现机制有关,可能由cookie,localStorage,vuex等实现。

提示的报错信息跟使用的ui框架有关,应该使用ui框架提供的消息提示工具,同时在console也要提示报错。

正确返回结果时,统一返回格式为JSON,包含3个属性:errcode、errmsg和data。code表示成功标识,为00000时表示成功,成功时通常会带回数据data,如果不是00000,则为失败,需要读取提示信息。

{
	errcode: "00000",
	errmsg: "success",
	data: {
		//....
	}
}

4.1.4 统一管理请求

为了统一管理请求,在src下创建api文件夹,用于存放各模块的远程请求方法。
例如,在api文件夹中创建login.js文件,放入以下请求。

import request from '@/http/request'

export function login(username, password) {
  return request({
    url: '/api/ums/admin/login',
    method: 'post',
    data: {
      username,
      password
    }
  })
}

该方法调用axios封装方法request来发送请求,当请求返回登录成功时,正常情况下会带回一个登录标识token,在处理请求返回时,将这个token存到本地缓存localStorage中,然后跳转到系统首页。

3.封装Mock.js

为了能看到登录效果,要么依赖后台功能正常返回,要么考虑前端模拟后端返回。
先安装 mockjs插件。

npm install -D  mockjs 

在src目录下新建一个mock目录,创建index.js。

和Axios请求模拟一样,数据的模拟也区分不同模块,因此继续在src/mock下创建一个modules文件夹,用于存放不同模块的模拟函数。并在modules文件夹下创建login.js文件。

import Mock from 'mockjs'

Mock.mock('http://localhost:8001/login',{
    errcode: '00000',
    errmsg: 'success',
    data: {
        token : 'abc123456'
    }
})
export function login(){
    return {
        url : "login",
        type: "post",
        data: {
            errcode : "00000",
            errmsg : "success",
            data : {
                token : "abc123456789",
                username : "admin"
            }
        }
    }
}

在index.js文件中引入各模块文件

import Mock from 'mockjs'
import * as login from './modules/login.js'

// 开启/关闭模块的拦截
const openMock = true
const baseUrl = "http://localhost:8001"

//模拟所有模块
mockAll([login],openMock)
function mockAll(modules,isOpen = true){
    for (const k in modules){
        mock(modules[k],isOpen)
    }
}
function mock(mod,isOpen = true){
    if(isOpen){
        for(var key in mod){
            ((res)=>{
                let url = baseUrl
                if(!url.endsWith("/")){
                    url = url +"/"
                }
                url = url + res.url
                Mock.mock(new RegExp(url),res.type,(opts) => {
                    opts['data'] = opts.body ? JSON.parse(opts.body) :null
                    delete opts.body
                    console.log('\n')
                    console.log('%cmock拦截,请求:','color:blue',opts)
                    console.log('%cmock拦截,请求:','color:blue',res.data)
                    return res.data
                })
            })(mod[key]()|| {})
        }
    }
}

至此,Mock.js封装完成。只需要在入口文件src/main.js中引入上面的入口文件即可,即修改main.js如下(注意加粗部分):

import './assets/main.css'
import './mock'

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'

import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const app = createApp(App)

for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
  }

app.use(createPinia())
app.use(router)

app.mount('#app')

4.引入状态管理库Pinia及管理登录状态

若未安装pinia,则先引入

npm install pinia

确保在main.js文件中应用了pinia

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')

设置用户登录状态

import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
    state: () => ({
       token: '',
       name:'',
       avatar: '',
       roles: [] 
      }),
    getters: {
      getToken: (state) => state.token,
    },
    actions: {
      setToken() {
      },
      setName(){},
      setAvatar(){},
      setRoles(){}
    },
  })

用户登录设计思路:
(1)用户在页面表单填写账号密码后,将数据传递给状态管理库,原因是状态管理需要保存用户信息。
(2)由状态管理访问api,接受返回的数据。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python匹配空白字符的完整指南

Python匹配空白字符的完整指南 在Python编程中&#xff0c;处理文本数据是一项常见任务。当我们需要从文本中提取数据时&#xff0c;通常需要从字符串中匹配特定的模式。这些模式可能包括空格、制表符和换行符等空白字符。本文将介绍如何使用Python正则表达式来匹配空白字符&a…

chatgpt赋能python:Python动态Import简介

Python动态Import简介 在Python中&#xff0c;Import语句用于导入其他Python模块中的函数和变量。通常在Python编程中&#xff0c;我们使用静态Import方法来导入模块。但是&#xff0c;Python也支持动态Import&#xff0c;即在运行时根据需要导入模块中的函数和变量。 在本文…

day 39:62. 不同路径63. 不同路径 II

动态规划 [62. 不同路径](https://leetcode.cn/problems/unique-paths/description/)1. dp数组以及下标名义2. 递归公式3. dp数组如何初始化4. 遍历顺序5.代码 [63. 不同路径 II&#xff1a;有障碍物](https://leetcode.cn/problems/unique-paths-ii/description/)1. dp数组以及…

银行从业——法律法规——经济基础知识

第一章、经济基础知识 第一节、宏观经济分析 【 知识点1】 宏观经济发展目标 宏观经济发展的总体目标一般包括四个&#xff1a; 宏观经济发展的总体目标 衡量指标1、经济增长国内生产总值&#xff08;GDP&#xff09;2、充分就业 失业率3、物价稳定通货膨胀率4、国际…

【HISI IC萌新虚拟项目】Package Process Unit项目全流程目录

说明 Package Process Unit虚拟项目是HISI部分部门芯片设计与验证新员工的培训项目,一般会分配6~10周的时间独立开发该项目并完成验收。在整个项目中,新员工需要熟悉工作站、项目流程、公共环境与代码等,并根据方案文档独立设计ppu模块,之后进行功能验证与综合等芯片交付流…

代码随想录算法训练营第四十六天|139.单词拆分、关于多重背包,你该了解这些!、背包问题总结篇!

文章目录 一、139.单词拆分二、关于多重背包&#xff0c;你该了解这些&#xff01;三、背包问题总结篇&#xff01;总结 一、139.单词拆分 public boolean wordBreak(String s, List<String> wordDict) {//完全背包问题&#xff0c;因为可以重复&#xff0c;背包正序排列…

chatgpt赋能python:Python匹配符号:快速有效地处理文本

Python匹配符号&#xff1a;快速有效地处理文本 什么是Python匹配符号&#xff1f; Python是一种灵活的编程语言&#xff0c;可以轻松地处理文本数据。在Python中&#xff0c;使用正则表达式来匹配符号。正则表达式是一种模式匹配工具&#xff0c;可以帮助用户找到特定的文本…

day 44 完全背包:518. 零钱兑换 II;377. 组合总和 Ⅳ

完全背包&#xff1a;物品可以使用多次 完全背包1. 与01背包区别 518. 零钱兑换 II1. dp数组以及下标名义2. 递归公式3. dp数组如何初始化4. 遍历顺序:不能颠倒两个for循环顺序5. 代码 377. 组合总和 Ⅳ:与零钱兑换类似&#xff0c;但是是求组合数1. dp数组以及下标名义2. 递归…

ASP.NET Core MVC 从入门到精通之自动映射(二)

随着技术的发展&#xff0c;ASP.NET Core MVC也推出了好长时间&#xff0c;经过不断的版本更新迭代&#xff0c;已经越来越完善&#xff0c;本系列文章主要讲解ASP.NET Core MVC开发B/S系统过程中所涉及到的相关内容&#xff0c;适用于初学者&#xff0c;在校毕业生&#xff0c…

034:Mapbox GL双屏地图联动

第034个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中实现双屏联动功能。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共110行)相关API参考:专栏目标示例效果 配置方式 1)查看基础设置:https://…

Redis入门到实战笔记-数据类型

这里写目录标题 SQL与NoSQL关系型数据库&#xff1a;查询方式&#xff1a; 非关联数据库&#xff1a;查询方式&#xff1a; 总结 认识RedisRedis安装远程连接防火墙设置关闭防火墙开启防火墙检查防火墙状态开放指定端口 Redis数据类型和常见命令keysdelEXISTexpired&#xff0c…

day 41:343. 整数拆分;96.不同的二叉搜索树

动态规划 [343. 整数拆分](https://leetcode.cn/problems/integer-break/description/)1. dp数组以及下标名义2. 递归公式3. dp数组如何初始化4. 遍历顺序:遍历i是从前向后遍历&#xff0c;先有dp[i - j]再有dp[i]5. 代码 96.不同的二叉搜索树1. dp数组以及下标名义2. 递归公式…

计组 第二章错题 2.3 浮点数的表示与运算

4.变形补码就是采用双符号位 &#xff0c;不能避免溢出&#xff0c;只是更方便判断是否溢出 5. 9.B 2047:阶码全1表示正无穷 -&#xff08;11-2*(-52&#xff09;) 10.没有想到用移位 10100是20 12.移码看做无符号数 B、无论有无规格化 都要对阶&#xff0c;并没有方便浮…

【Java 多态】面向对象编程の重要概念,多态是什么,附带小案例

博主&#xff1a;_LJaXi Or 東方幻想郷 专栏&#xff1a; Java | 从入门到入坟 专属&#xff1a;六月一日 | 儿童节 Java 多态 多态 &#x1f9a0;在继承中实现多态 &#x1f3a1;在接口中实现多态 &#x1f9ff; 多态 &#x1f9a0; Java的多态是指同一个方法在不同的对象上有…

深度剖析数据在内存中的存储(C语言)

[目录] 目录 #数据类型详细介绍 数据类型介绍 整型家族归类&#xff1a; 浮点型家族归类: 构造类型&#xff1a; 指针类型: 空类型: #整型在内存中的存储 #大小端字节序存储 #浮点数在内存中的存储 为什么会这样&#xff1f; 一&#xff1a;不是全0也不是全1 二&…

皮卡丘File Inclusion

1.File Inclusion(文件包含漏洞)概述 文件包含&#xff0c;是一个功能。在各种开发语言中都提供了内置的文件包含函数&#xff0c;其可以使开发人员在一个代码文件中直接包含&#xff08;引入&#xff09;另外一个代码文件。 比如 在PHP中&#xff0c;提供了&#xff1a; incl…

day 42:01背包问题;416. 分割等和子集

动态规划:01背包问题 01背包问题基础1. 暴力解法2. 二维dp数组01背包1.确定dp数组以及下标的含义2.递推公式3.dp数组如何初始化4.遍历顺序5.测试代码 01背包理论基础&#xff08;滚动数组&#xff09;&#xff1a;将二维dp转换为一维dp1. dp数组以及下标名义2. 递归公式3. dp数…

day 45:爬楼梯进阶版;322. 零钱兑换;279. 完全平方数

爬楼梯进阶版 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 一步一个台阶&#xff0c;两个台阶&#xff0c;三个台阶&#xff0c;…&#xff0c;直到 m个台阶。问有多少种不同的方法可以爬到楼顶呢&#xff1f; 1. dp数组以及下标名义 dp[j]&#xff1a;爬到…

《商用密码应用与安全性评估》第四章密码应用安全性评估实施要点4.5密码应用安全性评估测评工具

目录 测评工具使用和管理要求 测评工具体系 通用测评工具 专用测评工具 典型测评工具概述 测评工具使用和管理要求 测评过程中使用的专用测评工具应通过国家密码管理局的审批或者经检测认证合格。为确保工具测试结果的准确可信&#xff0c;测评机构应确认使用的专用工具是最…

chatgpt赋能python:Python删除离群值

Python 删除离群值 介绍 离群值是指在数据集中远离其他观测值的数据点&#xff0c;可以是数据输入或数据损坏产生的错误。它们通常会对分析造成影响&#xff0c;因此需要处理它们。 Python 是一种流行的编程语言&#xff0c;可以用于处理数据集和删除离群值。本文将介绍 Pyt…