美文网首页
Vue电商-功能模块

Vue电商-功能模块

作者: Imkata | 来源:发表于2022-04-21 09:32 被阅读0次

    一. 登录功能

    1 - 登录-token原理分析

    因为http是无状态的,所以我们有两种方式记住登录状态:

    • 如果服务器和客户端同源,通过 cookie 在客户端记录状态,通过 session 在服务器端记录状态
    • 如果服务器和客户端不同源,通过 token 方式维持状态

    在登录页面输入账号和密码进行登录,将数据发送给服务器,服务器返回登录的结果,登录成功则返回数据中带有token,客户端得到token并进行保存,后续的请求都需要将此token发送给服务器,服务器会验证token以保证用户身份。

    2 - 登录组件布局

    通过 Element-UI 组件实现布局

    • el-form
    • el-form-item
    • el-input
    • el-button
    • 字体图标

    3 - 实现登录

    1. 通过 axios 调用登录验证接口
    2. 登录成功之后保存用户 token 信息
    3. 跳转到项目主页
    const {data: res } = await this.$http.post('login', this.loginForm) 
    if (res.meta.status !== 200)return this.$message.error('登录失败!') 
    // 提示登录成功 
    this.$message.success('登录成功!') 
    // 把登录成功的token保存到sessionStorage 
    window.sessionStorage.setItem('token', res.data.token) 
    // 使用编程式导航,跳转到后台主页 
    this.$router.push('/home')
    

    4 - 路由导航守卫控制访问权限

    如果用户没有登录,但是直接通过 URL 访问特定页面,需要重新导航到登录页面。

    // 为路由对象,添加 beforeEach 导航守卫
    router.beforeEach((to, from, next) => {
       // 如果用户访问的登录页,直接放行
       if (to.path === '/login') return next()
       // 从 sessionStorage 中获取到 保存的 token 值
       const tokenStr = window.sessionStorage.getItem('token')
       // 没有token,强制跳转到登录页
       if (!tokenStr) return next('/login')
       next()
    })
    

    5 - Vue 直接操作 DOM

    1. 通过 ref 标注 DOM 元素
    // 在 DOM 元素上通过 ref 属性标注,属性名称自定义
    <div ref="info">hello</div>
    
    1. 通过 $refs 获取 DOM 元素
    // 通过 Vue 实例的 $refs 获取标记 ref 属性的元素
    let info = this.$refs.info.innerHTML
    console.log(info) // hello
    

    6 - 基于 Element-UI 进行表单验证

    Element-UI 表单验证规则:

    loginFormRules: {
    // 登录名称的验证规则
    username: [{ required: true, message: '请输入用户名称', trigger: 'blur' }],
    password: [{ required: true, message: '请输入用户密码', trigger: 'blur' }] }
    
    // 进行表单验证
    this.$refs.loginFormRef.validate(async valid => {
      // 如果验证失败,直接退出后续代码的执行
      if (!valid) return
       // 验证通过后这里完成登录成功后的相关操作(保存token、跳转到主页) 
    })
    

    7 - 退出功能

    基于 token 的方式实现退出比较简单,只需要销毁本地的 token 即可。这样,后续的请求就不会携带 token , 必须重新登录生成一个新的 token 之后才可以访问页面。在Home组件中添加一个退出功能按钮,给退出按钮添加点击事件,添加事件处理代码如下:

    // 清空token
    window.sessionStorage.clear()
    // 跳转到登录页
    this.$router.push('/login')
    

    二. 主页布局

    1 - 整体布局

    整体布局:先上下划分,再左右划分。

    <el-container>
      <!-- 头部区域 -->
      <el-header></el-header>
      <!-- 主体区域 -->
      <el-container>
          <!-- 侧边栏区域 -->
          <el-aside></el-aside>
          <!-- 右侧主体区域 -->
          <el-main></el-main>
      </el-container>
    </el-container>
    

    2 - 左侧菜单布局

    菜单分为二级,并且可以折叠。

    <el-menu>
      <el-submenu>
        <!-- 这个 template 是一级菜单的内容模板 -->
        <i class="el-icon-menu"></i>
        <span>一级菜单</span>
        <!-- 在一级菜单中,可以嵌套二级菜单 -->
        <el-menu-item>
          <i class="el-icon-menu"></i>
          <span slot="title">二级菜单</span>
        </el-menu-item>
      </el-submenu>
    </el-menu>
    

    3 - 通过接口获取菜单数据

    通过 axios 请求拦截器添加 token,保证拥有获取数据的权限。

    // axios请求拦截 
    axios.interceptors.request.use(config => {
      // 为请求头对象,添加 Token 验证的 Authorization 字段
      config.headers.Authorization = window.sessionStorage.getItem('token')
      return config 
    })
    

    4 - 动态渲染菜单数据并进行路由控制

    • 通过 v-for 双层循环分别进行一级菜单和二级菜单的渲染
    • 通过路由相关属性启用菜单的路由功能
    <el-menu router>
      <el-submenu :index="item.id + ''" v-for=“item in menus" :key="item.id">
        <template slot="title">
          <span>{{item.authName}}</span>
        </template>
        <el-menu-item :index="'/' + subItem.path" v-for="subItem in item.children"
          :key="subItem.id" >
          <span slot="title">{{subItem.authName}}</span>
        </el-menu-item>
      </el-submenu>
    </el-menu>
    

    三. 用户管理

    1 - 用户管理概述

    通过后台管理用户的账号信息,具体包括用户信息的展示、添加、修改、删除、角色分配、账号启用/注销等功能。

    • 用户信息列表展示
    • 添加用户
    • 修改用户
    • 删除用户
    • 启用或禁用用户
    • 用户角色分配

    2 - 用户信息列表展示

    1. 用户列表布局

    • 面包屑导航 el-breadcrumb
    • Element-UI 栅格系统基本使用 el-row
    • 表格布局 el-table、el-pagination

    2. 用户状态列和操作列处理

    作用域插槽

    <template slot-scope="scope">
        <!-- 开关 -->
        <el-switch v-model="scope.row.mg_state" 
            @change="stateChanged(scope.row.id, scope.row.mg_state)">
        </el-switch>
    </template>
    

    3. 表格数据填充

    • 调用后台接口
    • 表格数据初填充
    const { data: res } = await this.$http.get('users', { params: this.queryInfo }) 
    if (res.meta.status !== 200) { 
      return this.$message.error('查询用户列表失败!') 
    } 
    this.total = res.data.total 
    this.userlist = res.data.users
    

    4. 表格数据分页

    分页组件用法:

    1. 当前页码:pagenum
    2. 每页条数:pagesize
    3. 记录总数:total
    4. 页码变化事件
    5. 每页条数变化事件
    6. 分页条菜单控制
    <el-pagination 
      @size-change="handleSizeChange" 
      @current-change="handleCurrentChange" 
      :current-page="queryInfo.pagenum" 
      :page-sizes="[2, 3, 5, 10]" 
      :page-size="queryInfo.pagesize" 
      layout="total, sizes, prev, pager, next, jumper" 
      :total="total">
    </el-pagination>
    

    5. 搜索功能

    将搜索关键字,作为参数添加到列表查询的参数中。

    <el-input 
      placeholder="请输入搜索的内容" 
      v-model="queryInfo.query" 
      clearable 
      @clear="getUserList">
      <el-button slot="append" 
        icon="el-icon-search" 
        @click="getUserList"></el-button>
    </el-input>
    

    3 - 用户状态控制

    开关组件的用法

    <el-switch 
      v-model="scope.row.mg_state" 
      @change="stateChanged(scope.row.id, scope.row.mg_state)">
    </el-switch>
    

    接口调用更改用户的状态

    async stateChanged(id, newState) {
      const { data: res } = await this.$http.put(`users/${id}/state/${newState}`)
      if (res.meta.status !== 200) {
        return this.$message.error('修改状态失败!')
      } 
    }
    

    4 - 添加用户

    1. 添加用户表单弹窗布局

    • 弹窗组件用法
    • 控制弹窗显示和隐藏
    <el-dialog title="添加用户" :visible.s参数管理ync="addDialogVisible" width="50%">
      <el-form :model="addForm" label-width="70px">
        <el-form-item label="用户名" prop="username">
          <el-input v-model="addForm.username"></el-input>
        </el-form-item>
        <!-- 更多表单项 -->
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="resetAddForm">取 消</el-button>
        <el-button type="primary" @click="addUser">确 定</el-button>
      </span>
    </el-dialog>
    

    2. 表单验证

    内置表单验证规则:

    <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" >
      <!-- 表单 -->
    </el-form>
    
    addFormRules: {
      username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
      password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
    }
    
    this.$refs.addFormRef.validate(async valid => {
      if (!valid) return
    })
    

    自定义表单验证规则:

    const checkMobile = (rule, value, cb) => {
      let reg = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
      if (reg.test(value)) {
        cb()
      } else {
        cb(new Error('手机号码格式不正确'))
      } 
    }
    
    mobile: [
      { required: true, message: '请输入手机号', trigger: 'blur' },
      { validator: checkMobile, trigger: 'blur' }
    ]
    

    3. 表单提交

    将用户信息作为参数,并调用后台接口添加用户。

    this.$refs.addFormRef.validate(async valid => {
      if (!valid) return
      const { data: res } = await this.$http.post('users', this.addForm)
      if (res.meta.status !== 201) {
        return this.$message.error('添加用户失败!')
      }
      this.$message.success('添加用户成功!')
      this.addDialogVisible = false
      this.getUserList()
    })
    

    5 - 修改用户

    1. 根据 ID 查询用户信息

    <el-button type="primary" size="mini" icon="el-icon-edit" @click="showEditDialog(scope.row.id)"></el-button>
    
    async showEditDialog(id) {
      const { data: res } = await this.$http.get('users/' + id)
      if (res.meta.status !== 200) {
        return this.$message.error('查询用户信息失败!')
      }
      // 把获取到的用户信息对象,保存到 编辑表单数据对象中
      this.editForm = res.data
      this.editDialogVisible = true
    }
    

    2. 编辑提交表单

    this.$refs.editFormRef.validate(async valid => {
      if (!valid) return
      // 发起修改的请求
      const { data: res } = await this.$http.put('users/' + this.editForm.id, {
        email: this.editForm.email,
        mobile: this.editForm.mobile
      })
      if (res.meta.status !== 200) {
        return this.$message.error('编辑用户信息失败!')
    }
      this.$message.success('编辑用户信息成功!')
      this.getUserList()
      this.editDialogVisible = false
    })
    

    6 - 删除用户

    <el-button type="danger" size="mini" icon="el-icon-delete" 
    @click="remove(scope.row.id)"></el-button>
    
    async remove(id) {
      // 询问是否要删除
      const confirmResult = await this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(err => err)
      const { data: res } = await this.$http.delete('users/' + id)
      if (res.meta.status !== 200) return this.$message.error('删除用户失败!')
      this.$message.success('删除用户成功!')
      this.getUserList()
    },
    

    四. 权限管理

    1 - 权限管理业务分析

    通过权限管理模块控制不同的用户可以进行哪些操作,具体可以通过角色的方式进行控制,即每个用户分配一个特定的角色,角色包括不同的功能权限。

    2 - 权限列表展示

    <template slot-scope="scope">
      <el-tag size="small" v-if="scope.row.level == 0">一级</el-tag>
      <el-tag type="success" size="small" v-else-if="scope.row.level == 1">二级</el-tag>
      <el-tag type="warning" size="small" v-else>三级</el-tag>
    </template>
    
    // 获取权限列表数据
    async getRightsList() {
      const { data: res } = await this.$http.get('rights/list')
      if (res.meta.status !== 200) {
        return this.$message.error('获取权限列表失败!')
      }
      this.rightsList = res.data
    }
    

    3 - 角色列表展示

    • 调用后台接口获取角色列表数据
    • 角色列表展示
    // 获取所有角色列表
    async getRolesList() {
      const { data: res } = await this.$http.get('roles')
      if (res.meta.status !== 200) {
        return this.$message.error('获取角色列表失败!')
      }
      this.rolesList = res.data
    },
    

    4 - 用户角色分配

    1. 展示角色对话框

    1. 实现用户角色对话框布局
    2. 控制角色对话框显示和隐藏
    3. 角色对话框显示时,加载角色列表数据
    async showSetRoleDialog(userInfo) {
      this.userInfo = userInfo
      // 发起请求,获取所有角色的列表
      const { data: res } = await this.$http.get('roles')
      if (res.meta.status !== 200) {
        return this.$message.error('获取角色列表失败!')
      }
      this.rolesList = res.data
      this.setRoleDialogVidible = true
    }
    

    2. 完成角色分配功能

    async saveNewRole() {
      if (this.selectedRoleId === '') {
        return this.$message.error('请选择新角色后再保存!')
      }
      const { data: res } = await this.$http.put(`users/${this.userInfo.id}/role`, {
        rid: this.selectedRoleId
      })
      if (res.meta.status !== 200) {
        return this.$message.error('分配角色失败!')
      }
      this.$message.success('分配角色成功!')
      this.getUserList()
      this.setRoleDialogVidible = false
    }
    

    5 - 角色权限分配

    1. 表格行展开效果

    通过 el-table-column 组件的 type =“expand” 方式实现表格行展开效果

    <el-table :data="rolesList" border stripe>
      <!-- 展开行的列 -->
      <el-table-column type="expand">
        <template slot-scope="scope">
          <!-- 展开行内容填充 -->
        </template>
      </el-table-column>
    </el-table>
    

    2. 渲染一级权限菜单

    在表格展开行中渲染一级菜单

    <el-row v-for="(item1, i1) in scope.row.children" :key="item1.id" class="centerRow">
      <!-- 这一列,专门渲染 一级权限 -->
      <el-col :span="5">
        <el-tag closable>{{item1.authName}}</el-tag>
        <i class="el-icon-caret-right"></i>
      </el-col>
      <!-- 还剩余 19 列,分配给二三级权限 -->
      <el-col :span="19">
        <!-- 这里显示二三级权限 -->
      </el-col>
    </el-row>
    

    3. 渲染二、三级权限菜单

    在表格展开行中渲染二、三级菜单

    <el-row v-for="(item2, i2) in item1.children" :key="item2.id" class="centerRow">
      <!-- 放二级权限 -->
      <el-col :span="6">
        <el-tag closable type="success">{{item2.authName}}</el-tag>
        <i class="el-icon-caret-right"></i>
      </el-col>
      <!-- 放三级权限 -->
      <el-col :span="18">
        <el-tag closable type="warning" v-for="item3 in item2.children" :key="item3.id"> 
          {{item3.authName}}</el-tag>
      </el-col>
    </el-row>
    

    4. 删除角色下的权限

    点击权限菜单的删除按钮后,调用后台接口删除对应权限和其下的子权限。

    <el-col :span="5">
      <el-tag closable @close="removeRight(scope.row, item1.id)">
        {{item1.authName}}
      </el-tag>
      <i class="el-icon-caret-right"></i>
    </el-col>
    
    const { data: res } = await this.$http.delete(`roles/${role.id}/rights/${rightId}`)
    if (res.meta.status !== 200) {
      return this.$message.error('删除权限失败!')
    }
    this.$message.success('删除权限成功!')
    

    5. 给角色分配权限流程

    1. 实现角色分配权限对话框布局
    2. 控制对话框的显示和隐藏
    3. 对话框显示时调用后台接口加载权限列表数据
    4. 完成树形权限菜单的展示
    5. 选中默认的权限
    6. 保存选中的权限,调用后台接口完成角色权限的分配

    6. 实现权限分配对话框布局

    • 实现对话框布局效果
    • 控制对话框显示和隐藏
    <!-- 分配权限的对话框 -->
    <el-dialog title="分配权限" :visible.sync="setRightDialogVisible" width="50%" 
    @close="resetSetRightDialog">
      <!-- 权限菜单 -->
      <span slot="footer" class="dialog-footer">
        <el-button @click="setRightDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveRight">确 定</el-button>
      </span>
    </el-dialog>
    

    7. 渲染权限的树形结构

    树形组件 el-tree 的基本使用

    <el-tree ref="tree" :data="rightTree" :props="treeConfig" show-checkbox node�key="id" default-expand-all :default-checked-keys="defaultCheckedKeys"></el-tree>
    

    权限数据的加载与填充

    // 在展示对话框之前,先获取到权限的树形结构数据
    const { data: res } = await this.$http.get('rights/tree')
    if (res.meta.status !== 200) return this.$message.error('初始化权限失败!')
    // 把权限的树形结构数据,保存到data中,供页面渲染使用
    this.rightTree = res.data
    

    8. 设置默认权限菜单选中

    • 获取所有叶子节点的 id
    • 设置权限节点选中
    // 根据指定的节点和keys数组,递归获取所有三级节点的Id
    getLeafIds(node, keys) {
      if (!node.children) {
        keys.push(node.id)
      } else {
        node.children.forEach(item => this.getLeafIds(item, keys))
      } 
    }
    
    const keys = [] // 专门存放所有三级节点的Id
    this.getLeafIds(role, keys)
    this.defaultCheckedKeys = keys
    

    9. 完成角色授权

    • 获取所有选中的权限节点 id
    • 调用接口完成角色权限的分配
    // 获取树形控件中,所有半选和全选节点的Id数组
    const arr1 = this.$refs.tree.getCheckedKeys()
    const arr2 = this.$refs.tree.getHalfCheckedKeys()
    const rids = [...arr1, ...arr2].join(',')
    
    const { data: res } = await this.$http.post(`roles/${this.selectedRoleId}/rights`, { rids })
    if (res.meta.status !== 200) {
      return this.$message.error('分配权限失败!')
    }
    this.$message.success('分配权限成功!')
    

    五. 分类管理

    1 - 商品分类概述

    商品分类用于在购物时,快速找到所要购买的商品,可以通过电商平台主页直观的看到。

    2 - 商品分类列表

    • 实现基本布局
    • 实现分类列表数据加载
    const { data: res } = await this.$http.get('categories', { params: this.queryInfo })
    if (res.meta.status !== 200) {
      return this.$message.error('获取商品分类失败!')
    }
    this.cateList = res.data.result
    this.total = res.data.total
    

    3 - 树形表格

    1. 第三方树形表格的基本使用

    1. 安装依赖包 (地址: https://github.com/MisterTaki/vue-table-with-tree-grid
    npm i vue-table-with-tree-grid -S
    
    1. 基本使用
    import Vue from 'vue'
    import ZkTable from 'vue-table-with-tree-grid'
    Vue.use(ZkTable)
    

    2. 实现分类树形列表

    • 实现树形列表布局并进行数据填充
    • 自定义表格列
    <tree-table :data="cateList" :columns="columns" border :selection-type="false" 
    :expand-type="false" show-index index-text="#" class="tree-table">
      <!-- 操作的模板列 -->
      <!-- 排序的模板列 -->
      <!-- 是否有效的模板列 -->
      <template slot="isok" slot-scope="scope">
        <i class="el-icon-success" style="color:#20B2AA;" v-if="scope.row.cat_deleted 
    === false"></i>
        <i class="el-icon-error" style="color:#F92672;" v-else></i>
      </template>
    </tree-table>
    

    4 - 分页功能

    • 实现分页组件效果
    • 分页组件数据处理
    <!-- 分页区域 -->
    <el-pagination 
      @current-change="handleCurrentChange" 
      :current-page="queryInfo.pagenum" 
      :page-size="queryInfo.pagesize" 
      layout="total, prev, pager, next, jumper" 
      :total="total">
    </el-pagination>
    

    5 - 添加分类

    1. 实现分类树形列表

    • 实现添加分类对话框布局
    • 控制对话框显示和隐藏
    <el-dialog title="添加分类" :visible.sync="addDialogVisible" width="50%" @close="resetForm">
      <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="100px">
        <el-form-item label="分类名称:" prop="cat_name">
          <el-input v-model="addForm.cat_name"></el-input>
        </el-form-item>
        <el-form-item label="父级分类:">
          <!-- 分类菜单 -->
        </el-form-item>
      </el-form>
    </el-dialog>
    

    2. 实现分类级联菜单效果

    • 实现级联菜单效果
    • 级联菜单数据加载与填充
    <el-cascader 
      expand-trigger="hover" 
      :options="parentCateList" 
      :props="cascaderConfig" 
      v-model="selectedCateList" 
      @change="handleChange" 
      change-on-select 
      clearable>
    </el-cascader>
    
    // 先获取所有父级分类的数据列表
    const { data: res } = await this.$http.get('categories', { params: { type: 2 } })
    if (res.meta.status !== 200) return this.$message.error('获取父级分类失败!')
    // 把父级分类数据,挂载到data中
    this.parentCateList = res.data
    

    3. 控制父级分类的选择

    父级分类选择时,获取对应的分类 id。

    handleChange() {
      if (this.selectedCateList.length === 0) {
        // 证明没有选中任何父级分类
        this.addForm.cat_pid = 0
        this.addForm.cat_level = 0
      } else {
        // 选中父级分类
        this.addForm.cat_pid = this.selectedCateList[this.selectedCateList.length - 1]
        // 设置分类等级
        this.addForm.cat_level = this.selectedCateList.length
      } 
    }
    

    4. 完成分类添加

    将分类名称、分类等级和父分类 id 提交到后台,完成分类添加。

    const { data: res } = await this.$http.post('categories', this.addForm)
    if (res.meta.status !== 201) {
      return this.$message.error('添加分类失败!')
    }
    this.$message.success('添加分类成功!')
    

    六. 参数管理

    1 - 参数管理概述

    商品参数用于显示商品的固定的特征信息,可以通过电商平台商品详情页面直观的看到。

    2 - 商品分类选择

    1. 选择商品分类

    • 页面基本布局
    • 加载商品分类数据
    • 实现商品分类的级联选择效果
    // 获取所有商品的分类列表
    async getAllCateList() {
      const { data: res } = await this.$http.get('categories')
      if (res.meta.status !== 200) {
        return this.$message.error('获取商品分类列表失败!')
      }
      this.cateList = res.data
    }
    

    2. 控制级联菜单分类选择

    • 只允许选择三级分类
    • 通过计算属性的方式获取分类 id
    cascaderChanged() {
      if (this.selectedCateList.length !== 3) {
        // 没有选中三级分类,把分类重置为空
        this.selectedCateList = []
        this.manyTableData = []
        this.onlyTableData = []
      } else {
        // 选中了三级分类后,获取该分类对应的参数列表数据
        this.getParamsList()
      } 
    }
    
    cateId() {
      if (this.selectedCateList.length === 3) {
        return this.selectedCateList[this.selectedCateList.length - 1]
      } else {
        return null
      } 
    }
    

    3 - 实现参数列表

    1. 根据选择的商品分类加载对应的参数数据

    • 参数列表布局
    • 根据分类 id 加载参数列表数据
    // 获取所有商品的分类列表
    const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes`, {
      params: { sel: this.activeName }
    })
    

    2. 处理标签数据格式

    将字符串形式的数据分隔为数组。

    res.data.forEach(item => {
      // 把字符串的可选项,分割为数组,重新赋值给 attr_vals
      item.attr_vals = item.attr_vals.length > 0 ? item.attr_vals.split(‘,') : []
    })
    

    3. 控制添加标签文本框的显示

    $nextTick 的执行时机:DOM 更新完毕之后

    <el-button size="small" v-else @click="showTagInput(scope.row)">+ New Tag</el-button>
    
    showTagInput(row) {
      row.tagInputVisible = true
      // 当我们修改了 data 中 tagInputVisible 的值以后,如果要操作文本框,必须等页面重新渲染完毕之后才可以,所以,必须把操作文本框的代码放到 $nextTick 中,当作回调去执行($nextTick 的执行时机,是在DOM 更新完毕之后)
      this.$nextTick(() => {
        this.$refs.saveTagInput.$refs.input.focus()
      })
    }
    

    4. 实现标签动态添加的文本框控制逻辑

    • 控制标签输入域的显示和隐藏
    • 对输入的内容进行数据绑定
    res.data.forEach(item => {
      // 把字符串的可选项,分割为数组,重新赋值给 attr_vals
      item.attr_vals = item.attr_vals.length > 0 ? item.attr_vals.split(‘,') : []
      // 为每个数据行,添加自己的 tagInputVisible ,从而控制自己展开行中的输入框的显示与隐藏
      item.tagInputVisible = false
      // 把文本框中输入的值,双向绑定到 item.tagInputValue 上
      item.tagInputValue = ''
    })
    

    5. 实现标签的添加和删除操作

    添加标签和删除标签使用的是同一个接口,参数是一样的。

    const { data: res } = await this.$http.put(
      `categories/${this.cateId}/attributes/${row.attr_id}`,
      {
        attr_name: row.attr_name,
        attr_sel: row.attr_sel,
        attr_vals: row.attr_vals.join(' ')
      } 
    )
    if (res.meta.status !== 200) {
      return this.$message.error('更新参数项失败!')
    }
    this.$message.success('更新参数项成功!')
    

    4 - 实现动态参数与静态属性添加

    • 动态参数与静态属性表单重用
    • 添加动态参数与静态属性使用的是同一个接口,参数是一样的
    const { data: res } = await this.$http.post(`categories/${this.cateId}/attributes`, {
      // 参数的名称
      attr_name: this.addForm.attr_name,
      // 参数类型 many only
      attr_sel: this.activeName
    })
    if (res.meta.status !== 201) return this.$message.error('添加参数失败!')
    this.$message.success('添加参数成功!')
    

    七. 商品管理

    1 - 商品管理概述

    商品管理模块用于维护电商平台的商品信息,包括商品的类型、参数、图片、详情等信息。通过商品管理模块可以实现商品的添加、修改、展示和删除等功能。

    2 - 商品列表

    • 实现商品列表布局效果
    • 调用后台接口获取商品列表数据
    const { data: res } = await this.$http.get('goods', { params: this.queryInfo })
    if (res.meta.status !== 200) {
      return this.$message.error('初始化商品列表失败!')
    }
    // 为商品列表赋值
    this.goodsList = res.data.goods
    // 为总数量赋值
    this.total = res.data.total
    

    3 - 添加商品

    1. 基本布局与分布条效果

    • 添加商品基本布局
    • 分布条组件用法
    <el-steps :active="activeName-0" finish-status="success" align-center>
      <el-step title="基本信息"></el-step>
      <el-step title="商品参数"></el-step>
      <el-step title="商品属性"></el-step>
      <el-step title="商品图片"></el-step>
      <el-step title="商品内容"></el-step>
      <el-step title="完成"></el-step>
    </el-steps>
    

    2. 商品信息选项卡Tab布局效果

    Tab 组件的基本使用

    <el-tabs tab-position="left" v-model="activeName" :before-leave="beforeTabLeave">
      <el-tab-pane label="基本信息" name="0"><!-- 基本信息面板 --></el-tab-pane>
      <el-tab-pane label="商品参数" name="1"><!-- 商品参数面板 --></el-tab-pane>
      <el-tab-pane label="商品属性" name="2"><!-- 商品静态属性面板 --></el-tab-pane>
      <el-tab-pane label="商品图片" name="3"><!-- 图片上传面板 --></el-tab-pane>
      <el-tab-pane label="商品内容" name="4"><!-- 商品描述面板 --></el-tab-pane>
    </el-tabs>
    

    3. 商品基本信息

    • 商品基本信息表单布局
    • 表单数据绑定
    • 表单验证
    addFormRules: {
      goods_name: [{ required: true, message: '请填写商品名称', trigger: 'blur' }],
      goods_price: [{ required: true, message: '请填写商品价格', trigger: 'blur' }],
      goods_weight: [{ required: true, message: '请填写商品重量', trigger: 'blur' }],
      goods_number: [{ required: true, message: '请填写商品数量', trigger: 'blur' }],
      goods_cat: [{ required: true, message: '请选择商品分类', trigger: 'blur' }]
    }
    

    4. 商品分类信息

    • 商品分类布局
    • 商品分类数据加载
    <el-cascader expand-trigger="hover" :options="cateList" :props="cascaderConfig" 
    v-model="addForm.goods_cat" @change="handleCascaderChange"></el-cascader>
    
    const { data: res } = await this.$http.get('categories')
    if (res.meta.status !== 200) {
      return this.$message.error('初始化商品分类失败!')
    }
    this.cateList = res.data
    

    5. 商品动态参数

    • 获取商品动态参数数据
    • 商品动态参数布局
    const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes`, {
      params: { sel: 'many' }
    })
    if (res.meta.status !== 200) return this.$message.error('获取动态参数列表失败!')
    // 把动态参数中的每一项数据中的 attr_vals,都从字符串分割为数组
    res.data.forEach(item => {
      item.attr_vals = item.attr_vals.length === 0 ? [] : item.attr_vals.split(' ')
    })
    this.manyData = res.data
    

    6. 商品静态属性

    • 获取商品静态属性数据
    • 商品静态属性布局
    const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes`, {
      params: { sel: 'only' }
    })
    if (res.meta.status !== 200) {
      return this.$message.error('获取动态参数列表失败!')
    }
    this.onlyData = res.data
    

    7. 商品图片上传

    图片上传组件基本使用

    <el-upload
      action="http://47.96.21.88:8888/api/private/v1/upload"
      :headers="uploadHeaders"
      :on-preview="handlePreview"
      :on-remove="handleRemove"
      :on-success="handleSuccess"
      list-type="picture">
        <el-button size="small" type="primary">点击上传</el-button>
    </el-upload>
    

    图片预览

    // 预览图片时候,触发的方法
    handlePreview(result) {
      this.previewImgSrc = result.response.data.url
      this.previewVisible = true
    }
    

    图片删除

    // 当移除图片,会触发这个方法
    handleRemove(result) {
      // 根据 result.response.data.temp_path 从 addForm.pics 数组中,找到要删除那个对象的索引值
      const index = this.addForm.pics.findIndex(item => item.pic === result.response.data.tmp_path)
      // 根据索引删除对应的图片信息对象
      this.addForm.pics.splice(index, 1)
    }
    

    完成图片上传

    // 图片上传成功
    handleSuccess(result) {
      if (result.meta.status === 200) {
        // 把上传成功后,图片的临时路径,保存到 addForm.pics 数组中,作为对象来保存
        this.addForm.pics.push({
          pic: result.data.tmp_path
        })
      } 
    }
    

    8. 商品详情

    富文本编辑器基本使用

    // 安装vue-quill-editor
    npm install vue-quill-editor -S
    
    import VueQuillEditor from 'vue-quill-editor‘
    Vue.use(VueQuillEditor)
    
    <quill-editor v-model="addForm.goods_introduce"></quill-editor>
    

    9. 完成商品添加

    • 处理商品相关数据格式
    • 调用接口完成商品添加
    // 先处理好商品相关的数据格式,然后再提交
    const newForm = _.cloneDeep(this.addForm)
    newForm.goods_cat = newForm.goods_cat.join(',')
    // 到此位置,商品相关数据已经准备好,可以提交了
    const { data: res } = await this.$http.post('goods', newForm)
    if (res.meta.status !== 201) return this.$message.error(res.meta.msg)
    this.$message.success('添加商品成功!')
    // 跳转到商品列表页
    this.$router.push('/goods/list')
    

    八. 订单管理

    1 - 订单管理概述

    订单管理模块用于维护商品的订单信息,可以查看订单的商品信息、物流信息,并且可以根据实际的运营情况对订单做适当的调整。

    2 - 订单列表

    1. 订单列表展示

    • 订单数据加载
    • 订单列表布局
    const { data: res } = await this.$http.get('orders', { params: this.queryInfo })
    if (res.meta.status !== 200) {
      return this.$message.error('获取订单列表失败!')
    }
    this.orderList = res.data.goods
    this.total = res.data.total
    

    2. 查看订单地址信息

    • 省市区三级联动效果
    • 省市区数据格式分析
    <el-cascader 
      :options="cityOptions" 
      v-model="selectedArea" 
      @change="changeProvince" 
      change-on-select 
      style="width: 100%;">
    </el-cascader>
    

    3. 查看订单物流信息

    • 调用接口获取物流数据
    • 实现物流信息列表效果
    const { data: res } = await this.$http.get('/kuaidi/110121212622')
    if (res.meta.status !== 200) {
      return this.$message.error('获取物流进度失败!')
    }
    this.wlList = res.data
    

    九. 数据统计

    1 - 数据统计概述

    数据统计模块主要用于统计电商平台运营过程的中的各种统计数据,并通过直观的可视化方式展示出来,方便相关 运营和管理人员查看。

    2 - 用户来源数据统计报表

    1. Echarts 第三方可视化库的基本使用

    // 安装echarts库
    npm install echarts -S
    
    // 导入echarts接口
    import echarts from 'echarts'
    

    2. 实现用户来源数据统计报表

    1. 调用接口获取后台接口数据
    2. 通过echarts的api实现报表效果
    // 基于准备好的dom,初始化echarts实例
    var myChart = echarts.init(this.$refs.main)
    const { data: res } = await this.$http.get('reports/type/1')
    if (res.meta.status !== 200) return this.$message.error('初始化折线图失败!')
    const data = _.merge(res.data, this.options)
    // 绘制图表
    myChart.setOption(data)
    

    相关文章

      网友评论

          本文标题:Vue电商-功能模块

          本文链接:https://www.haomeiwen.com/subject/nbkiertx.html