当前位置:   article > 正文

vue2.0 从0到1搭建后台管理项目(一)_vue从零开始搭建后台管理系统

vue从零开始搭建后台管理系统

一.使用版本

  • Node.js: 14.3.0
  • Vue: 2.6.10
  • Npm: 6.14.5
  • Webpack: 4.0.0
  • Node-sass: 4.14.1
  • Sass-loader: 7.3.1

二.使用技术

  • Vue 2.0
  • vue-router 路由
  • element-ui 组件
  • vuex 状态存储工具
  • axios 数据交互

三. 环境搭建

  1.      1. 安装node (node -v查询版本号)
  2.            node 安装 (下载地址:https://nodejs.org/en/download/)

  3.      2. 安装淘宝镜像

  4. npm install -g cnpm --registry=https://registry.npm.taobao.org
    1.      3. 安装 webpack,以全局的方式安装

  5. npm install webpack -g
  6.      4.全局安装vue以及脚手架vue-cli

  7. npm install @vue/cli -g --unsafe-perm
  8.      5.创建vue项目 mall-manage-system(项目名称)         

  9. vue create mall-manage-system

           5.1 选择使用vue版本直接回车

  10.    6. 运行当前项目 这个整个项目就搭建好了

   npm run serve 

四. 搭建项目

 1. 引入组件库 - 此项目使用element - ui组件库

      https://element.eleme.cn/#/zh-CN/component/installation

在main.js中引入

  1. //新添
  2. import ElementUI from 'element-ui'
  3. //新增
  4. import 'element-ui/lib/theme-chalk/index.css'
  5. //新增
  6. Vue.use(ElementUI)

2.创建路由 (router/index.js)

创建登录页面路由/页面路由

  1. import Vue from 'vue'
  2. import Router from 'vue-router'
  3. Vue.use(Router)
  4. /* Layout */
  5. import Layout from '@/layout'
  6. /**
  7. * 处理控制台的下面报错
  8. * Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/home/list".
  9. * 添加以下代码
  10. */
  11. const originalPush = Router.prototype.push
  12. Router.prototype.push = function push(location) {
  13. return originalPush.call(this, location).catch(err => err)
  14. }
  15. export const constantRoutes = [
  16. // 重定向,用来指向一打开网页就跳转到哪个路由
  17. {
  18. path: '/',
  19. redirect: '/login'
  20. },
  21. //login
  22. {
  23. path: '/login',
  24. component: () => import('@/views/login/login'),
  25. },
  26. {
  27. path: "/404",
  28. component: () => import("@/views/error-page/404")
  29. },
  30. {
  31. path: "/401",
  32. component: () => import("@/views/error-page/401")
  33. },
  34. ]
  35. const createRouter = () => new Router({
  36. scrollBehavior: () => ({
  37. y: 0
  38. }),
  39. routes: constantRoutes
  40. })
  41. const router = createRouter()
  42. export default router

3.创建登录界面

  1. <template>
  2. <div class="sign-in">
  3. <el-row>
  4. <el-col :span="12" :offset="6">
  5. <h1>后台系统</h1>
  6. <el-form
  7. :model="loginForm"
  8. :rules="loginRules"
  9. ref="ruleForm"
  10. label-width="100px"
  11. class="demo-ruleForm"
  12. >
  13. <el-form-item label="手机号:" prop="user_phone">
  14. <el-input v-model="loginForm.user_phone"></el-input>
  15. </el-form-item>
  16. <el-form-item label="密码:" prop="sort">
  17. <el-input v-model="loginForm.password" type="password"></el-input>
  18. </el-form-item>
  19. <el-form-item>
  20. <el-button type="primary" @click="handleLogin('ruleForm')">
  21. 立即登录
  22. </el-button>
  23. <el-button @click="resetForm('ruleForm')">重置</el-button>
  24. </el-form-item>
  25. </el-form>
  26. </el-col>
  27. </el-row>
  28. </div>
  29. </template>
  30. <script>
  31. import { setBasicInfo } from "@/utils/auth";
  32. import { Login, signIn } from "../../api/login/login";
  33. import store from "@/store";
  34. export default {
  35. data() {
  36. return {
  37. loginForm: {
  38. user_phone: "admin",
  39. password: "123123",
  40. },
  41. loginRules: {
  42. name: [{ required: true, message: "请输入手机号", trigger: "blur" }],
  43. password: [{ required: true, message: "请输入密码", trigger: "blur" }],
  44. },
  45. };
  46. },
  47. methods: {
  48. async handleLogin(formName) {
  49. this.$refs[formName].validate(async (valid) => {
  50. if (valid) {
  51. const res = await Login()
  52. if(!res.success) return this.$message.error('错了哦!系统错误!');
  53. const data =res.data
  54. if(this.loginForm.user_phone === data.user_phone&&this.loginForm.password ===data.password){
  55. // const res2 = await signIn();
  56. const menu = await setBasicInfo()
  57. await store.dispatch('apply/getApply')
  58. const redirect = menu[0].path + '/' + menu[0].children[0].path
  59. await this.$router.push(redirect);
  60. }else{
  61. this.$message.error('错了哦!账号密码不正确!');
  62. }
  63. }
  64. });
  65. },
  66. resetForm(formName) {
  67. this.$refs[formName].resetFields();
  68. },
  69. },
  70. };
  71. </script>
  72. <style scoped lang="scss">
  73. .sign-in {
  74. padding-top: 100px;
  75. }
  76. h1 {
  77. text-align: center;
  78. }
  79. </style>

   使用axios进行交互

   3.1 引入axios

         官网: http://www.axios-js.com/

   3.2 安装 axios 

npm install axios -S

    安装完成后在package.json中dependencies下可以看到安装是否成功

   3.3 点击登录进行接口请求获取token,将获取到的返回信息可存储到storage中或VUEX中

   3.4 设置路由守卫进行权限判断进入项目

         views下创建 permission.js文件

  1. /* eslint-disable prefer-const */
  2. import router from './router'
  3. import NProgress from 'nprogress' // progress bar
  4. import 'nprogress/nprogress.css' // progress bar style
  5. import getPageTitle from '@/utils/get-page-title'
  6. import store from '@/store'
  7. import {getToken, toLogin, setBasicInfo} from '@/utils/auth'
  8. //NProgress.configure({ showSpinner: false }) // NProgress Configuration
  9. NProgress.configure({
  10. easing: 'ease', // 动画方式
  11. speed: 500, // 递增进度条的速度
  12. showSpinner: false, // 是否显示加载ico
  13. trickleSpeed: 200, // 自动递增间隔
  14. minimum: 0.3 // 初始化时的最小百分比
  15. })
  16. // 白名单
  17. const whiteList = ['/login'] // no redirect whitelist.
  18. // 挂载路由导航守卫:to表示将要访问的路径,from表示从哪里来,next是下一个要做的操作
  19. /**
  20. * to: Route: 即将要进入的目标 路由对象
  21. * from: Route: 当前导航正要离开的路由
  22. * next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
  23. * next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
  24. * next(false): 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
  25. * next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
  26. * next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
  27. */
  28. router.beforeEach(async (to, from, next) => {
  29. NProgress.start()
  30. document.title = getPageTitle(to.meta.title)
  31. if (whiteList.includes(to.path)) {
  32. next()
  33. } else {
  34. const token = getToken()
  35. if (!token) {
  36. await toLogin()
  37. return
  38. }
  39. if (store.state.permission.asyncRouteFlag === '1') {
  40. next()
  41. } else {
  42. try {
  43. const menu = await setBasicInfo(token)
  44. next({...to, replace: true})
  45. await store.dispatch('apply/getApply')
  46. } catch (e) {
  47. console.log(e, 'e')
  48. }
  49. }
  50. }
  51. })
  52. router.afterEach(() => {
  53. NProgress.done()
  54. })

utils/get-page-title.js

  1. import defaultSettings from '@/settings'
  2. const title = defaultSettings.title || 'SaaS'
  3. export default function getPageTitle(pageTitle) {
  4. if (pageTitle) {
  5. return `${pageTitle} - ${title}`
  6. }
  7. return `${title}`
  8. }

utils/auth.js

  1. import Cookies from "js-cookie";
  2. import { Message } from 'element-ui'
  3. import router from '@/router'
  4. import { userList } from "@/api/login/login";
  5. import { getArea } from '@/api/common'
  6. import store from "@/store";
  7. import { generateRoutes } from '@/utils/generteRoute'
  8. // 设置token
  9. export const setToken = (token) => {
  10. storage.setItem(tokenKey, token)
  11. }
  12. // 获取token
  13. export const getToken = () => {
  14. return storage.getItem(tokenKey) || ''
  15. }
  16. /**
  17. * 删除cookie中的token
  18. * @returns {*}
  19. */
  20. export function removeToken() {
  21. return Cookies.remove(TokenKey);
  22. }
  23. const storage = window.localStorage
  24. export const tokenKey = 'token'
  25. // 清除token
  26. export const clearToken = () => {
  27. storage.removeItem('swapOperationInfo')
  28. storage.removeItem('swapOperationCompany')
  29. store.dispatch('permission/setPreToken', '')
  30. storage.removeItem(tokenKey)
  31. }
  32. // 跳转到登录页面
  33. // 跳转到登录页面
  34. export const toLogin = () => {
  35. clearToken()
  36. // if (process.env.NODE_ENV === 'development') {
  37. // router.replace('/login')
  38. // } else {
  39. // setTimeout(() => {
  40. // // window.location.replace(`${process.env.VUE_APP_LOGIN_PAGE}?active=${store.getters.app_id}`)
  41. // window.location.replace(`${window.location.origin}/#/login`)
  42. // }, 500)
  43. // }
  44. // // window.location.replace(`${process.env.VUE_APP_LOGIN_PAGE}?active=${store.getters.app_id}`)
  45. }
  46. /**
  47. * 根据token获取用户和权限信息
  48. * @param token
  49. * @returns {Promise<unknown>}
  50. */
  51. export const setBasicInfo = async (token) => {
  52. const res = await userList(token);
  53. return new Promise(async (resolve, reject) => {
  54. if (res.success) {
  55. const route = (res.data || {}).route || [];
  56. if (!route.length) {
  57. Message({
  58. message: "抱歉!你没有任何页面的访问权限!",
  59. duration: 4000,
  60. type: "error",
  61. });
  62. } else {
  63. const userInfo = {
  64. telephone: res.data.telephone,
  65. role_name: res.data.role_name,
  66. role_id: res.data.role_id,
  67. user: res.data.user_name,
  68. };
  69. // 获取基础数据
  70. await getBasicData()
  71. await store.dispatch("user/setUserInfo", userInfo);
  72. await store.dispatch("user/setUserMenu", res.data.route || [])
  73. const accessRoutes = await generateRoutes(res.data.route)
  74. // 旧版本已废除 router.addRoutes
  75. // router.addRoutes(accessRoutes)
  76. // 新版本使用方法
  77. for (let item of accessRoutes) {
  78. router.addRoute(item)
  79. }
  80. setToken(res.data.token)
  81. resolve(res.data.route)
  82. }
  83. }
  84. })
  85. }
  86. // 获取基础数据-运营公司、供应商、地区, 并存入store
  87. export const getBasicData = async () => {
  88. try {
  89. const areaRes = await getArea()
  90. await store.dispatch('options/setArea', (areaRes.data || {}).children || [])
  91. } catch (e) {
  92. Message.error('获取地区数据失败')
  93. }
  94. }

utils/generteRoute.js

  1. import Layout from '@/layout'
  2. import store from '@/store'
  3. // 组件路径转换成模块
  4. export function componentRoutes(routes) {
  5. const res = []
  6. routes.forEach(route => {
  7. const component = route.component === 'Layout' ? Layout : function (resolve) {
  8. require([`@/views/${route.component}`], resolve)
  9. }
  10. const tmp = { ...route, component }
  11. if (tmp.children && tmp.children.length) {
  12. tmp.children = componentRoutes(tmp.children)
  13. }
  14. res.push(tmp)
  15. })
  16. return res
  17. }
  18. // 生成动态路由
  19. export const generateRoutes = (asyncRoutes) => {
  20. return new Promise(resolve => {
  21. let accessedRoutes = componentRoutes(asyncRoutes)
  22. // 标记路由是否已经生成
  23. store.dispatch('permission/toggleRouteFlag', '1')
  24. accessedRoutes.push({ path: '*', redirect: '/404', hidden: true })
  25. resolve(accessedRoutes)
  26. })
  27. }

    store内容查看下面文件夹进行下载

    https://download.csdn.net/download/weixin_64374806/87854628?spm=1001.2014.3001.5503

    

五.进入项目

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/98439
推荐阅读
相关标签
  

闽ICP备14008679号