黑马后台管理总结


提示:以下是本篇文章正文内容,下面案例可供参考

本地接口baseurl根地址http://localhost:8888/api/private/v1/

登录流程:

一..登录总思路 -baseurl/login

1.在登录页面输入用户名和密码

2.调用后台接口进行验证

3.通过验证之后,根据后台的响应状态跳转到项目主页

1. 登录组件布局

通过 Element-UI 组件实现布局

el-form el-form-item el-input el-button

2. 实现登录

通过 axios 调用登录验证接口

登录成功之后保存用户 token 信息

跳转到项目主页

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')
​

3. 路由导航守卫控制访问权限

如果用户没有登录,但是直接通过 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()
})

4. Vue 直接操作 DOM

通过 ref 标注 DOM 元素

 // 在 DOM 元素上通过 ref 属性标注,属性名称自定义
<div ref="info">hello</div>

通过 $refs 获取 DOM 元素

// 通过 Vue 实例的 $refs 获取标记 ref 属性的元素
let info = this.$refs.info.innerHTML
console.log(info) // hello

退出功能

基于 token 的方式实现退出比较简单,只需要销毁本地的 token 即可。这样,后续的请求就不会携带 token ,

必须重新登录生成一个新的 token 之后才可以访问页面。

主页布局

左侧菜单布局

通过接口获取菜单数据
通过 axios 请求拦截器添加 token,保证拥有获取数据的权限。
// axios请求拦截
axios.interceptors.request.use(config => {
// 为请求头对象,添加 Token 验证的 Authorization 字段
config.headers.Authorization = window.sessionStorage.getItem('token')
return config
})

动态渲染菜单数据并进行路由控制
通过 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. 用户管理

1.1 用户管理概述

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

1.2 用户信息列表展示

1. 用户列表布局

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

1.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. 表格数据分页

分页思路 : 本接口主要是后台分页:后台要求传入当前页数 pagenum, 每页条数 pagesize 。后台会返回
总条数 total, 当前页数 pagesize 。使用分页插件实现分页样式,当条数改变时传入条数提交接口,当页
数改变时传入页数提交接口
分页组件用法:
① 当前页码:pagenum
② 每页条数:pagesize
③ 记录总数:total
④ 页码变化事件
⑤ 每页条数变化事件
⑥ 分页条菜单控制
<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. 搜索功能

将搜索关键字,作为参数添加到列表查询的参数中。
传入搜索值,请求用户列表接口,注意传入的参数 - 当前页数 pagenum, 每页条数
pagesize
<el-input
placeholder="请输入搜索的内容"
v-model="queryInfo.query"
clearable
@clear="getUserList">
<el-button slot="append"
icon="el-icon-search"
@click="getUserList"></el-button>
</el-input>

用户状态控制

1. 开关组件的用法
2. 接口调用更改用户的状态
<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('修改状态失败!')
}
}

1.4 添加用户

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

添加用户 -- 思路: 1. 调用 dialog 对话框组件显示 2. 表单双向数据绑定 :model="addForm", 验证规则
绑定 :rules="addFormRules" 3. 提交表单时 , 获取该表单名字 ref="addFormRef" ,验证表单规则 , 可自定
义规则。注意 prop 属性绑定的验证规则里的属性 4. 提交接口,在次调用渲染列表
<el-dialog title="添加用户" :visible.sync="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
})

1.5 修改用户

修改用户 -1. 弹出修改对话框 , 获取当前行信息 2. 提前存储当前行用户信息。为什么要存储每行信息?
因为点击确定操作时,当前行用户信息不知道。 3. 因为有多列都涉及到点击操作 , 所以要用作用域插槽
scope 有属性 $index ,代表索引, row- 当前行所有信息
<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. 编辑提交表单
更新用户 - 验证规则通过后,请求!!!注意接口 ,id 是必传项 (id 获取时 , 是变量 ) ,其它参数要带着 ,
容可以为空

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
})

1.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()
},

角色列表展示

 async getRolesList() {
 const { data: res } = await this.$http.get('roles')
 if (res.meta.status !== 200) {
 return this.$message.error('获取角色列表失败!')
 }
 this.rolesList = res.data
 },

用户角色分配

. 调用角色对话框,存储角色信息,点击更新时用到 2. 获取所有角色接口,存储数据,更
新时用到 3. 下拉列表选择时 -v-model 绑定数据 id ,属性 :value="item.id" 配合获取下拉选择项 4. 点击确
定时,提交用户 id, 角色 id 更新数据

 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
 }
完成角色分配功能
. 获取角色信息,下拉选择时的角色 id( 注意是绑定的角色 id 数据 selectedRoleId) 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
 }

2.1 权限管理业务分析

通过权限管理模块控制不同的用户可以进行哪些操作,具体可以通过角色的方式进行控制,即每个用户分配
一个特定的角色,角色包括不同的功能权限。
渲染权限列表思路 - 使用三重嵌套 for 循环生成权限下拉列表
# 调用 el-table 里的展开列数据格式
# 布局要合理 - 因为页面要的格式是 3 , 数据格式也是 3 , 如何取出每 1 层下对应的数据? table 嵌套外
1 2 列,第 2 列里又嵌套 1 2 列。这样总共就有了 3 列。每列渲染对应的数据

权限列表展示

权限列表展示
 <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
 }
角色列表展示
 // 获取所有角色列表
 async getRolesList() {
 const { data: res } = await this.$http.get('roles')
 if (res.meta.status !== 200) {
 return this.$message.error('获取角色列表失败!')
 }
 this.rolesList = res.data
 },
<el-table-column type="expand">
					<template slot-scope="scope">
						<el-row :class="['bdbottom',i1===0?'bdtop':'','vcenter']" v-for="(item1,i1) in scope.row.children" :key="item1.id">
							<!-- 渲染一级权限 -->
							<el-col :span="5">
								<el-tag closable @close="removeRightById(scope.row,item1.id)">{{item1.authName}}</el-tag>
								<i class="el-icon-caret-right"></i>
							</el-col>
							<!-- 渲染二级和三级权限 -->
							<el-col :span="19">
								<el-row :class="[i2===0?'':'bdtop','vcenter']" v-for="(item2,i2) in item1.children" :key="item2.id">
									<el-col :span="6">
										<el-tag type="success" closable @close="removeRightById(scope.row,item2.id)">{{item2.authName}}</el-tag>
										<i class="el-icon-caret-right"></i>
									</el-col>
									<el-col :span="18">
										<el-tag type="warning" v-for="item3 in item2.children" :key="item3.id" closable @close="removeRightById(scope.row,item3.id)">{{item3.authName}}</el-tag>
									</el-col>
								</el-row>

							</el-col>
						</el-row>
					</template>
				</el-table-column>
————————————————
版权声明:本文为CSDN博主「cc--crush」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_52690585/article/details/121179469
1. 表格行展开效果

 2. 渲染一级权限菜单

. 默认选中实现?通过递归的形式,获取当前角色下所有三级权限的 id ,并保存到 默认 defKeys
中数组中 。递归会不断的遍历当前角色下 childen 推入默认选中数组
#4. 提交选中更新权限 - 点击为角色分配权限 - 注意这里调用 element 两个方法来记录你选中了那些: 1
个是全选中方法 getCheckedKeys() 1 个是半选中方法 getHalfCheckedKeys, 在把它们合并成数组
[105,116,117,150,101,104] 。注意接口提交的时候要的是字符串
 <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('删除权限成功!')
2.5 角色权限分配
实现对话框布局效果
控制对话框显示和隐藏
 <!-- 分配权限的对话框 -->
 <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 nodekey="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,3 级分类 ) ,分类参数是给某个 3 级分类填加参
数或者属性说明的,商品列表是为具体某个商品上传详情信息的 , 比如图片,描述等。
录属关系 : 商品列表隶属于某个分类参数 , 分类参数又隶属于某个商品分类
实现基本布局
实现分类列表数据加载
 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
树形表格
1. 第三方树形表格的基本使用
安装依赖包 (地址:
https://github.com/MisterTaki/vue-table-with-tree-grid
 npm i vue-table-with-tree-grid -S
import Vue from 'vue'
 import ZkTable from 'vue-table-with-tree-grid'
 Vue.use(ZkTable)
实现分类树形列表
实现树形列表布局并进行数据填充
自定义表格列
 <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>
分页功能
实现分页组件效果
分页组件数据处理
<!-- 分页区域 -->
 <el-pagination 
 @current-change="handleCurrentChange" 
 :current-page="queryInfo.pagenum" 
 :page-size="queryInfo.pagesize" 
 layout="total, prev, pager, next, jumper" 
 :total="total">
 </el-pagination>
添加分类
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>
实现分类级联菜单效果
级联菜单使用 -
<!-- expandTrigger='hover'( 鼠标悬停触发级联 ) v-model( 设置级联菜单绑定数据 ) :options( 指定级
联菜单数据源 ) :props( 用来配置数据显示的规则 )
clearable( 提供 “X” 号完成删除文本功能 ) change-on-select( 是否可以选中任意一级的菜单 )
@change="parentCateChanged" 选择项改变时触发事件 -->
<el-cascader expand-trigger="hover" :options="parentCateList" :props="cascaderProps" v
model="selectedKeys" @change="parentCateChanged" clearable change-on-select>
<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
控制父级分类的选择
父级分类选择时,获取对应的分类 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
 }
 }
# 接口需要入参 - 分类名称 , 父分类 id, 当前分类层级
const { data: res } = await this.$http.post('categories', {cat_name: '', cat_pid: 0,cat_level: 0})
# 分类层级,要根据父分类层级提交参数 , 你怎么知道父级要类选择了几级?

// 给级联菜单绑定一个数组 ,selectedKeys [1] ,你选择的项会存储到数组里 # 选择的分类层级是哪个?
// 级联如果 selectedKeys 数组中的 length 大于 0 ,证明选中的父级分类。反之,就说明没有选中任
何父级分类

参数管理概述

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

布局 - 通过 el-tab 进行切换,通过 v-model 绑定激活项
1 逻辑实现 - 注意这里只允许为第三级分类添加相关参数!
# 用户选中前两级怎么办?设置动态参数数据,静态属性数据为空,这样就不会渲染数据
# 如果选中是第三级? - 根据所选分类的 cateId( 分类 id 是根据你所选的第几个大类 , 动态获取的 ) ,和当前
所处的面板,获取对应的参数
const { data: res } = await this.$http.get( categories/${this.cateId}/attributes , {params: {
sel: this.activeName } } )

# 三级分类 id 如何获取? - 级联菜单绑定数组 selectedCateKeys, 级联选择改变时,数组里会有 3 个值,获
取下
<el-cascader expand-trigger="hover" :options="catelist" :props="cateProps" v
model="selectedCateKeys" @change="handleChange">
// 可放在计算属性里 , 因为 cateId 是动态获取的 computed: {
// 当前选中的三级分类的 Id
cateId() {
if (this.selectedCateKeys.length === 3) {
return this.selectedCateKeys[2]
}
return null
}
}

 

封装一个获取参数列表数据 getParamsData() , 方便级联选中变化时调用 ,tab 切换时也会调用
每行里 tag 标签 - 通过组件实现 ——tag 删除回车输入内容时触发编辑提交参数接口 put 提交
. 下拉选择时,获取参数列表数据,对数据里的 "attr_vals": "a b c" 给的是字符串进行转换成数组操
给每行的 tag 组件外面加
入作用域插槽,渲染时只渲染当前行数据 (scope.row.attr_vals), 输入内容时只操作当前行数据 绑定 v
model 时,也只绑定当前行
<template slot-scope="scope">
                <el-tag
                  closable
                  v-for="(item, index) in scope.row.attr_vals"
                  :key="index"
                  @close="removeTag(index, scope.row)"
                  >{{ item }}</el-tag
                >
                <el-input
                  class="input-new-tag"
                  v-if="scope.row.newTagVisible"
                  v-model="scope.row.newTagValue"
                  ref="saveTagInput"
                  size="small"
                  @keyup.enter.native="handleInputConfirm(scope.row)"
                  @blur="handleInputConfirm(scope.row)"
                >
                </el-input>
                <el-button
                  v-else
                  class="button-new-tag"
                  size="small"
                  @click="showInput(scope.row)"
                  >+ New Tag</el-button
                >
              </template>
.tag 输入内容时 , 1 次输入不上,会合并行的问题 ? 在遍历 attr_vals 数据转换成数组时,就给每个对象
当前行绑定属性
if (this.cateSelected.length !== 3) {
        this.cateSelected = [];
        this.manyParamsList = [];
        this.onlyParamsList = [];
        return null;
      }
      const res = await attributeslist({
        id: this.cateID,
        rel: this.activeName,
      });

      if (res.meta.status !== 200) return;

      res.data.forEach((item) => {
        item.attr_vals = item.attr_vals ? item.attr_vals.split(" ") : [];
        item.newTagVisible = false;
        item.newTagValue = "";
      });
      this.activeName === "many"
        ? (this.manyParamsList = res.data)
        : (this.onlyParamsList = res.data);

5.1 商品管理概述

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

基本布局与分布条效果

布局 - 用到步骤条 el-step 组件 , 每个 tab 组件里套着表单组件。步骤条与 tab 如何联动?,可给 tab
1 个激活索引 v-model="activeIndex" 同时每个 tab 子项给到 name=“ 索引 ,步骤条调用该索引
<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>
tab 切换验证:切换下一个 , 得验证上一个是否选择?可用离开之前属性 -:before-leave 调用方法,
判断用户是否选择了下拉的 3 级列表
<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 级分类 id 请求对应数据。你怎么知道它点击的是商
品属性,还是商品参数?点击时 @tab-click="tabClicked" 通过判断当前激活索引是多少,做相应的接口 请求

添加商品

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. 商品图片上传

1. 通过存在内存中的文件流,获取后台会返回 1 个正式路径地址,你把此路径写入到图片中
即可
移除某个图片 : 0. 在移除的时候删除的是临时路径 1. 如何获取将要删除的图片的临时路径 ? 通过存在内
存中的文件流, 从 提交表单图片 pics 数组中,找到这个图片对应的索引值。从该数组中 splice 切除掉
图片上传成功: 0. 点击上传成功后 , 后台会返回临时路径和正式地址 1. 拼接得到一个图片信息对象 const
picInfo = { pic: response.data.tmp_path } !!注意,因为后端接口需要传 pic 字段,所以拼接下 2.
图片信息对象 picInfo push 到表单图片 pics 数组中。
 <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')

6.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>

7.1 数据统计概述

数据统计模块主要 用于统计电商平台运营过程的中的各种统计数据 ,并通过直观的可视化方式展示出来,方便相关
运营和管理人员查看。
1. Echarts 第三方可视化库的基本使用
 // 安装echarts库
 npm install echarts -S
// 基于准备好的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-cli 的命令选项可以生成打包报告
 // --report 选项可以生成 report.html 以帮助分析包内容
 vue-cli-service build --report
② 通过可视化的UI面板直接查看报告( 推荐
在可视化的UI面板中,通过 控制台 分析 面板,可以方便地看到项目中所存在的问题
开发环境 : npm run dev/serve 在本地运行的,对包的体积基本没要求,就是本地玩的
生产环境 :npm run build 生成 1 dist 文件夹,需要对这个文件进行体积的优化,然后上传到线上运行
我怎么知道你是在开发或者生产运行的? process.env.NODE_ENV === 'production' 生产环境
开发与上线都会运行 index.html 文件 , 这个文件越小 , 首页加载越快 , 公司越省钱 ( 大公司 )
. 打包介绍:
npm run build 生成打包 dist 文件。 dist 文件就是要上线的项目
app.js 一般是打包的 main.js 里的引入
chunk-vendors 一般是打包的第三方插件 , 框架
Order_Report 一般是路由按需加载的名字
.map 文件 是 .js 文件的映射镜像

2. 通过 vue.config.js 修改 webpack 的默认配置

通过 vue-cli 3.0 工具生成的项目, 默认隐藏了所有 webpack 的配置项 ,目的是为了屏蔽项目的配置过程,让程
序员把工作的重心,放到具体功能和业务逻辑的实现上。
如果程序员有修改 webpack 默认配置的需求,可以在项目根目录中,按需创建 vue.config.js 这个配置文件,从

而对项目的打包发布过程做自定义的配置(具体配置参考 https://cli.vuejs.org/zh/config/#vue-config-js )。

. public 文件里找到 index.html 进行 cdn 引入

. 优化其它项
0. 去除 sourcemap 镜像文件 ,map 文件比较占体积
1. 打包输出目录,要变成 ./ ,否则加载 index.html 文件时,找不到其它 js,css 文件
2. 开发环境配置 , 一般可配置跨域

 

 相关面试题

项目概述:本项目,是一个商品后台管理系统。采用前后端分离开发,主要用于给内部运营人员管理商
品用的。主要有登录模块 ( 登录注册忘记密码等页面 ), 用户管理模块 ( 管理内部登录用户的 ), 权限管理 ( 包含
角色列表 , 权限列表 [ 不同人有不同权限 ]), 商品管理 ( 管理商品的增删改查 ) ,数据统计 ( 领导看商品销售数
据,主要用到 echarts) 等模块
. 登录模块 :
1. 登录鉴权如何做的 ?
1. 前台传入用户名和密码,后台返回 token 。把 token 存到本地或 vuex 2. 通过 router 的全局守卫
beforeEach 进行鉴权处理 , 判断是否有 token 3. 进入到后台,请求其它数据要带着 token, axios 请求拦
截器 , 可统一设置请求头协议 header token
2. 登录后你们的 token 有没有过期时间 ? 过期了怎么处理?
有过期时间,一般是一天 , 后台返回错误码(一般是 4001 5001 )提示我过期了或者无效 token
进行判断提醒用户跳转重新登录
3. 登录验证码怎么实现的 ? 登录密码有没有加密传给后台?
后端提供了一个接口,返回了图片路径,前端渲染就行了
有加密,通过引入 md5 插件加密下传给后台,后台解析下就可以了
. 用户模块 - 管理网站不同登录用户的
1. 你们分页,搜索,分配角色是怎么实现的?
分页功能 : 分为前端分页和后端分页,大部分都是让后端进行分页 . 我们分页是后端进行的分页,前端通过 UI 框架提供的分页组件实现 , 需要后台返回总页数 total, 当前第
几页 pagenum
2. 分配角色 : 需要通过作用域插件传过来当前行信息,下拉时获取选择的角色 id 传给后台
. 权限管理模块
1. 你们的权限是如何实现的?根据前台登录不同用户,后台返回该用户的权限路径 , 然后前端在路由表
里,把所有的路径都写上。这样其实就是静态路由
2. 你是静态路由,还是动态路由?你有没有听说过动态路由?
所谓动态路由就是通过后台返回的路由路径,动态填加的, router.addRoutes()
3. 分配权限
后台返回的是树结构数据 , 结合绑定 tree 组件 , 进行渲染就行了。
打开弹窗时,有默认选中如何实现?给它绑定一个数组,通过递归遍历,拿到该角色下所有权限 id
给它推入到该默认选择数组中。
提交更新权限 - 传入角色 id, 和所有选中的权限 id 给后台
. 商品管理模块 - 对所有商品进行增删改查操作
图片上传如何实现的? 1. 通过 upload 组件进行上传 ,前端给它 url 上传路径和头协议 token 2. 上传
成功后,后台返回临时路径 ( 前台有删除操作 , file 文件里删除的临时路径 ) 和正式地址 ( 做预览操作 )
如果用原生实现上传,说下思路? 1. 通过 input 标签 ,type=file 2. 文件协议是通过 form-data 传输二进制
3. 提交接口路径
.echarts 图表 - 主要给领导看一些销售数据用的
通过引入 echarts 插件,找到相关图表,复制里面代码 , 修改 options 配置里 data 数据
. 首屏加载如何优化?
0. 首先要区分开发环境和生产环境 , 杂区分?创建 2 个文件,里面定义了环境变量。通过
process.env.NODE_ENV === 'production' 生产环境, process.env.NODE_ENV === 'development'
开发环境
1. 把大的第三方插件 -echarts,elmentui 抽离出去。通过 webpack 插件 chainWebpack ,配置链式调用找
到生产环境的 main, 单独配置 externals 抽离。在 index.html 通过 cdn 引入链接
2.SourceMap 镜像文件配置成 false
3. 路由懒加载
4. console.log 移除
5. 文件压缩 ( 后端开户 gzip 压缩 )

总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值