vue.js|尚品汇后台管理系统


尚品汇后台管理系统

  • 1、登录(退出登录)
  • 2、路由设置(***)
    • 路由表component属性
  • 3、品牌列表模块
    • 3.1 el-pagination layout属性
    • 3.2 封装四个模块api
    • 3.3 this滥用和参数解构
    • 3.4 品牌列表展示(插槽)
    • 3.5 品牌信息新增和修改
    • 3.6 表单验证
    • 3.7 删除品牌信息
  • 4、商品属性
    • 4.1 三级联动
    • 4.2 商品属性展示

1、登录(退出登录) 后台接口swagger在线文档:
后台接口1
后台接口2
1、将所有的api接口url更换为和swagger在线文档相同的url。
2、跨域解决
devServer部分(proxy代理解决跨域)
devServer: { port: port, open: true, overlay: { warnings: false, errors: true }, proxy: { // 会把请求路径中的/api换为后面的代理服务器 '/dev-api': { // 提供数据的服务器地址 target: 'http://39.98.123.211', pathRewrite: { '^/dev-api': '' } } }},

记得重启项目
3、切记将请求拦截器的X-Token改为token,否则后台会返回jwt空错误。
config.headers['token'] = getToken()
退出登录部分可以不做修改。
2、路由设置(***) 路由部分代码
export const constantRoutes = [ { path: '/login', component: () => import('@/views/login/index'), hidden: true },{ path: '/404', component: () => import('@/views/404'), hidden: true },{ path: '/', component: Layout, redirect: '/dashboard', children: [{ path: 'dashboard', name: 'Dashboard', component: () => import('@/views/dashboard/index'), meta: { title: '首页', icon: 'dashboard' } } ] }, { path: '/product', name: 'Product', component: Layout, meta: { title: '商品管理', icon: 'el-icon-goods' }, children: [{ path: 'trademark', name: 'TradeMark', component: () => import('@/views/tradeMark'), meta: { title: '品牌管理' } }, { path: 'attr', name: 'Attr', component: () => import('@/views/Attr'), meta: { title: '平台属性管理' } }, { path: 'sku', name: 'Sku', component: () => import('@/views/Sku'), meta: { title: 'Sku管理' } }, { path: 'spu', name: 'Spu', component: () => import('@/views/Spu'), meta: { title: 'Spu管理' } } ] }, // 404 page must be placed at the end !!! { path: '*', redirect: '/404', hidden: true } ]

路由表component属性 component用法一:
path: 'trademark', name: 'TradeMark', component: () => import('@/views/tradeMark'),

当访问path为trademark时,会显示tradeMark这个组件。上面只是component最简单的应用。
component用法二
path: '/product', name: 'Product', component: Layout, meta: { title: '商品管理', icon: 'el-icon-goods' }, children: [{ path: 'trademark', name: 'TradeMark', component: () => import('@/views/tradeMark'), meta: { title: '品牌管理' } }]

如果一个路由只是一个菜单项,并不对应相应的组件,那么此时的component为本菜单项所在的路由组件。
例如:上面代码中product只是一个菜单项,并不对应相应组件。所以他的component应该为他所在的组件,即component: Layout。trademark为子菜单项,有具体对应的组件,所以component: () => import('@/views/tradeMark'),trademark的component原理就是用法一。
前端菜单栏显示的实现具体如下:
遍历路由信息数组,将路由项渲染为菜单项。菜单项的信息在路由信息中获取。
(1)如果路由项只有一个子路由,则将该子路由信息作为作为菜单项信息。
(2)如果路由项有多个子路由,将父路由信息作为一级菜单项信息。然后,遍历所有的子路由,生成相应的二级菜单项。
这个前端菜单项显示代码值得研究,写的非常好。
3、品牌列表模块 3.1 el-pagination layout属性 layout是指分页器各组件的排列方式,例如:
layout=" prev, pager, next, jumper,->,sizes,total"
vue.js|尚品汇后台管理系统
文章图片

->后面的组件会被放在页面的最右边。如下图所示:
vue.js|尚品汇后台管理系统
文章图片

3.2 封装四个模块api 四个模块分别为attr、sku、spu、tradeMark。
每个模块的api封装为对应的js文件,如下图所示:
vue.js|尚品汇后台管理系统
文章图片

为了方便使用,将四个模块再次封装到一个js文件中,然后统一暴露。
vue.js|尚品汇后台管理系统
文章图片

这样如果我们使用时,只需要import这个js文件就可以使用了,但是为了更加简介,我们可以将这个js文件在main.js中注册,将其是设置为全局属性。
// 引入api请求接口 import API from '@/api' Vue.prototype.$API = API

之后在组件中使用四个模块的api函数时,可直接通过this.$API.函数名调用。
3.3 this滥用和参数解构 data中的数据十分常用,当我们使用时可能会频繁的通过this.使用data中的数据,这样容易发生滥用this去读取data中数据,程序性能会下降。具体原因链接描述
解决方法:ES6允许我们通过参数解构来避免this的滥用。
例如,getPageList函数需要使用page, limit两个属性。直接const { page, limit } = this解构出这两个属性。
export default { name: 'TradeMark', data() { return { page: 1, limit: 3 } }, mounted() { this.getPageList() }, methods: { getPageList() { const { page, limit } = this this.$API.trademark.getTradeMarkInfo(page, limit) } } }

3.4 品牌列表展示(插槽) 1、获取数据函数
设置了pager = 1参数,调用时,如果传值就会将值赋给pager ,如果不传pager = 1。即默认获取的是第一页数据。
async getPageList(pager = 1) { this.page = pager const { page, limit } = this const result = await this.$API.trademark.getTradeMarkInfo(page, limit) if (result.code === 200) { this.total = result.data.total this.list = result.data.records } }

2、需要注意的是插槽的使用。我们需要通过插槽获取父组件数据。
el-table插槽使用方法:
vue.js|尚品汇后台管理系统
文章图片

品牌logo列使用了插槽。所以通过一下代码探究插槽的使用

下面三个箭头分别对应slot-scope="{row, column, $index}中的row, column, $ index。
row表示表格当前一行的全部信息;
column表示当前列的一些属性;
$index表示当前行数据在整个数据数组中的下标。
vue.js|尚品汇后台管理系统
文章图片

这里我们只需要用到当前行所包含的品牌logo图片链接,所以只需要使用row,完整代码如下:

3、分页器修改页面大小和修改当前页码都比较简单,直接贴代码。
// 修改当前页码 handleCurrentChange(current) { this.getPageList(current) }, // 修改页面大小 handleSizeChange(size) { this.limit = size this.getPageList() },

注意:handleSizeChange中的getPageList需要带参数,因为getPageList定义了默认参数pager=1,如果不传入current,则getPageList的默认参数pager=1就会生效,就会一直请求第一页数据。
3.5 品牌信息新增和修改 1、头像上传组件
新增中比较重要的时头像上传组件,代码如下
vue.js|尚品汇后台管理系统
文章图片
只能上传jpg文件,且不超过2MB

图片数据不能用v-model绑定,
action 必选参数,上传的地址。这里的 action取值是上传图片的接口,是后台提供好的接口。
before-upload表示上传成功前的函数
beforeAvatarUpload(file) { const isJPG = file.type === 'image/jpeg' const isLt2M = file.size / 1024 / 1024 < 2if (!isJPG) { this.$message.error('上传头像图片只能是 JPG 格式!') } if (!isLt2M) { this.$message.error('上传头像图片大小不能超过 2MB!') } return isJPG && isLt2M }

on-success表示上传成功后的函数
handleAvatarSuccess(res, file) { // res是上传成功后返回给前端的数据 // file是上传成功后服务器返回给前端的数据 this.tmFrom.logoUrl = URL.createObjectURL(file.raw) }

上面两个函数饿了吗UI官网都以给出,理解即可。
2、新增和修改函数
新增和修改按钮使用的是同一个弹窗。
(1)点击添加按钮显示弹窗
记得清空上次操作的数据
addTradeMark() { this.dialogFormVisible = true // 清空上次操作的数据 this.tmFrom = { tmName: '', logoUrl: '' } }

(2)点击修改按钮显示弹窗(浅拷贝问题)
this.$tmFrom = row会使得二者同时指向数据的引用,当修改tmFrom表单项时,表格中数据也会改变,如果修改后点了取消按钮,表格中数据会发生改变。所以,要解决浅拷贝
updateTradeMark(row) { this.dialogFormVisible = true // ...解决单层浅拷贝问题 this.tmFrom = { ...row } }

当赋值的对象row中还有对象元素时,又会出现上面的问题,所以可以通过深拷贝JSON.parse(JSON.stringfy())实现。
(3)击弹窗的确定按钮实现数据的修改或新增
新增和修改成功后,需要再次获取品牌信息。需要注意,如果时新增则刷新后显示第一页,如果是修改,则要在当前页刷新显示。
async addOrUpdate() { this.dialogFormVisible = false let result = await this.$API.trademark.addOrUpdateTradeMark(this.tmFrom) if (result.code === 200) { this.$message.success(this.tmFrom.id ? '修改品牌成功' : '添加品牌成功') } // 现需要再次获取品牌信息,修改数据要在当前页刷新 this.getPageList(this.tmFrom.id ? this.page : 1) },

新增或修改品牌API函数
// 新增或修改品牌 export const addOrUpdateTradeMark = (tradeMark) => { // 有id则为修改 if (tradeMark.id) { return request({ url: 'admin/product/baseTrademark/update', method: 'put', data: tradeMark }) } // 无id则为新增 return request({ url: 'admin/product/baseTrademark/save', method: 'post', data: tradeMark }) }

3.6 表单验证 表单验证,主要分以下几步:
(1)定义rules
(2)表单绑定rules,表单项prop绑定验证属性
(3)提交表单时触发的函数内,先进行表单验证,如果成功执行后续操作,否则弹出失败。
3.7 删除品牌信息 (1)气泡确认框
@onConfirm="deleteTradeMark(row)"绑定的是删除函数

(2)删除函数
删除成功后要刷新页面。
async deleteTradeMark(row) { const result = await this.$API.trademark.deleteTradeMark(row.id) if (result.code === 200) { this.$message.success('删除成功') // 成功后,重新获取数据 await this.getPageList(this.list.length > 1 ? this.page : 1) } else { this.$message.error('删除失败') } }

示例:
vue.js|尚品汇后台管理系统
文章图片

4、商品属性 4.1 三级联动 (1)三级联动静态组件
示例
vue.js|尚品汇后台管理系统
文章图片

由于多个页面都使用到了上面的el-card,所以将其封装为全局组件。
main.js
import CategorySelect from './components/CategorySelect' Vue.component(CategorySelect.name, CategorySelect)

注意:虽然该全局组件的名字是CategorySelect ,但是在使用时最好用后面的形式
原因:html不区分大小写,会将大写字母转换为小写,并在前面加-。即CategorySelect 转换为category-select
(2)三级联动数据展示
示例:
vue.js|尚品汇后台管理系统
文章图片

html静态代码
查询

data属性
data() { return { category1List: [], category2List: [], category3List: [], formList: { category1: '', category2: '', category3: '' } }

注意:formList内容是三个选择框选中属性的id。后续也是通过id去查询。
针对于选中一级属性后,自动获取二级属性列表,选中二级属性后,再自动获取三级属性列表问题。
最初思路:通过computed或者watch去实现,但都没有成功。
老师的方法:通过给选择框添加@change属性,再回调函数内去获取下一级属性列表。
@change绑定的获取三级列表函数都比较简单,这里就不过多描述。
// 获取一级分类 // 获取一级分类 async getCategory1List() { const result = await this.$API.attr.reqCategory1List() if (result.code === 200) { this.category1List = result.data } else { alert(result.message) } }, // 通过选中一级属性id获取二级属性列表 async getCategory2List() { // 当一级分类改变时,上一次选择的二级和三级分类应设置为空 this.category2List = [] this.category3List = [] this.formList.category2 = '' this.formList.category3 = '' const result = await this.$API.attr.reqCategory2List(this.formList.category1) if (result.code === 200) { this.category2List = result.data } else { alert(result.message) } }, // 通过选中二级属性id获取三级属性列表 async getCategory3List() { // 当二级分类改变时,上一次选择的三级分类应设置为空 this.category3List = [] this.formList.category3 = '' const result = await this.$API.attr.reqCategory3List(this.formList.category2) if (result.code === 200) { this.category3List = result.data } else { alert(result.message) } },

(3)将选中的三级分类id传递给父组件
这里是通过点击查询按钮实现的父子组件通信
查询按钮绑定的回调
// 子组件将三级分类id传递给父组件,父组件使用该id去查询并展示数据 async onSubmit() { this.$emit('getCategoryId', this.formList) }

父组件

父组件data
data() { return { category1Id: '', category2Id: '', category3Id: '' } },

父子组件通信,父组件的接收函数:getCategoryId函数
只有当三级id不为空时,才发请求。
// 获取子组件传递三级分类id getCategoryId(list) { this.category1Id = list.category1Id this.category2Id = list.category2Id this.category3Id = list.category3Id if (this.category3Id) { console.log('发请求') } }

4.2 商品属性展示 【vue.js|尚品汇后台管理系统】通过三级联动获取到要展示的属性id后,接下来就是通过该id请求数据,然后展示。

    推荐阅读