用户后台管理的流程

使用的组件有:element-ui    echarts表格   富文本编辑器

登录页面流程:

在登录页面布局完成之后,当我们点击登录之后先是调用登录接口,将用户名和密码发送给接口,然后当接口返回登录成功信息的时候将token存储到本地,因为登录成功之后的接口都需要加一个请求头tokrn,所以我们在前置拦截器里面统一的进行配置请求头,然后在后置拦截器里面进行错误响应信息的配置以及重复请求的处理。

前置拦截器

后置拦截器 

进入home页面之后:

在home页面的话左侧是有一个二级菜单,后端给我们返回的数据中是已经处理好的,我们只需要将数据渲染到左侧的菜单中,然后配置路由跳转到对印的页面,路由的话有两种路由的方式可以写,一种是静态路由,另一种动态路由,静态路由的话只需要我们在router.js中进行手动配置,如果是静态路由的话,但凡后端返回的路径有恒多的话,在写路由的时候就会很麻烦,在项目中如果后端中途进行了修改路径,静态的路由的话也需要重新进行修改,但是如果我们写的是动态路由的话,不管后端怎样修改路径,前端都会动态的生成对应的路由,极大的提升了开发项目的效率。

动态路由的实现:

动态路由的话需要我们在登录成功的时候路由跳转到home之前获取一次home页面的左侧菜单数据并把它存储到本地,如果后端给我们的数据是处理好的,那我们就需要将数据进行递归处理一个新的数组,因为后面需要在路由里面再次调用这个递归函数,所以我们可以创建一个routerlist.js文件夹,在这个文件夹写一个处理数据的递归函数,在这个函数内部处理完之后将他们每一条数据以路由对象的的格式添加到一个新的数组,最后将这个函数抛出去,然后在登陆的页面引入这个js文件,将请求的左侧菜单栏的数据以参数的形式传递给他,拿到返回的数组进行遍历让他们依次添加给路由(this.$router.addRoute("名称",item).这个时候我们跳转到home页面的时候就已经生成了动态路由了,但是呢当我们进行刷新的时候,动态路由就会消失,是因为每刷新一次页面路由是最先走的,这个时候动态路由还没有添加上去,所以我们需要在router.js中获取到本地存储的左侧菜单数据再次进行递归处理,依次添加到路由中去。

封装的递归方法

递归函数//
export function fn(data) {
    console.log('递归数据', data);
    let arr = []

    function deep(data) {
        data.forEach(item => {
            //判断如果children里有数据的话就将他进行递归
            if (item.children.length) {
                deep(item.children)
            } else {
                let path = item.path.slice(0, 1).toUpperCase() + item.path.slice(1)
                arr.push({
                    path: "/" + item.path,
                    name: item.authName,
                    component: () =>
                        import (`../views/${path}.vue`)
                })
            }
        })
    }
    deep(data)
    return arr
}

将路由动态的添加上起

引入封装的递归函数//
import { fn } from '@/utils/routers.js'

function LoadRouter() {

    将登录成功存储的左侧菜单数据请求出来//
    let routerlist = JSON.parse(localStorage.getItem("routerlist"))
    let token = localStorage.getItem("token")

    判断如果有数据的话并且token存在就让他动态的添加上去
    if (routerlist && token) {

        let routertwo = fn(routerlist)
        routertwo.forEach(item => {
            router.addRoute("home", item)
        })
    }
}

LoadRouter()

需要注意的问题

1.在写动态路由之前,最好是将所有的页都放在一个文件夹内,后期路径比较容易处理

2.如果我们写了防止接口重复请求的代码,那么因为我们登陆的时候请求了一下左侧菜单数据,登陆成功后有请求了一次左侧菜单渲染的数据,时间间隔比较短,可能会造成取消了一次接口请求的问题,这个时候我们可以在登录请求接口的时候使用await来阻塞后面的代码执行,只有他执行完毕的时候才会去执行后面的代码。

 用户管理>用户列表

用户列表信息渲染主要就是用户信息的增删改查,将后端返回给我们的数据渲染到页面中去,在添加用户的时候需要将添加字段和后端给我们的接口一一对应,删除时候需要获取到当前点击的数据id获取出来进行接口请求删除,主要就是在删除的时候,当我们数据回填完毕后,这个时候有两种写法一种是使用之前添加数据时候的模态框,使用添加的模态框的话添加按钮和修改按钮是同一个按钮,在点击修改的时候会出现同时执行添加事件的问题,这个时候就需要我们对添加和修改按钮的状态进行判断处理。另一种方法就是再写一个模态框用于修改使用就不会出现冲突的问题了。在用户页面还有一个分页器的功能,分页器的话一般我们引入组件时候需要在组件中绑定当前页数pagenum和当前页显示的条数以及总条数,总条数是需要我们在从请求接口的数据中获取的。然后组件自带一个页数切换和每页显示条数切换的事件,在事件中对页数和条数进行修改并重新调用接口渲染数据。

权限管理>角色列表

角色列表的话除了正常的增删改查以外,还有就是他的权限分配以及每条数据的权限列表渲染,在我们请求的每一条数据中一般都会有一个children属性里面存放的就是对应的权限信息,布局的时候我是通过表格嵌套表格的形式进行渲染的。具体实现如下,仅供参考。

 代码实例

<!-- 树状图嵌套表格区域 -->
                        <div class="box">
                            <table class="box-1">
                                <tr class="yicen" v-for="(item,index) in props.row.children" :key="index">
                                    <td class="yicen-1">
                                        <el-tag closable :disable-transitions="false" color="#409EFF" style="color:#fff;" @close="dell(props.row,item.id)">
                                            {{item.authName}}
                                        </el-tag>
                                        <i class="el-icon-caret-right" ></i>
                                     </td>
                                    <td class="yicen-2">
                                        <table class="ercen">
                                            <tr v-for="(ite,ind) in item.children" :key="ind">
                                                <td class="td1">
                                                    <el-tag closable :disable-transitions="false" color="#67C23A" style="color:#fff;" @close="dell(props.row,ite.id)">
                                                        {{ite.authName}}
                                                    </el-tag>
                                                    <i class="el-icon-caret-right" ></i>
                                                </td>
                                                <td class="td2">
                                                    <el-tag closable :disable-transitions="false" color="#E6A23C" style="color:#fff;" v-for="(it,i) in ite.children" :key="i"  @close="dell(props.row,it.id)">
                                                        {{it.authName}}
                                                    </el-tag>
                                                </td>
                                            </tr>
                                        </table>
                                    </td>
                                </tr>
                            </table>
                        </div>
                        <!-- 树状图嵌套表格区域 -->

分配角色功能

分配角色功能的话采用的是树状图的形式渲染的,在点击登录分配按钮的时候需要将当前行数据的所有权限id获取到进行数据的回填,怎么获取呢?我是采用的递归的方式从当前行的数据中依次将id获取出来放到一个空的数组中去,然后在权限列表中渲染出所有的权限信息,并把刚刚获取到的回填数组绑定到树状图的组件中去,就可以实现数据回填的效果了,当我们对权限进行取消状态的选中,和新增选中的时候可以使用组件中自带的方法获取到所有的选中权限的id,将他进行处理提交给接口就可以实现分配权限的功能了。

商品管理>商品分类

商品分类的话,除了基本的增删改查之外,还有就是它渲染出来列表之后,他的列表是一个级联菜单的形式。每点开一层都是对应的数据,每一个请求的接口数据里面都有一个children属性,分别对应的是每一层的数据在我们点击添加分类的时候。弹出的模态框里它有一个父级分类,父级分类的话是一个级联菜单三级联动的效果,他是用后端请求的数据渲染上来之后,然后当我们点击添加分类的时候,他会判断我们选中的层级是哪一级的数据,然后分别添加到对应的列表里数据里。

商品管理>分类参数

在商品分类里有一个动态参数和静态属性的渲染,这里的话是有一个tab栏切换的效果,当我们选择完商品后,需要渲染出对应的动态参数和静态的参数,这里要注意的是,一般情况下,在我们选择商品参数的时候必须得选择的是三级的参数,所以我们需要对选择的数据惊醒判断是不是三级的参数。在动态参数和静态参数的切换中可以设置一个状态来判断当前添加的是动态参数还是静态属性,添加完对应的数据后。

 

每一条参数或者属性都是一个可以下拉的级联菜单,里面的每一个tag标签放的都是该参数的具体信息,参数的具体信息是通过修改的接口,获取到当前行的id和pig将我们新增的tag参数以逗号的形式凭借成一个字符串,然后请求编辑的接口将数据分配给对应的参数,这里要注意的是,我们在渲染的时候是需要将后端返回数据里的的存放具体参数的数据转换成一个数组的形式才可以进行渲染。同样删除也是请求的编辑的接口在渲染tag标签的数组中删除对应的数据,然后重新转换为数组的形式提交给后端接口进行编辑。

添加具体代码

// 点击回车或者失去焦点添加tag标签
    async handleInputConfirm(inputValue, row) {
      if (inputValue) {
        // 判断点击的是添加参数还是添加属性
        if (!this.done) {
          //   判断为false添加到参数
          let res = await geteditcs(
            this.id,
            row.attr_id,
            row.attr_name,
            row.attr_vals + "," + inputValue
          );
          // 找出点击的数据进行替换
          res.data.attr_vals =
            res.data.attr_vals === "" ? [] : res.data.attr_vals.split(",");
          if (res.data.attr_vals[0] == "") {
            res.data.attr_vals.splice(0, 1);
          }
          this.data.forEach((item, index) => {
            if (item.attr_id == row.attr_id) {
              this.$set(this.data[index], "attr_vals", res.data.attr_vals);
            }
          });
        } else {
          //   判断为false添加到参数
          let res = await geteditsx(
            this.id,
            row.attr_id,
            row.attr_name,
            row.attr_vals + "," + inputValue
          );
          // 找出点击的数据进行替换
          res.data.attr_vals =
            res.data.attr_vals === "" ? [] : res.data.attr_vals.split(",");
          if (res.data.attr_vals[0] == "") {
            res.data.attr_vals.splice(0, 1);
          }
          this.data1.forEach((item, index) => {
            if (item.attr_id == row.attr_id) {
              this.$set(this.data1[index], "attr_vals", res.data.attr_vals);
            }
          });
        }
      }
      inputValue = "";
    },

删除代码片段

// 删除对应的tag标签
    async handleClose(index, ind, row) {
      if (!this.done) {
        this.data[index].attr_vals.splice(ind, 1);
        let res = await geteditcs(
          this.id,
          row.attr_id,
          row.attr_name,
          this.data[index].attr_vals.join()
        );
        // 找出点击的数据进行替换
        res.data.attr_vals =
          res.data.attr_vals === "" ? [] : res.data.attr_vals.split(",");
        this.data.forEach((item, index) => {
          if (item.attr_id == row.attr_id) {
            this.$set(this.data[index], "attr_vals", res.data.attr_vals);
          }
        });
      } else {
        this.data1[index].attr_vals.splice(ind, 1);
        let res = await geteditsx(
          this.id,
          row.attr_id,
          row.attr_name,
          this.data1[index].attr_vals.join()
        );
        res.data.attr_vals =
          res.data.attr_vals === "" ? [] : res.data.attr_vals.split(",");
        this.data1.forEach((item, index) => {
          if (item.attr_id == row.attr_id) {
            this.$set(this.data1[index], "attr_vals", res.data.attr_vals);
          }
        });
      }
    },

商品管理>分类参数

 商品参数:

点击到商品参数的时候将基本信息里选择的三级分类的id上传接口返回对应的参数信息,将参数信息中的attr_vals属性的值转换为数组的形式并给数组中的每一项新增一个checked状态,用于在添加时候状态的选择。

商品图片:

引入一个图片上传的组件,在点击图片上传的时候,需要将上传图片的接口信息绑定给组件中的属性,并在组件中添加一个headers的请求头,因为在图片上传中是走不到前置拦截器的,所以我们需要手动的配置一个请求头,然后通过上传成功的事件拿到返回上传成功的图片将他放入一个数组中去,添加时候使用,如果我们要删除上传的图片,那我们就需要找到点击的图片路径并在数组中进行去除,还有就是想要实现图片预览的话,可以在获取到我们点击图片的路径让他以模态框的方式渲染出来。

再点击添加按钮后将商品的基本信息以及图片路径的数组动态静态参数依次提交给接口,这里要注意的是商品的动态参数和静态参数在添加的时候是放到一个数组里面以对象的方式进行添加的,所以我们就需要找出每个参数对应的id数据放到一个对象里面,最后push到一个数组里面提交。

数据统计>数据报表

引入echarts表格,需要在对应的页面中写一个盒子,这个盒子必须得设置宽高,在页面中获取到这个盒子的dom元素,将接口请求出来的数据赋值给盒子的配置项。

在项目中一般情况下后端返回给我们的数据是没有进行处理好的,所以我们需要在后端返回的数据抽离出表格需要的对应的数据进行赋值。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值