后台管理系统

news2025/1/21 21:53:10

后台管理系统主要是我们内部人员使用的一款用来管理我们产品的一个系统,然后呢,我们今天写的呢是一个电商的后台管理系统。主要是可以用来管理我们的用户还有我们是商品的。

我们这个系统呢采用的是一个前后端分离的模式,主要是使用后端给我们的接口来实现的,我们前端呢是使用了 Vue 的框架,界面呢我们使用了 element-ui 的框架。

它里面呢包含有几个模块,有我们的登录页,用户页,角色页,主要的是商品页面,还有一个是图表的页面,那么下面呢,我么下面得我们来说一说基本功能得一个实现


对于axios的二次封装

因为我们在项目中会有一些错误的信息还要向我们的后台发送token来请求数据,还有可能会在网络不好是,出现多次请求的一个现象发生,如果都将他们写在我们的页面中,容易造成代码混乱,代码冗余,也会增加我们的一个工作量。

所以在项目开始前,我们可以对axios进行一个简单的二次封装

在请求拦截器中我们可以传递token值,响应拦截器可以处理错误的信息,还可以取消重复的请求

// 请求拦截器
serve.interceptors.request.use((config) => {
    // 检查是否有重复的请求,如果有就删掉
    rem(config)
        // 把当前请求添加到pindingRequest对象中
    req(config)
        // 把token传到后台
    config.headers.Authorization = localStorage.getItem("token")
    console.log(config);
    return config
}, (err) => {
    return Promise.reject(err)
})



    // 响应拦截器
serve.interceptors.response.use((config) => {

    // 无效token,弹出提示框
    if (flag) {
        flag = false
        if (config.data.meta.msg == "无效token") {
            MessageBox.confirm('登录状态已过期, 是否重新登录?', '提示', {
                confirmButtonText: '重新登录',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
                // 原生js跳转页面,不能用element-ui的,this不能用
                location.href = "/#/login"
            }).catch(() => {});
        }
    }

    console.log(config);
    // 状态是以下这些,就提示错误信息
    if (config.data.meta.status === 400 || config.data.meta.status === 401 || config.data.meta.status === 403 || config.data.meta.status === 404 || config.data.status === 500) {
        Message.error({
            duration: 1000,
            message: config.data.meta.msg
        })
    }
    return config.data
}, (err) => {
    rem(err.config || {})
    if (axios.isCancel(err)) {
        Message.error("已取消重复请求")
    } else {

    }


    console.log(err);
    let { message } = err
    if (message == "Network Error") {
        message = "接口连接异常"
    } else if (message.includes("timeout")) { //返回的错误信息,如果包含timeout,就赋值网络异常
        message = "网络异常"
    }

    // 提示错误信息
    Message.error({
        duration: 2000,
        message: message
    })

    return Promise.reject(err)
})



// 这是一个唯一的key值
function key1(config) {
    let { methods, url, params, data } = config
    return [methods, url, JSON.stringify(params), JSON.stringify(data)].join("&")
}

// 定义map结构
let map = new Map()

// 判断是否是第一次请求(去重)
function req(config) {
    let key = key1(config)
    config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
        if (!map.has(key)) {
            map.set(key, cancel)
        }
    })
}

// 取消重复的请求
function rem(config) {
    let key = key1(config)
    if (map.has(key)) {
        let cancel = map.get(key)
        cancel(key)
            // 移除上一次请求
        map.delete(key)
    }
}


登录页面

登录页面呢我们可以使用element-ui组件来实现页面的布局,表单校验也可以使用它里面提供给我们的,然后我们在登录成功之后,它会返回给我们一个token值,我们在后续写其他页面请求数据的时候也是需要用到这个token,所以我们需要将他存储到本地中,方便我们使用。


登录鉴权

如果我们在没有登录的时候,是不能访问我们其他的页面的,所以我们需要实现一个登录鉴权的功能,如果你没有token,是不能访问我的页面的。

我们可以在main.js中定义一个全局的路由守卫,首先判断当前是否是登录页面,如果当前不是登陆页面,我们在判断本地中有没有token值,如果你既不是在登录页面,本地也没有token值,那么我就让你去登录页,这样我们可以实现一个登录鉴权的功能。

这里需要注意的是路由守卫中,如果我们不写next(),那么是无法进行跳转页面的

// 路由守卫
router.beforeEach((to, from, next) => {
    // 判断当前是否是登录页面
    if (to.path != "/login") {
        // 判断有没有token值
        if (!localStorage.getItem("token")) {
            // 跳转到登录页面
            next("/login")
        }
    }
    // 跳转页面
    next()
})

首页

当我们登录成功之后,需要跳转到我们的首页

 

 左侧是我们的路由菜单,在这里我们可以使用静态路由动态路由两种方式

静态路由

静态路由是路由的一种,他需要我们去手动的添加到我们的路由页面中,如果后端又添加了一个路由的话,我们还需要再手动将他加进去,如果后端修改完,没有告诉你的话,那么就芭比Q了,就找不到页面了。

静态路由的话,大家应该都会,这里就不多叙述了

//静态路由
{
             path: '/admin/home',
             name: 'admin_home',
             component: () =>
                 import ('./views/admin/home.vue'),
             children: [{
                     path: '/admin/welcome',
                     name: 'admin_welcome',
                     component: () =>
                         import ('./views/admin/welcome.vue')
                 }, {
                     path: '/admin/users',
                     name: 'admin_users',
                     component: () =>
                         import ('./views/admin/users.vue')
                 }, {
                     path: '/admin/roles',
                     name: 'admin_roles',
                     component: () =>
                         import ('./views/admin/roles.vue')
                 }, {
                     path: '/admin/rights',
                     name: 'admin_rights',
                     component: () =>
                         import ('./views/admin/rights.vue')
                 }, {
                     path: '/admin/goods',
                     name: 'admin_goods',
                     component: () =>
                         import ('./views/admin/goods.vue')
                 }]
}

动态路由

动态路由也是路由的一种,我们前端呢可以使用js将树状结构转为列表结构再将它动态的添加到我们的路由表中,这个时候如果后端再次新增路由,那么他就可以动态的添加进去,就不需要我们再次手动的添加了

动态路由的实现,主要是通过递归函数,将树状结构转为列表结构,然后通过router实例的addRoute方法,动态的添加到我们的二级路由中。

const routes = [{
    path: "/home",
    name: "Home",
    component: Home,
    redirect: "/welcome",
    children: [{
            path: "/welcome",
            name: "welcome",
            component: () =>
                import ("./views/admin/welcome.vue")
        }
    ]
}]


//递归函数遍历数据
function fn(data) {
    let arr = []

    function deep(data) { 
        data.forEach(item => { //遍历树状结构
            if (item.children.length) { //如果他下面的children属性还有内容
                deep(item.children) //就让他一直查找
            } else {
                arr.push({
                    path: "/" + item.path,
                    name: item.authName,
                    component: () =>
                        import (`@/views/admin/${item.path}.vue`)
                })
            }
        })
    }
    deep(data)
    return arr
}

const router = new Router()  //router实例化

function loadRoute() {
    let token = localStorage.getItem("token")
    let menuList = JSON.parse(localStorage.getItem("menuList"))

    if (token && menuList) { //如果本地有token和菜单列表
        let menu = fn(menuList) //进行递归遍历
        menu.forEach(item => {
            router.addRoute("Home", item) //通过addRoute将他填进二级路由中
        })
    }
}
loadRoute()

那么走到这一步,我们的动态路由就基本是实现了。

然后我们的路由也不可能全部是动态的,里面还会有一些不需要动态添加的路由,比如说我们的登录页面,这里我们就可以将他写在我们的白名单中

const whiteList = ["/login"] //路由白名单

router.beforeEach((to, form, next) => {  //前置路由守卫
    let token = localStorage.getItem("token")
    if (token) { //如果token值存在
        next()  //就直接进行跳转
    } else {
        if (whiteList.indexOf(to.path) != -1) { //路由白名单中的,查找到就跳转
            next()
        } else {
            next("/login") //否则跳转到登录页面
        }
    }
})

这里需要注意的是我们在登录的时候也是需要去调用方法的,不然会出现找不到路由的问题,不管点击哪个,都会跳转到我们的登录页面,解决呢就是再次调用一下方法,再调用时可能会有同步和异步的问题,可能获取不到数据,需要将他改为同步,可以使用async await改为同步执行。


用户列表

用户列表页面主要是用来管理使用这个后台系统的用户的,可以给用户设置角色,不同的角色会有不同的权限。

基本的增删改查我们就不多说了。主要是有一个分配权限的功能,我们需要获取到当前用户的id和新增角色的id,发送到后台就可以返回响应的数据了


角色列表

然后是我们的角色列表,角色列表的主要功能是给我们的角色分配权限的,他里面是一个tree组件

我们在打开弹出框的同时获取到我们角色的权限 ,将他渲染出来

这里我们可以使用递归函数判断每一层数据有没有children属性,如果有就一直递归循环,如果没有了,就将它的id值添加到我们的一个数组中,再使用tree组件的方法default-checked-keys,将数组渲染到页面中。

在分配权限的时候呢,tree给我们提供了两个方法getCheckedKeys和getHalfCheckedKeys,这两个方法可以获取我们选中数据的id和半选中节点的id,拿到这两个id后,传递到后台那么就可以实现分配权限的一个功能了


商品管理

商品管理是我们这个后台项目中主要的模块,分为商品分类和商品列表

商品分类中我们主要是有一个级联选择器,需要将拿到的数据渲染在级联选择器中

 在添加分类的时候需要获取到我们的父级id,还有需要添加到的层级id,拿到这两个id后,我们就可以向后台发送数据,将他添加到我们相应的分类中

分类参数是用来给我们的分类数据添加动态参数和静态属性的

 这里注意只能为三级分类设置相关的参数,只有当我们选择了分类的时候,才可以设置相关的参数

 当我们在点击动态参数和静态属性的时候会去请求相应的接口,来返回不同的数据,渲染在我们的页面中,当我们新增属性的时候,需要在后台返回给我们的数据中添加一个标识符,用来隐藏和显示输入框,如果绑定的是全局的标识符,就会把全部的输入框都改变状态。

这里需要注意一下,就是后台返回的数据是字符串的格式,如果我们要将他渲染到页面中,还需要使用字符串的split方法,将他转换为数组,转换完毕后渲染到页面上就可以了

商品列表中有一个添加商品功能,因为我们用的是动态路由的方式,会找不到这个页面,所以我们需要手动的添加一个路由

在这里我们需要先选择商品分类,才可以去渲染其他的数据,不然是左侧的tab是不能切换的,这里我们可以使用tab提供的 before-leave 方法,这个方法是在tab切换前执行的一个方法,如果返回的是false,那么就不会进行跳转

当我们点击商品参数和商品属性的时候需要请求不同的接口,将返回的数据渲染出来

这里我们使用 el-checkbox-group 需要给他绑定v-model,当我们选中一些参数时 ,会自动的添加到绑定的数组中,注意在请求接口时在在用join方法转换为字符串

然后是商品图片的功能,这里我们使用upload组件,这里需要注意的是图片上传时需要单独的请求一个接口,并且传递token值,当上传成功后,将tem_path以对象的形式添加到我们的数组中

 

商品内容区域是一个富文本,我们可以下载 vue-quill-editor 依赖,挂载到我们的vue中,然后使用的时候,需要使用v-model绑定一下

最后将所有数据上传到后台,那么商品的添加就完成了


数据统计

最后呢是一个数据统计,这个模块主要是给我们的领导看的,将统计好的数据绘制成图表,在渲染到页面中,那么这里就可以使用 echarts 图表来做,它里面给我们提供了很多的图表供我们使用,有折线图,柱状图等等

这里我们使用的是折线图

 需要我们提前在页面上写好一个带有宽高的盒子,然后请求数据

在拿到接口返回的数据后,我们需要将对应的数据给到对应的字段上

option: {
        title: {
          text: "数据报表"
        },
        color: [
          "#5470c6",
          "#91cc75",
          "#fac858",
          "#ee6666",
          "#73c0de",
          "#3ba272",
          "#fc8452",
          "#9a60b4",
          "#ea7ccc"
        ],
        tooltip: {},
        legend: {},
        grid: {},
        xAxis: [],
        yAxis: [],
        series: []
      }


//基于准备好的dom,初始化echarts实例
let myChart = echarts.init(document.getElementById("main"));

    let res = await getReports();

    this.option.legend = res.data.legend;
    this.option.series = res.data.series;
    this.option.xAxis[0].data = res.data.xAxis[0].data;
    this.option.yAxis = res.data.yAxis;

    myChart.setOption(this.option);


 

当然我们可能会在大屏上显示我们图表,那么这个时候就需要给他自适应我们窗口的大小

// 窗口大小改变时,监听图表大小,自适应一下
    window.onresize = function () {
      myChart.resize();
    };

大家也可以自己去封装一些组件来使用,本次项目中呢,也有一些自己封装的组件,比如说dialog组件和分页组件,那么这里就不多说了,毕竟我们要学会面向 百度 编程嘛

那么进行这里后,我们的项目就基本上是结束了,有什么不足,也希望大家多多指教!

在这里呢也预祝我们热爱编程的小伙伴们,更上一层楼,越来越棒!

这里呢是本次项目的源码,欢迎大家前来

335love/zhilei - Gitee.com

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

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

相关文章

Vue 当页面进入全屏状态时element-ui的el-select下拉菜单不显示问题

在前两天进行页面全屏时,一切都还好好的,可当使用element-ui中的el-select时,下拉菜单却怎么也显示不出来,但只要退出全屏状态,立马就好。 非全屏时: 全屏时: 开始我以为是层级问题&#xff0…

前端加载高德离线地图的解决方案

核心是需要下载地图瓦片放在本地,脱离在线地图服务,实现离线加载地图。使用BIGMap工具下载地图离线瓦片到本地 下载地址:http://www.bigemap.com/reader/download/detail201802015.html BIGEMAP GIS Office-全能版需要注册试用版(…

web前端面试宝典——带你直击面试重难点(40个经典题目,涵盖近90%的考点,码字2w,干货满满!)

系列文章目录 JavaScript 知识梳理,收录了web前端面试 95%以上 的高频考点,满满的干货。给你做一个高效的知识梳理,为你的面试保驾护航! 内容参考链接HTML & CSS 篇HTML & CSS 篇JavaScript 篇(一)…

【微信小程序】条件渲染和列表渲染

🍒🍒 观众老爷们好啊,牛牛又更新了,上文我们详细了解了微信小程序中的事件绑定,那么今天我们就来讲讲WXML语法中的列表渲染和条件渲染,它俩也是非常重要的知识点,赶紧学起来吧。 🍒&…

如何更改ElementUI组件的图标大小以及标签属性

话不多说,直接上菜。 ElementUI提供的Rate评分组件的默认大小是这样的 图标太小了,想设置宽高、行高、尺寸,但代码不起作用。 打开浏览器调试,发现是用font-size设置才有用。 由此代码存在优先级问题,要提高优先级。…

vscode里面使用vue的一些插件,方便开发

1、vue 2 Snippets (vue语法提示) vue提示这个也可以 1.1 Vue VSCode Snippets 2、vetur Vetur支持.vue文件的语法高亮显示,除了支持template模板以外 3、Element UI Snippets(饿了么的提示) 4、indent-rainbow(缩进高亮提示) 5…

Vue Element table表格实现表头自定义多类型动态筛选 , 目前10种筛选类型,复制即用

一、效果图 目前10种筛选类型 看看是否是你需要的,本文可能有点长 ,我尽可能的给讲清楚,包括源码附上 二、无聊发言 点击当前行跳转部分数据后缀追加图标某列数据根据状态增加颜色标识 三、前言 实现图中的表格,特定的两个要求&…

css-两种画弧线方法

第一种&#xff1a;::after <template><view><view class"bg"></view></view> </template> <style> .bg{background-color: pink; } .bg::after{content: ;position: absolute;width: 160%;height: 100px;background: sk…

多项目版本管理:monorepo 策略

monorepo 是什么 一个产品会有多个项目&#xff0c;每个项目之间会存在版本同步的问题&#xff0c;如何在其中一个项目发布上线后&#xff0c;保证每个项目版本升级后的版本同步问题&#xff0c;提出的解决方案就是 monorepo 策略。 monorepo 是一种将多个项目代码存储在一个…

【小程序项目开发-- 京东商城】uni-app之商品列表页面 (上)

&#x1f935;‍♂️ 个人主页: 计算机魔术师 &#x1f468;‍&#x1f4bb; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 该文章收录专栏 ✨ 2022微信小程序京东商城实战 ✨ 文章目录一、前言介绍二、创建goodlist 分支&#xff08;选读*)三、商品列…

H5页面跳转小程序的三种方式

文章目录前言一、web-view标签返回小程序1.小程序启动页面只写web-view标签跳转到授权页面。2.编写auth.html3、把auth.html放到服务器就可以测试访问&#xff0c;打开小程序默认进入启动页面中的webview跳转到H5&#xff0c;授权成功后&#xff0c;通过wx.miniProgram.reLaunc…

Vue自定义网页顶部导航栏

Vue自定义web网页顶部导航栏 说明&#xff1a;此组件是为论坛类项目定制的一个实用的顶部导航栏&#xff0c;当然也可以用于其他的Web项目&#xff0c;只需要稍作修改便可以达到想要的效果。其中导航栏包含了搜索栏&#xff0c;用户头像&#xff0c;以及基本的导航标题。导航栏…

uniapp小程序自定义顶部导航栏,输入框软键盘把顶部顶上去的解决方法

首先在小程序input标签增加:adjust-position"false"的属性&#xff0c;然后已经可以把软键盘不使上方顶出&#xff0c;但是输入框也会因此被遮挡 解决方法&#xff1a;在input输入框聚焦的方法中增加操作 focus"inputBindFocus" 定义方法 inputBindFoc…

【vue3】基础概念的介绍

⭐【前言】 首先&#xff0c;恭喜你打开了一个系统化的学习专栏&#xff0c;在这个vue专栏中&#xff0c;大家可以根据博主发布文章的时间顺序进行一个学习。博主vue专栏指南在这&#xff1a;vue专栏的学习指南 &#x1f973;博主&#xff1a;初映CY的前说(前端领域) &#x1f…

Vue提升:理解vue中的 slot-scope=“scope“

slot是插槽&#xff0c;slot-scope“scope“语义更加明确&#xff0c;相当于一行的数据&#xff0c;在实际开发中会碰到如下的场景 这个工作状态是变化的&#xff0c;而我们就可以通过后端返回的具体值来判断这里应该显示什么样的内容&#xff0c;具体代码如下 <el-table-co…

利用vue实现登陆界面及其跳转

1.做登录框 步骤&#xff1a; &#xff08;1&#xff09; 创建vue项目&#xff0c;使用vite方式创建&#xff1b;npm init vuelatest &#xff08;2&#xff09;项目结构&#xff1a; src&#xff1a;代码书写位置&#xff1b; app.vue&#xff1a;根组件&#xff1b; main…

vue配置开发环境和生产环境

介绍 本文主要介绍开发、测试以及生产环境的配置。&#xff08;以下内容可根据需求进行配置&#xff09; 步骤 1、在src同级目录也就是根目录下新建文件&#xff1a;.env.development&#xff08;开发环境&#xff09;、.env.test&#xff08;测试环境&#xff09;、.env.pr…

微信小程序授权获取用户信息之wx.getUserInfo 切换到 wx.getUserProfile的使用(已弃用)

目录更新&#xff1a;wx.getUserProfile() 已弃用背景一、小程序获取用户信息相关接口调整说明二、wx.getUserProfile的使用1. 之前的wx.getUserInfo接口的使用2. 现在的wx.getUserProfile接口的使用三、wx.getUserInfo 切换到 wx.getUserProfile前后对比更多问题可参考&#x…

详解v-for中:key属性的作用

举个栗子 不设置key <div id"app"><div><input type"text" v-model"name"><button click"add">添加</button></div><ul><li v-for"(item, i) in list"><input type&qu…

众多mock工具,这一次我选对了

文章目录写在前面Mock介绍Mock能解决什么问题?传统Mock解决方案Postman接口测试工具Mock js第三方库Eolink解决方案全局Mock高级Mock返回结果Mock智能内置Mock智能自定义Mock约束条件MockEolink的Mock解决方案的优势:写在最后写在前面 交战之前&#xff0c;战士必先利其兵器&…