提示:以下是本篇文章正文内容,下面案例可供参考
本地接口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. 用户列表布局
![](https://img-blog.csdnimg.cn/85f21716402e485b8e67c7f5e3fc74f5.png)
面包屑导航 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提供了大量能使我们快速便捷地处理数据的函数和方法。