基础前端后台管理系统——完整版权限开发(附带教程及代码)

简介: 完整版权限开发(附带教程及代码)

前言:之前后台管理系统只是写了两个页面并没有分开布局

详情

所用到的技术栈:

vue-element-ui

vue-vuex

vue-router

vue-axios

这篇文章是按照上篇文章进行了大幅度修改,并且使用多页面进行布局。效果看起来会比之前的好一些

下面我们来看一下这种写法的实现效果

726ddfc497ca4b71b1f3a903ba5748cb.gif

登录页面默认为Login页面

004025a8019e4147bf9a8244ce13bf81.png

55a74bcb1c8441c1b6a3d8f9a81e45a2.png

如果这里随便输入路径也会自动跳回登录页面

80f9ed96626549829658abc52808137c.gif

对表单验证进行了改进

59bf2e7db27c444c9c88bc91d9c67b49.png

13e196e2f0e140acbdc2de8718e4e7b2.png

管理员权限页面

38d39f59984d490ab0f49108a87f7d65.png

普通用户页面

9799eca9e89f46eebc61202536ca5fb4.png

把整个页面进行了分割,一个部分一个页面,这样的话复用性比较强

e5a14e05e150412c84df75e4c784017a.png

下面是页面结构

ba3564b0e35543559ee5b42f27e02823.png

b302d7179ef44471bf3d3ed6fec9e759.png

还有一个axios.js上面没有截取到

下面是实战代码:

Header.vue:这个页面就是放在普通用户页面和管理员页面的头部

51f87644553f4c14a18b12bcecf9f479.png

<template>
  <div class="header">
    <div class="header-left">
      <div class="left">KGC后台管理系统</div>
    </div>
    <div class="header-right">
      <div class="header-right__logout">
        <el-button type="danger" size="20" @click="logout">退出</el-button>
      </div>
      <div class="header-right__info">
        <div class="right">{{ name }}</div>
      </div>
    </div>
  </div>
</template>
<script>
import { mapState } from "vuex";
export default {
  name: "Header",
  data() {
    return {
      name: "",
    };
  },
  mounted() {
    this.name = window.sessionStorage.getItem("username");
  },
  methods: {
    logout() {
      this.$confirm("您确定要退出吗, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          window.sessionStorage.clear();
          this.$message({
            message: "你已经退出登陆!请重新登录账号",
            type: "warning",
          });
          this.$router.push({ path: "/" });
        })
        .catch((err) => err);
    },
  },
  computed: {
    ...mapState(["user"]),
  },
};
</script>
<style >
.header {
  height: 50px;
  line-height: 50px;
  background-color: rgb(73, 80, 96);
  padding: 0 50px;
  color: #fff;
}
.left {
  color: #fff;
  float: left;
}
.header-right__info {
  float: right;
  margin: 0 20px;
}
.header-right__logout {
  float: right;
}
</style>

axios.js:直接在生成好的模板的let config={里面写入此接口}

baseURL:  'http://localhost:3000'

Login.vue页面:!!这个页面主要就是布局一下登陆页面,然后对登录按钮进行一个验证,如果数据中的账号中不存在所输入的账号,那么就会判断没有这个账号;

如果所输入的账号与数据中的账号相匹配,那么会判断是否为管理员账号,如果是管理员账号并且输入的密码与数据中的密码相匹配,那么就进入管理员页面;

如果是普通用户的账号,并且输入的密码与数据中的密码相匹配那么就进入用户页面

c5b86d7a1f484df5a2fba6fbdb6b8cd7.png

<template>
  <div class="home">
    <div class="homebox" v-loading="loading">
      <h3>KGC后台管理系统</h3>
      <el-input
        class="input"
        v-model="username"
        style="width: 500px"
        placeholder="用户名"
      ></el-input>
      <el-input
        class="input"
        placeholder="密码"
        style="width: 500px"
        v-model="password"
        show-password
      ></el-input>
      <el-button
        type="primary"
        size="medium "
        @click="login"
        style="width: 500px"
        >登陆</el-button
      >
    </div>
  </div>
</template>
<script>
export default {
  name: "Login",
  data() {
    return {
      username: "admin",
      password: 123,
      loading: false,
    };
  },
  mounted() {},
  methods: {
    login() {
      this.$axios.get("/users").then((v) => {
        this.loading = true;
        const uname = [];
        const passw = [];
        console.log(v);
        const res = v.data;
        for (var i = 0; i < res.length; i++) {
          uname.push(res[i].name);
          passw.push(res[i].pwd);
        }
        console.log(uname);
        console.log(passw);
        console.log(uname.indexOf(this.username) === -1);
        setTimeout(() => {
          if (uname.indexOf(this.username) === -1) {
            this.loading = false;
            this.$message.error("账号不存在,请重新输入!");
          } else if(uname.indexOf(this.username) != -1 && this.username == 'admin'){
            var index = uname.indexOf(this.username);
            console.log(passw[index]);
            if (passw[index] == this.password) {
              this.loading = false;
              this.$message({
                message: "欢迎来到管理员页面!您已经超过了99%的用户",
                type: "success",
              });
              window.sessionStorage.setItem('username',this.username)
              this.$router.push("./Page");
            } else {
              this.loading = false;
              this.$message.error("密码错误,请重新输入");
            }
          }else{
             var index = uname.indexOf(this.username);
            console.log(passw[index]);
            if (passw[index] == this.password) {
              this.loading = false;
              this.$message({
                message: "欢迎登陆用户页面!!!",
                type: "success",
              });
              window.sessionStorage.setItem('username',this.username)
              this.$router.push("./Page2");
            } else {
              this.loading = false;
              this.$message.error("密码错误,请重新输入");
            }
          }
        }, 2000);
      });
    },
  },
};
</script>
<style>
body {
  background-color: rgb(238, 243, 250);
}
.homebox {
  text-align: center;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -150px;
  margin-left: -300px;
  width: 600px;
  height: 300px;
  background-color: rgb(255, 255, 255);
}
h3 {
  padding: 20px 0;
}
.input {
  margin-bottom: 20px;
}
</style>

Page.vue页面:这个页面就是显示了用户管理和商品管理两个导航菜单,当每次点击时会进入所对应的数据页面,也就是存放用户管理中的数据和商品管理中的数据页面

818abe6acb7144ca993dfa2199897337.png

<template>
  <div>
    <el-container>
      <el-col :span="3">
        <el-menu default-active="1" class="el-menu-vertical-demo">
          <el-menu-item index="1" @click="btn1">
            <i class="el-icon-menu"></i>
            <span slot="title">用户管理</span>
          </el-menu-item>
          <el-menu-item index="2" @click="btn2">
            <i class="el-icon-setting"></i>
            <span slot="title">商品管理</span>
          </el-menu-item>
        </el-menu>
      </el-col>
      <el-main>
        <router-view></router-view>
      </el-main>
    </el-container>
  </div>
</template>
<script>
import Header from "../components/Header";
export default {
  name: "Page",
  data() {
    return {
      loading: false,
    };
  },
  mounted() {},
  components: {
    Header,
  },
  methods: {
    btn1() {
      this.$router.push("./user");
    },
    btn2() {
      this.$router.push("./commodity");
    },
    handleOpen(key, keyPath) {
      console.log(key, keyPath);
    },
    handleClose(key, keyPath) {
      console.log(key, keyPath);
    },
  },
};
</script>
<style scoped>
</style>

Page2.vue页面:这个页面就是普通用户的页面,只有一个商品管理的一个导航菜单

1c907ec41a914687a8d88ebf5f914be6.png

<template>
  <div>
    <el-container>
      <el-col :span="3">
        <el-menu default-active="1" class="el-menu-vertical-demo">
          <el-menu-item index="2">
            <i class="el-icon-setting"></i>
            <span slot="title">商品管理</span>
          </el-menu-item>
        </el-menu>
      </el-col>
      <el-main>
        <router-view></router-view>
      </el-main>
    </el-container>
  </div>
</template>
<script>
import Header from "../components/Header";
export default {
  name: "Page",
  data() {
    return {
      loading: false,
    };
  },
  mounted() {},
  components: {
    Header,
  },
  methods: {
    handleOpen(key, keyPath) {
      console.log(key, keyPath);
    },
    handleClose(key, keyPath) {
      console.log(key, keyPath);
    },
  },
};
</script>
<style scoped>
/* .el-main {
  padding: 0;
} */
</style>

User.vue页面:这个页面主要是写了数据项包括后面的一个删除按钮,删除按钮是假删除有两种方法,第二种方法我这里给注释掉了。这里直接获取数据用:data="tableData"获取数据

19678bd4ac8647a982037f16c781ba28.png

<template>
  <div>
    <el-table :data="tableData" v-loading="loading">
      <el-table-column prop="id" label="编号" width="180"> </el-table-column>
      <el-table-column prop="name" label="用户名" width="180">
      </el-table-column>
      <el-table-column prop="role" label="角色"> </el-table-column>
      <el-table-column prop="phone" label="手机号码"> </el-table-column>
      <el-table-column prop="email" label="邮箱"> </el-table-column>
      <el-table-column prop="role" label="操作">
        <template v-slot="scope">
          <el-button
            type="danger"
            size="mini"
            @click="deleteData(scope.$index.tableData)"
            >删除</el-button
          >
          <!--  @click="deleteData(scope.row.name)" -->
          <el-dialog title="提示" width="30%">
            <span class="warcont"
              ><i class="el-icon-warning"></i>是否确定要删除该用户</span
            >
            <span slot="footer" class="dialog-footer">
              <el-button>取 消</el-button>
              <el-button type="primary">确 定</el-button>
            </span>
          </el-dialog>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
import { mapState } from "vuex";
export default {
  name: "User",
  data() {
    return {
      loading: false,
    };
  },
  computed: {
    ...mapState(["tableData"]),
  },
  mounted() {
    this.loading = true;
   setTimeout(() => {
     this.loading = false;
      this.$axios.get("/users").then((res) => {
      const home = res.data;
      this.$store.commit("addrecord", home);
    });
   }, 500);
  },
  methods: {
    //  deleteData(name)
    deleteData(index,row){
              this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.$message({
            type: 'success',
            message: '删除成功!'
          });
        /*    var index = this.tableData.findIndex(item => {
      return item.name === name;
      });
          this.tableData.splice(index,1) */
          this.tableData.splice(index,1)
        }).catch(() => {
          this.$message({
            type: 'info',
            message: '已取消删除'
          });          
        });
    },
    handleClick(tab, event) {
      console.log(tab, event);
    },
  },
};
</script>

Commodity.vue页面:与user.vue页面方法一致,只不过这个页面是商品管理页面的数据

44fffa0576cf4ec4bcc26d71a8a31c08.png

<template>
  <el-table
    border
    style="width: 100%"
    :data="table"
    v-loading="loading"
    element-loading-text="拼命加载中"
  >
    <el-table-column prop="id" label="编号" width="180"> </el-table-column>
    <el-table-column prop="name" label="商品名称" width="180">
    </el-table-column>
    <el-table-column prop="price" label="单价"> </el-table-column>
    <el-table-column prop="number" label="库存"> </el-table-column>
  </el-table>
</template>
<script>
import { mapState } from "vuex";
export default {
  name: "Commodity",
  data() {
    return {
      loading: false,
    };
  },
  mounted() {
    this.loading = true;
    clearTimeout(clear)
    var clear = setTimeout(() => {
       this.$axios.get("/goods").then((v) => {
        const com = v.data;
        this.$store.commit("record", com);
        this.loading = false
      })
    }, 300);
  },
  computed: {
    ...mapState(["table"]),
  },
};
</script>

*404页面:这个页面就是防止页面出错以及复制管理员地址所产生的报错页面,这里没有用到,可以忽略

<template>
  <div class="not-found">
    <h1>啊哦!找不到相关页面o(╥﹏╥)o。</h1>
    <router-link to>
      <p @click="$router.back(-1)">返回上一级页面</p>
    </router-link>
  </div>
</template>
<script>
export default {
name:'Found'
}
</script>
<style lang="less" scoped>
.not-found {
  width: 100%;
  height: 100vh;
  background-color: #6495ED;
  display: flex;
  justify-content: center;
  align-items: center;
  h1 {
    margin: 0;
    color: #fff;
  }
  a {
    color: #E0FFFF;
    font-size: 14px;
    font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
    transform: translateY(10px);
  }
}
</style>

接下来就是路由页面了:

router.js页面:这个页面最为重要,当页面为/时会重定向到Login登录页面,用导航守卫去限制不必要的链接把Page页面和Page2页面作为父路由,把user以及commodity作为子路由进行绑定。并且重写了原型上的push方法,解决一些不知道会报啥错误的信息

import Vue from "vue";
import VueRouter from "vue-router";
import Login from "../views/Login.vue";
import Page from "../views/Page.vue";
import Page2 from "../views/Page2.vue";
import User from "../views/User.vue";
import Commodity from "../views/Commodity.vue";
import Header from "../components/Header.vue";
Vue.use(VueRouter);
const routes = [
  {
    path: "/",
    redirect: "/Login",
  },
  {
    path: "/Login",
    name: "Login",
    component: Login,
  },
  {
    path: "/page",
    name: "Page",
    components: {
      default: Page,
      Header,
    },
    children: [
      {
        path: "/page",
        redirect: "/page/user",
      },
      {
        path: "/page/user",
        name: "User",
        component: User,
      },
      {
        path: "/page/commodity",
        name: "Commodity",
        component: Commodity,
      },
    ],
  },
  {
    path: "/page2",
    name: "Page2",
    components: {
      default: Page2,
      Header,
    },
    children: [
      {
        path: "/page2",
        redirect: "/page2/commodity",
      },
      {
        path: "/page2/commodity",
        name: "Commodity",
        component: Commodity,
      },
    ],
  },
];
const router = new VueRouter({
  routes,
  mode: "history",
});
router.beforeEach((to, from, next) => {
  if (to.path == "/login") {
    next();
  } else {
    let token = window.sessionStorage.getItem("username");
    console.log(token);
    if (!token) {
      next("/login");
    } else {
      next();
    }
  }
});
const originalPush = VueRouter.prototype.push;
// 重写了原型上的push方法,统一的处理了错误信息
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this, location).catch((err) => err);
};
export default router;

store.js页面:这个页面主要是用来存储获取到的数据并把他们放在数组中,使用载荷的方式去其他页面进行调用

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
  state: {
    tableData:[],
    table:[],
    user:JSON.parse(window.sessionStorage.getItem('user') || '[]'),
  },
  // 存储用户管理页面数据
  mutations: {
    addrecord(state,preload){
      state.tableData = preload
      window.sessionStorage.setItem('rightsList',JSON.stringify(preload))
    },
    // 存储商品管理数据
    record(state,preload){
      state.table = preload
      console.log(state.table);
      window.sessionStorage.setItem('liftList',JSON.stringify(preload))  
    },
    setUser(state,preload){
    state.user = preload;
    window.sessionStorage.setItem('user',JSON.stringify(state.user));
  },
  },
  actions: {
  },
  modules: {
  }
})

接下来就是一些常用的配置文件页面

main.js

import Vue from 'vue'
import './plugins/axios'
import App from './App.vue'
import store from './store'
import router from './router'
import './plugins/element.js'
Vue.config.productionTip = false
new Vue({
  store,
  router,
  render: h => h(App)
}).$mount('#app')

App.vue页面:主要是用来渲染公共样式

<template>
  <div id="app">
    <router-view name="Header"></router-view>
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: "app",
};
</script>
<style>
*{margin: 0;padding: 0;}
</style>
element.js
import Vue from 'vue'
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(Element)
相关文章
|
前端开发 JavaScript 安全
7.6K Star Shadcn Admin:颜值与实力并存的后台管理系统,前端开发者的新宠!
"基于 Shadcn UI 和 Vite 打造的现代化管理后台,开箱即用的响应式设计 + 无障碍访问,让后台开发从未如此优雅!" —— 来自 GitHub 7.6K 星认证
3233 26
|
JavaScript 前端开发 Java
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。
1209 1
|
人工智能 自然语言处理 前端开发
DeepSite:基于DeepSeek的开源AI前端开发神器,一键生成游戏/网页代码
DeepSite是基于DeepSeek-V3模型的在线开发工具,无需配置环境即可通过自然语言描述快速生成游戏、网页和应用代码,并支持实时预览效果,显著降低开发门槛。
2001 93
DeepSite:基于DeepSeek的开源AI前端开发神器,一键生成游戏/网页代码
|
9月前
|
存储 前端开发 安全
实现“永久登录”:针对蜻蜓Q系统的用户体验优化方案(前端uni-app+后端Laravel详解)-优雅草卓伊凡
实现“永久登录”:针对蜻蜓Q系统的用户体验优化方案(前端uni-app+后端Laravel详解)-优雅草卓伊凡
374 5
|
存储 消息中间件 前端开发
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
校园圈子系统校园论坛小程序采用uni-app前端框架,支持多端运行,结合PHP后端(如ThinkPHP/Laravel),实现用户认证、社交关系管理、动态发布与实时聊天功能。前端通过组件化开发和uni.request与后端交互,后端提供RESTful API处理业务逻辑并存储数据于MySQL。同时引入Redis缓存热点数据,RabbitMQ处理异步任务,优化系统性能。核心功能包括JWT身份验证、好友系统、WebSocket实时聊天及活动管理,确保高效稳定的用户体验。
693 4
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
|
自然语言处理 前端开发 IDE
用通义灵码全新智能体+MCP实现从设计稿到前端代码,个人免费用
通义灵码全新升级,发布国内首个支持“自主决策+工具链闭环”的编程智能体,面向个人免费!新增功能包括智能体模式、混合推理模型Qwen3支持、全面集成MCP中文社区(涵盖2400+服务)及长期记忆能力。用户可通过IDE插件使用,兼容主流开发环境如JetBrains、VS Code和Visual Studio。教程展示如何将MasterGo设计稿转化为前端代码,简化开发流程。探索链接:[通义灵码官网](https://lingma.aliyun.com/)。
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
1596 14
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
1018 0
|
SpringCloudAlibaba JavaScript 前端开发
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
分布式组件、nacos注册配置中心、openfegin远程调用、网关gateway、ES6脚本语言规范、vue、elementUI
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架

热门文章

最新文章

  • 1
    前端如何存储数据:Cookie、LocalStorage 与 SessionStorage 全面解析
    1179
  • 2
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(九):强势分析Animation动画各类参数;从播放时间、播放方式、播放次数、播放方向、播放状态等多个方面,完全了解CSS3 Animation
    521
  • 3
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(八):学习transition过渡属性;本文学习property模拟、duration过渡时间指定、delay时间延迟 等多个参数
    405
  • 4
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(七):学习ransform属性;本文学习 rotate旋转、scale缩放、skew扭曲、tanslate移动、matrix矩阵 多个参数
    399
  • 5
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(六):全方面分析css的Flex布局,从纵、横两个坐标开始进行居中、两端等元素分布模式;刨析元素间隔、排序模式等
    514
  • 6
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(五):背景属性;float浮动和position定位;详细分析相对、绝对、固定三种定位方式;使用浮动并清除浮动副作用
    685
  • 7
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(四):元素盒子模型;详细分析边框属性、盒子外边距
    1240
  • 8
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(三):元素继承关系、层叠样式规则、字体属性、文本属性;针对字体和文本作样式修改
    278
  • 9
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
    1027
  • 10
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(一):CSS发展史;CSS样式表的引入;CSS选择器使用,附带案例介绍
    478