后台项目总结

后台项目总结

一、项目总体结构

布局方面:

1、CSS样式:项目展示页面可分为头部,侧边导航栏,内容三部分,可使用element-ui里的布局容器进行布局。
头部使用弹性盒子均匀分布。
侧边导航栏使用element-ui组件。通过collapse为true或false控制是否折叠。
主体内容是设置子路由,将子路由的内容放入一个坑里。

设置子路由:

  {
    path: '/',
    name: 'home',
    component: HomeView,
    redirect: 'welcome',
    children: [
      {
        path: '/welcome',
        name: 'welcome',
        component: () => import('../views/Welcome.vue')
      },]
      }

页面:

简单的后台管理有 Login登录页面,welcome欢迎页面。
用户管理的user用户列表;权限管理的roles角色列表,rights权限列表;商品管理的goods商品列表,params分类参数,categories商品分类;订单管理的orders订单列表;数据统计的reports数据报表

二、封装API请求

为方便项目的维护,可以将请求进行封装。

封装流程:
1、在src路径下创建API文件夹
2、文件夹内创建request.js文件封装axios
3、创建api.js文件将请求放在一起,便于后期维护查找接口

request.js文件封装axios:

import axios from "axios";
import { MessageBox, Message } from 'element-ui'
import router from '../router'
const instance = axios.create({
    baseURL: 'http://www.ysqorz.top:8888/api/private/v1/',
    // baseURL: process.env.VUE_APP_API,  
    timeout: 5000
})

// 添加请求拦截器
instance.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    //设置请求头

    config.headers.Authorization = window.sessionStorage.getItem('token')

    return config;
}, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
});

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    let msg = response.data.meta.msg
    let code = response.data.meta.status
    // 无效token处理
    if (msg === '无效token') {
        MessageBox.confirm('token已过期, 是否跳转登录?', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
        }).then(() => {
            sessionStorage.removeItem('token')
            router.push('/login')
            Message({
                type: 'success',
                message: '跳转成功!'
            });
        }).catch(() => {
            Message({
                type: 'info',
                message: '已取消'
            });
            return false
        });
    }

    //错误状态码的处理
    //400 请求的地址不存在或者包含不支持的参数
    //401 未授权
    //403 被禁止访问
    //404 请求的资源不存在
    //500 内部错误,后台出现问题
    if (code === 400 || code === 401 || code === 403 || code === 404 || code === 500) {
        Message({
            message: msg,
            type: 'error'
        });
    }
    return response;
}, function (error) {
    // 对响应错误做点什么
    console.log(error);
    //网络异常处理
    let { message } = error
    if (message == 'Network Error') {
        message = '网络连接异常'
    }
    if (message.includes('timeout')) {
        message = '网络请求超时'
    }
    Message({
        message: message,
        type: 'error'
    });
    return Promise.reject(error);
});

export default instance

三、页面功能实现

1、Login登录页面

登录页面实现流程:

  • 登录正则验证–element-ui组件实现
  • 后台传参进行获取数据
  • 获取token值存入本地
  • 点击登录跳转页面

退出登录时需先清除本地存储的token值再进行跳转

注意事项:

  • 传参时要与参数文档所要求的的参数一致,不一致会报400错误
  • 要根据后台响应传递的参数进行判断,状态为200进行跳转否则报错

vuex实现登录的几种方式:

  • 同步操作:页面通过 this.$store.commit(gettoken,res.data.data.token) 进行使用
 state: {
    token: ''
  },
  getters: {
  },
  mutations: {
    gettoken(state, token) {
      state.token = token
      sessionStorage.setItem('token', token)
    }
  },
  • 异步操作:
 actions: {
    //方法一
    // Login({ commit }, token) {
    //   commit('gettoken', token)
    // }
    //方法二 async await 使用
    // async Login({ commit }, userinfo) {
    //   let res = await getLogin(userinfo)
    //   console.log(res);
    //   if (res.data.meta.status == 200) {
    //     commit('gettoken', res.data.data.token)
    //     Message({
    //       type: 'success',
    //       message: res.data.meta.msg
    //     });
    //     location.href = '#/welcome'
    //   }
    // }
    // promise.then操作
    // Login({ commit }, userinfo) {
    //   getLogin(userinfo).then((res) => {
    //     console.log(res);
    //     if (res.data.meta.status == 200) {
    //       commit('gettoken', res.data.data.token)
    //       Message({
    //         type: 'success',
    //         message: res.data.meta.msg
    //       });
    //       location.href = '#/welcome'
    //     }
    //   })
    // }
    // 方法三 组件级操作  要把请求成功的结果拿到外面使用
    Login({ commit }, userinfo) {
      return new Promise((resolve, reject) => {
        getLogin(userinfo).then((res) => {
          console.log(res);
          commit('gettoken', res.data.data.token)
          resolve(res)
        })
      })
    }
  },

方法一通过 this.$store.dispatch(Login,res.data.data.token) 进行使用

方法二通过this.$store.dispatch(‘Login’,this.ruleForm)

方法三

 this.$store.dispatch("Login", this.ruleForm).then((res) => {
            console.log(res);
             if (res.data.meta.status == 200) {
               this.$message({
               message: res.data.meta.msg,
                 type: "success",
              });
              this.$router.push("/");
            }
           });

2、左侧权限列表

  • 用导航组件实现基本布局
  • 路由点击跳转-需要加入属性router,配合 获取数据里的路径
  • 默认激活打开-属性 :default-active=“/users”
    点击时,存储路径,页面加载 ,获取路径
  • 点击展开与收缩属性 :collapse=“true”
  • 图标问题-从element里找图标, 通过class绑定,每个图标不一样,可以定义数组

3、用户列表

用户列表可分为:

  • 面包屑导航部分–element-ui组件
  • 按钮部分(搜索框,搜索按钮,添加按钮)
  • 表格部分(多个页面使用可进行封装)
  • 分页部分

搜索用户:

  • 绑定值为请求用户列表接口传参的query,传入搜索值。请求用户列表接口,注意传入的参数:query,当前页数pagenum,每页条数pagesize

添加用户:

  • 点击添加按钮调用dialog对话框组件显示
  • 表单双向数据绑定:model=“addForm”, 验证规则绑定:rules=“addFormRules”
  • 提交表单时,获取该表单名字 ref=“addFormRef”,验证表单规则,可自定
    义规则。(注意prop属性绑定的验证规则里的属性 )
  • 提交接口,传参为this.addForm,再次调用渲染列表

修改用户:

  • 点击编辑按钮弹出修改对话框,获取当前行信息
  • 因为有多列都涉及到点击操作,所以要用作用域插槽(scope 有属性$index,代表索引,row-当前行所有信息)
  • 点击按钮打开对话框要进行数据回填
   // 编辑
    handleEdit(index, row) {
      console.log(index, row);
      this.title = "编辑用户";
      this.dialogFormVisible = true;
      this.addForm.username = row.username;
      this.addForm.email = row.email;
      this.addForm.mobile = row.mobile;
      this.addForm.id = row.id;
    },
  • 更新用户 验证规则通过后,请求。注意接口,id是必传项(id获取时,是变量),其它参数要带着,内容可以为空。

删除用户:

  • 使用element-ui组件,确认后调删除接口
  • 传参传当前行id

分配角色:

  • 点击按钮调用角色对话框
  • 获取所有角色接口
  • 下拉列表选择时-v-model绑定数据id,属性:value=“item.id” 配合获取下拉选择项
  • 点击确定时,提交用户id,角色id更新数据

切换用户状态:

  • 获取当前行信息,请求接口,传入当前行id和state值

分页思路:
本接口主要是后台分页:后台要求传入当前页数pagenum,每页条数pagesize。后台会返回总条数total,当前页数pagesize。
使用element-ui里的分页插件实现分页样式,当条数改变时传入条数提交接口,当页数改变时传入页数提交接口

  • 分页插件:
    @size-change(条数改变时触发)
    @current-change(页数发生改变时触发)
    :current-page(设置当前页码)
    :page-size(设置每页的数据条数) layout是布局样式
    :total(设置总页数)

4、权限管理

权限管理 分为角色列表和权限列表

角色列表增删改查基本与角色列表一致,注意传参形式!!!
**渲染权限列表:**使用三重嵌套for循环生成权限下拉列表

  • 调用el-table里的展开列数据格式
  • 布局要合理 ,因为页面要的格式是3层,数据格式也是3层。如何取出每1层下对应的数据?table嵌套外层1行2列,第 2列里又嵌套1行2列。这样总共就有了3列。每列渲染对应的数据

权限分配:

  • 点击按钮显示属性列表(列表布局使用el-tree组件)
  • 调用接口获取权限列表
  • 默认选中实现:通过递归的形式,获取当前角色下所有三级权限的id,并保存到默忍defKeys 选中数组中 。递归会不断的遍历当前角色下childen添加到默认选中数组中
  • 提交选中更新权限:点击为角色分配权限,注意element-ui提供的方法
    全选中方法getCheckedKeys(),半选中方法getHalfCheckedKeys,再把它们合并成数组
    (注意接口提交的时候要的是字符串)

5、商品管理

商品列表(增删改查基本与角色列表一致,注意传参形式!!!)

商品添加页面:

  • 布局:使用步骤条el-step组件,每个tab组件里套着表单组件。给tab声明1个激活索引v-model="activeIndex"同时每个tab子项给到name=“索引”,步骤条调用该索引。

  • tab切换验证:切换下一个,得验证上一个是否选择。可用离开之前属性-:before-leave 调用方法,判断用户是否填写完整,是否选择了下拉的3级列表。

  • 点击商品属性或商品参数,要根据上次选择的3级分类id请求对应数据。点击时@tab-click="tabClicked"通过判断当前激活索引是多少,做相应的接口请求,得知是商品属性,还是商品参数。

  • 图片上传:
    使用upload组件完成图片上传
    在element.js中引入upload组件,并注册
    因为upload组件进行图片上传的时候并不是使用axios发送请求
    所以,我们需要手动为上传图片的请求添加token,即为upload组件添加headers属性

  • 图片预览:

    • 通过存在内存中的文件流,后台会返回1个正式路径地址,你把此路径写入到图即可
  • 移除某个图片:在移除的时候删除的是临时路径 。
    如何获取将要删除的图片的临时路径 ?通过存在内存中的文件流, 从 提交表单图片pics 数组中,找到这个图片对应的索引值。从该数组中splice切除掉

  • 图片上传成功:点击上传成功后 ,后台会返回临时路径和正式地址 。拼接得到一个图片信息对象 const picInfo = { pic: response.data.tmp_path } !!注意,因为后端接口需要传pic字段,所以拼接下 ,然后将图片信息对象picInfo,push 到表单图片pics数组中。

  • 使用富文本编辑器插件
    想要使用富文本插件vue-quill-editor,就必须先从依赖安装该插件引入并注册vue-quill-editor。

  • 点击提交填加商品:需要将已有数据,转换成接口要求的格式。最后提交整个表单

    • 将goods_cat从数组转换为字符串形式(join)
    • 接口要的attrs数组,需要包含商品的动态参数和静态属性。所以需要单独处理将
      manyTableData(动态参数)和 onlyTableData(静态属性)数据处理添加到attrs
分类参数
  • 通过el-tab进行切换,通过v-model绑定激活项 设置name=" many"动态参数 "only"静态属性
  • 这里只允许为第三级分类添加相关参数。如果用户只选中前两级就设置动态参数,静态属性的数据为空,不让他渲染;如果选中第三级就根据所选分类的cateId和当前所处的面板(many/only)获取对应的数据。
  • 三级分类id如何获取?-级联菜单绑定数组selectedCateKeys,级联选择改变时,数组里会有3个值,获取如下:
 <el-cascader expand-trigger="hover" :options="catelist" :props="cateProps" vmodel="selectedCateKeys" @change="handleChange">
//可放在计算属性里,因为cateId是动态获取的
computed: {
 // 当前选中的三级分类的Id
 cateId() {
 if (this.selectedCateKeys.length === 3) {
 return this.selectedCateKeys[2]
 }
 return null
 }
}
  • 每行里tag标签:通过组件实现——tag 删除回车输入内容时触发编辑提交参数接口 put提交categories/:id/attributes/:attrId
    • 下拉选择时,获取参数列表数据,对数据里的 “attr_vals”: “a b c” 给的是字符串进行转换成数组操作
    • bug问题:在tag里输入内容时,同时会操作多个行里的内容问题。
    • 解决办法:给每行的tag组件外面加入作用域插槽,渲染时只渲染当前行数据(scope.row.attr_vals),输入内容时只操作当前行数据 绑定vmodel时,也只绑定当前行。
商品分类

添加分类:

  • 级联菜单使用
<!-- expandTrigger='hover'(鼠标悬停触发级联) v-model(设置级联菜单绑定数据) :options(指定级
联菜单数据源) :props(用来配置数据显示的规则)
 clearable(提供“X”号完成删除文本功能) change-on-select(是否可以选中任意一级的菜单)
@change="parentCateChanged" 选择项改变时触发事件-->
  props: {
        value: "cat_id",//绑定自己数据
        label: "cat_name",
        children: "children",
        checkStrictly: true,//显示单选框按钮,单级也可选
        expandTrigger: "hover",//划上显示数据
      },
  • 点击确定提交分类
    接口需要传入参数:分类名称,父分类id,当前分类层级
    分类层级,要根据父分类层级提交参数,你怎么知道父级要类选择了几级?
    //给级联菜单绑定一个数组,selectedKeys,[1] ,你选择的项会存储到数组里

6、 数据统计

  • 导入 echarts:
    导入 echarts-由于版本问题,直接导入import echarts from 'echarts’可能会报init
    错误,可把安装的包卸载 npm uninstall echarts 。重新安装4以下低版本的echarts cnpm i echarts@4
  • 调用接口,改变那些需要修改的数据

7、项目上线优化

在 vue.confing.js 文件中配置

1、配置输出路径,没有设置会导致白屏 publicPath: ‘./’

2、去除生产环境的代码镜像-productionSourceMap

3、在项目文件夹下运行npm run build
如果有跨域 也要配置跨域

4、我们会发现在原来的项目文件夹中多出了一个dist文件夹,
这个文件夹就是我们要放到线上的内容 把这个文件挂载到后端服务器上

优化:
通过 externals 加载外部 CDN 资源
通过 import 语法导入的第三方依赖包,最终会被打包合并到同一个文件中,
从而导致打包成功后,单文件体积过大的问题。 为了解决上述问题,可以通过 webpack 的 externals 节点,来配置并加载外部的 CDN 资源。

凡是声明在externals 中的第三方依赖包,都不会被打包。
通过 CDN 优化 ElementUI 的打包
路由懒加载

去除 console.log() 通过下载 插件
抽离第三方插件 注意 别名的配置
在bable.config.js文件中配置

// 项目上线时-去除console.log 。注意需要安装cnpm i  babel-plugin-transform-remove-console -D
const prodPlugins = [];
if (process.env.NODE_ENV === 'production') {
  prodPlugins.push('transform-remove-console');
}
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    ...prodPlugins
  ]
}

你可能感兴趣的:(vue.js,javascript,前端)