项目简介:
该项目为电商后台的管理系统。设计了登录页面。
管理人员需要通过输入正确的用户名和密码才能登录。登陆成功之后进入管理页面:
管理页面由五个子模块组成:用户管理,权限管理,商品管理,订单管理,数据统计;
每个子模块有若干子模块组成,用户管理下->用户列表,权限管理->角色列表,权限管理,商品管理->商品列表,分类参数,商品分配,订单管理->订单列表,数据统计->数据报表
登录页面
登录页面中对用户输入的内容进行预校验,如果不符合要求则,则不向后端发送请求,同事挂载路由守卫,防止强制跳转。同时设置令牌校验,避免重复登录。如果用户输入格式正确的用户名以及密码时,向后端发送请求,请求通过则跳转到管理页面,否则返回登录页面。
路由导航守卫:
// 挂载路由导航守卫
router.beforeEach((to, from, next) => {
// to 将要访问的路径
// from 代表从哪个路径跳转而来
// next 是一个函数,表示放行
// next() 放行 next('/login') 强制跳转
if (to.path === '/login') return next()
// 获取token
const tokenStr = window.sessionStorage.getItem('token')
if (!tokenStr) return next('/login')
next()
})
登录页面核心代码:
export default {
data() {
return {
// 这是登录表单的数据绑定对象
loginForm: {
username: 'admin',
password: '123456'
},
// 这是表单的验证规则对象
loginFormRules: {
// 验证用户名是否合法
username: [
{ required: true, message: '请输入登录名称', trigger: 'blur' },
{ min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }
],
// 验证密码是否合法
password: [
{ required: true, message: '请输入登录密码', trigger: 'blur' },
{ min: 6, max: 15, message: '长度在 6 到 15 个字符', trigger: 'blur' }
]
}
}
},
methods: {
// 点击重置按钮,重置登录表单
resetLoginForm() {
// console.log(this);
this.$refs.loginFormRef.resetFields()
},
login() {
this.$refs.loginFormRef.validate(async valid => {
if (!valid) return
const { data: res } = await this.$http.post('login', this.loginForm)
if (res.meta.status !== 200) return this.$message.error('登录失败!')
this.$message.success('登录成功')
// 1. 将登录成功之后的 token,保存到客户端的 sessionStorage 中
// 1.1 项目中出了登录之外的其他API接口,必须在登录之后才能访问
// 1.2 token 只应在当前网站打开期间生效,所以将 token 保存在 sessionStorage 中
window.sessionStorage.setItem('token', res.data.token)
// 2. 通过编程式导航跳转到后台主页,路由地址是 /home
this.$router.push('/home')
})
}
}
}
.login_container {
background-color: #2b4b6b;
height: 100%;
}
.login_box {
width: 450px;
height: 300px;
background-color: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.avatar_box {
height: 130px;
width: 130px;
border: 1px solid #eee;
border-radius: 50%;
padding: 10px;
box-shadow: 0 0 10px #ddd;
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
img {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #eee;
}
}
}
.login_form {
position: absolute;
bottom: 0;
width: 100%;
padding: 0 20px;
box-sizing: border-box;
}
.btns {
display: flex;
justify-content: flex-end;
}
菜单实现
管理页面有一个侧面的两级菜单,菜单的数据来自于后端,点击二级菜单会跳转到相应的子页面中。在el-menu中设置router属性,即可通过index添加到路由上进行跳转。
电商后台管理系统
{{item.authName}}
:key="subItem.id" @click="saveNavState('/' + subItem.path)"> {{subItem.authName}}
export default {
data() {
return {
// 左侧菜单数据
menulist: [],
iconsObj: {
'125': 'iconfont icon-user',
'103': 'iconfont icon-tijikongjian',
'101': 'iconfont icon-shangpin',
'102': 'iconfont icon-danju',
'145': 'iconfont icon-baobiao'
},
// 是否折叠
isCollapse: false,
// 被激活的链接地址
activePath: ''
}
},
created() {
this.getMenuList()
this.activePath = window.sessionStorage.getItem('activePath')
},
methods: {
logout() {
window.sessionStorage.clear()
this.$router.push('/login')
},
// 获取所有的菜单
async getMenuList() {
const { data: res } = await this.$http.get('menus')
if (res.meta.status !== 200) return this.$message.error(res.meta.msg)
this.menulist = res.data
console.log(res)
},
// 点击按钮,切换菜单的折叠与展开
toggleCollapse() {
this.isCollapse = !this.isCollapse
},
// 保存链接的激活状态
saveNavState(activePath) {
window.sessionStorage.setItem('activePath', activePath)
this.activePath = activePath
}
}
}
.home-container {
height: 100%;
}
.el-header {
background-color: #373d41;
display: flex;
justify-content: space-between;
padding-left: 0;
align-items: center;
color: #fff;
font-size: 20px;
> div {
display: flex;
align-items: center;
span {
margin-left: 15px;
}
}
}
.el-aside {
background-color: #333744;
.el-menu {
border-right: none;
}
}
.el-main {
background-color: #eaedf1;
}
.iconfont {
margin-right: 10px;
}
.toggle-button {
background-color: #4a5064;
font-size: 10px;
line-height: 24px;
color: #fff;
text-align: center;
letter-spacing: 0.2em;
cursor: pointer;
}
用户管理
用户列表
用户管理下有用户列表,这里渲染了后端的用户列表,可以编辑用户信息,删除用户,为用户分配角色,还可以对用户是否禁用进行管理;除此之外,还添加了查询用户,添加用户,和分页功能。
核心代码:
当前的用户:{{userInfo.username}}
当前的角色:{{userInfo.role_name}}
分配新角色:
export default {
data() {
// 验证邮箱的规则
var checkEmail = (rule, value, cb) => {
// 验证邮箱的正则表达式
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
if (regEmail.test(value)) {
// 合法的邮箱
return cb()
}
cb(new Error('请输入合法的邮箱'))
}
// 验证手机号的规则
var checkMobile = (rule, value, cb) => {
// 验证手机号的正则表达式
const regMobile = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
if (regMobile.test(value)) {
return cb()
}
cb(new Error('请输入合法的手机号'))
}
return {
// 获取用户列表的参数对象
queryInfo: {
query: '',
// 当前的页数
pagenum: 1,
// 当前每页显示多少条数据
pagesize: 2
},
userlist: [],
total: 0,
// 控制添加用户对话框的显示与隐藏
addDialogVisible: false,
// 添加用户的表单数据
addForm: {
username: '',
password: '',
email: '',
mobile: ''
},
// 添加表单的验证规则对象
addFormRules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{
min: 3,
max: 10,
message: '用户名的长度在3~10个字符之间',
trigger: 'blur'
}
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{
min: 6,
max: 15,
message: '用户名的长度在6~15个字符之间',
trigger: 'blur'
}
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ validator: checkEmail, trigger: 'blur' }
],
mobile: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ validator: checkMobile, trigger: 'blur' }
]
},
// 控制修改用户对话框的显示与隐藏
editDialogVisible: false,
// 查询到的用户信息对象
editForm: {},
// 修改表单的验证规则对象
editFormRules: {
email: [
{ required: true, message: '请输入用户邮箱', trigger: 'blur' },
{ validator: checkEmail, trigger: 'blur' }
],
mobile: [
{ required: true, message: '请输入用户手机', trigger: 'blur' },
{ validator: checkMobile, trigger: 'blur' }
]
},
// 控制分配角色对话框的显示与隐藏
setRoleDialogVisible: false,
// 需要被分配角色的用户信息
userInfo: {},
// 所有角色的数据列表
rolesList: [],
// 已选中的角色Id值
selectedRoleId: ''
}
},
created() {
this.getUserList()
},
methods: {
async getUserList() {
const { data: res } = await this.$http.get('users', {
params: this.queryInfo
})
if (res.meta.status !== 200) {
return this.$message.error('获取用户列表失败!')
}
this.userlist = res.data.users
this.total = res.data.total
console.log(res)
},
// 监听 pagesize 改变的事件
handleSizeChange(newSize) {
// console.log(newSize)
this.queryInfo.pagesize = newSize
this.getUserList()
},
// 监听 页码值 改变的事件
handleCurrentChange(newPage) {
console.log(newPage)
this.queryInfo.pagenum = newPage
this.getUserList()
},
// 监听 switch 开关状态的改变
async userStateChanged(userinfo) {
console.log(userinfo)
const { data: res } = await this.$http.put(
`users/${userinfo.id}/state/${userinfo.mg_state}`
)
if (res.meta.status !== 200) {
userinfo.mg_state = !userinfo.mg_state
return this.$message.error('更新用户状态失败!')
}
this.$message.success('更新用户状态成功!')
},
// 监听添加用户对话框的关闭事件
addDialogClosed() {
this.$refs.addFormRef.resetFields()
},
// 点击按钮,添加新用户
addUser() {
this.$refs.addFormRef.validate(async valid => {
if (!valid) return
// 可以发起添加用户的网络请求
const { data: res } = await this.$http.post('users', this.addForm)
if (res.meta.status !== 201) {
this.$message.error('添加用户失败!')
}
this.$message.success('添加用户成功!')
// 隐藏添加用户的对话框
this.addDialogVisible = false
// 重新获取用户列表数据
this.getUserList()
})
},
// 展示编辑用户的对话框
async showEditDialog(id) {
// console.log(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
},
// 监听修改用户对话框的关闭事件
editDialogClosed() {
this.$refs.editFormRef.resetFields()
},
// 修改用户信息并提交
editUserInfo() {
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.editDialogVisible = false
// 刷新数据列表
this.getUserList()
// 提示修改成功
this.$message.success('更新用户信息成功!')
})
},
// 根据Id删除对应的用户信息
async removeUserById(id) {
// 弹框询问用户是否删除数据
const confirmResult = await this.$confirm(
'此操作将永久删除该用户, 是否继续?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).catch(err => err)
// 如果用户确认删除,则返回值为字符串 confirm
// 如果用户取消了删除,则返回值为字符串 cancel
// console.log(confirmResult)
if (confirmResult !== 'confirm') {
return this.$message.info('已取消删除')
}
const { data: res } = await this.$http.delete('users/' + id)
if (res.meta.status !== 200) {
return this.$message.error('删除用户失败!')
}
this.$message.success('删除用户成功!')
this.getUserList()
},
// 展示分配角色的对话框
async setRole(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.setRoleDialogVisible = true
},
// 点击按钮,分配角色
async saveRoleInfo() {
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.setRoleDialogVisible = false
},
// 监听分配角色对话框的关闭事件
setRoleDialogClosed() {
this.selectedRoleId = ''
this.userInfo = {}
}
}
}
权限管理
角色列表
角色列表中可以创建新的角色,创建的新的角色可以在用户管理中赋予用户,同时可以为已有的角色赋予权限
export default {
data() {
return {
// 所有角色列表数据
rolelist: [],
// 控制分配权限对话框的显示与隐藏
setRightDialogVisible: false,
// 所有权限的数据
rightslist: [],
// 树形控件的属性绑定对象
treeProps: {
label: 'authName',
children: 'children'
},
// 默认选中的节点Id值数组
defKeys: [],
// 当前即将分配权限的角色id
roleId: ''
}
},
created() {
this.getRolesList()
},
methods: {
// 获取所有角色的列表
async getRolesList() {
const { data: res } = await this.$http.get('roles')
if (res.meta.status !== 200) {
return this.$message.error('获取角色列表失败!')
}
this.rolelist = res.data
console.log(this.rolelist)
},
// 根据Id删除对应的权限
async removeRightById(role, rightId) {
// 弹框提示用户是否要删除
const confirmResult = await this.$confirm(
'此操作将永久删除该文件, 是否继续?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).catch(err => err)
if (confirmResult !== 'confirm') {
return this.$message.info('取消了删除!')
}
const { data: res } = await this.$http.delete(
`roles/${role.id}/rights/${rightId}`
)
if (res.meta.status !== 200) {
return this.$message.error('删除权限失败!')
}
// this.getRolesList()
role.children = res.data
},
// 展示分配权限的对话框
async showSetRightDialog(role) {
this.roleId = role.id
// 获取所有权限的数据
const { data: res } = await this.$http.get('rights/tree')
if (res.meta.status !== 200) {
return this.$message.error('获取权限数据失败!')
}
// 把获取到的权限数据保存到 data 中
this.rightslist = res.data
console.log(this.rightslist)
// 递归获取三级节点的Id
this.getLeafKeys(role, this.defKeys)
this.setRightDialogVisible = true
},
// 通过递归的形式,获取角色下所有三级权限的id,并保存到 defKeys 数组中
getLeafKeys(node, arr) {
// 如果当前 node 节点不包含 children 属性,则是三级节点
if (!node.children) {
return arr.push(node.id)
}
node.children.forEach(item => this.getLeafKeys(item, arr))
},
// 监听分配权限对话框的关闭事件
setRightDialogClosed() {
this.defKeys = []
},
// 点击为角色分配权限
async allotRights() {
const keys = [
...this.$refs.treeRef.getCheckedKeys(),
...this.$refs.treeRef.getHalfCheckedKeys()
]
const idStr = keys.join(',')
const { data: res } = await this.$http.post(
`roles/${this.roleId}/rights`,
{ rids: idStr }
)
if (res.meta.status !== 200) {
return this.$message.error('分配权限失败!')
}
this.$message.success('分配权限成功!')
this.getRolesList()
this.setRightDialogVisible = false
}
}
}
.el-tag {
margin: 7px;
}
.bdtop {
border-top: 1px solid #eee;
}
.bdbottom {
border-bottom: 1px solid #eee;
}
.vcenter {
display: flex;
align-items: center;
}
权限列表
权限列表对不同的权限做出展示,只发送一个请求即可获取所有需要的数据
export default {
data() {
return {
// 权限列表
rightsList: []
}
},
created() {
// 获取所有的权限
this.getRightsList()
},
methods: {
// 获取权限列表
async getRightsList() {
const { data: res } = await this.$http.get('rights/list')
if (res.meta.status !== 200) {
return this.$message.error('获取权限列表失败!')
}
this.rightsList = res.data
console.log(this.rightsList)
}
}
}
商品管理
商品分类
export default {
data() {
return {
// 查询条件
querInfo: {
type: 3,
pagenum: 1,
pagesize: 5
},
// 商品分类的数据列表,默认为空
catelist: [],
// 总数据条数
total: 0,
// 为table指定列的定义
columns: [
{
label: '分类名称',
prop: 'cat_name'
},
{
label: '是否有效',
// 表示,将当前列定义为模板列
type: 'template',
// 表示当前这一列使用模板名称
template: 'isok'
},
{
label: '排序',
// 表示,将当前列定义为模板列
type: 'template',
// 表示当前这一列使用模板名称
template: 'order'
},
{
label: '操作',
// 表示,将当前列定义为模板列
type: 'template',
// 表示当前这一列使用模板名称
template: 'opt'
}
],
// 控制添加分类对话框的显示与隐藏
addCateDialogVisible: false,
// 添加分类的表单数据对象
addCateForm: {
// 将要添加的分类的名称
cat_name: '',
// 父级分类的Id
cat_pid: 0,
// 分类的等级,默认要添加的是1级分类
cat_level: 0
},
// 添加分类表单的验证规则对象
addCateFormRules: {
cat_name: [{ required: true, message: '请输入分类名称', trigger: 'blur' }]
},
// 父级分类的列表
parentCateList: [],
// 指定级联选择器的配置对象
cascaderProps: {
value: 'cat_id',
label: 'cat_name',
children: 'children'
},
// 选中的父级分类的Id数组
selectedKeys: []
}
},
created() {
this.getCateList()
},
methods: {
// 获取商品分类数据
async getCateList() {
const { data: res } = await this.$http.get('categories', {
params: this.querInfo
})
if (res.meta.status !== 200) {
return this.$message.error('获取商品分类失败!')
}
console.log(res.data)
// 把数据列表,赋值给 catelist
this.catelist = res.data.result
// 为总数据条数赋值
this.total = res.data.total
},
// 监听 pagesize 改变
handleSizeChange(newSize) {
this.querInfo.pagesize = newSize
this.getCateList()
},
// 监听 pagenum 改变
handleCurrentChange(newPage) {
this.querInfo.pagenum = newPage
this.getCateList()
},
// 点击按钮,展示添加分类的对话框
showAddCateDialog() {
// 先获取父级分类的数据列表
this.getParentCateList()
// 再展示出对话框
this.addCateDialogVisible = true
},
// 获取父级分类的数据列表
async getParentCateList() {
const { data: res } = await this.$http.get('categories', {
params: { type: 2 }
})
if (res.meta.status !== 200) {
return this.$message.error('获取父级分类数据失败!')
}
console.log(res.data)
this.parentCateList = res.data
},
// 选择项发生变化触发这个函数
parentCateChanged() {
console.log(this.selectedKeys)
// 如果 selectedKeys 数组中的 length 大于0,证明选中的父级分类
// 反之,就说明没有选中任何父级分类
if (this.selectedKeys.length > 0) {
// 父级分类的Id
this.addCateForm.cat_pid = this.selectedKeys[this.selectedKeys.length - 1]
// 为当前分类的等级赋值
this.addCateForm.cat_level = this.selectedKeys.length
} else {
// 父级分类的Id
this.addCateForm.cat_pid = 0
// 为当前分类的等级赋值
this.addCateForm.cat_level = 0
}
},
// 点击按钮,添加新的分类
addCate() {
this.$refs.addCateFormRef.validate(async valid => {
if (!valid) return
const { data: res } = await this.$http.post('categories', this.addCateForm)
if (res.meta.status !== 201) {
return this.$message.error('添加分类失败!')
}
this.$message.success('添加分类成功!')
this.getCateList()
this.addCateDialogVisible = false
})
},
// 监听对话框的关闭事件,重置表单数据
addCateDialogClosed() {
this.$refs.addCateFormRef.resetFields()
this.selectedKeys = []
this.addCateForm.cat_level = 0
this.addCateForm.cat_pid = 0
}
}
}
.treeTable {
margin-top: 15px;
}
.el-cascader {
width: 100%;
}
商品列表
{{scope.row.add_time | dateFormat}}
export default {
data() {
return {
// 查询参数对象
queryInfo: {
query: '',
pagenum: 1,
pagesize: 10
},
// 商品列表
goodslist: [],
// 总数据条数
total: 0
}
},
created() {
this.getGoodsList()
},
methods: {
// 根据分页获取对应的商品列表
async getGoodsList() {
const { data: res } = await this.$http.get('goods', {
params: this.queryInfo
})
if (res.meta.status !== 200) {
return this.$message.error('获取商品列表失败!')
}
this.$message.success('获取商品列表成功!')
console.log(res.data)
this.goodslist = res.data.goods
this.total = res.data.total
},
handleSizeChange(newSize) {
this.queryInfo.pagesize = newSize
this.getGoodsList()
},
handleCurrentChange(newPage) {
this.queryInfo.pagenum = newPage
this.getGoodsList()
},
async removeById(id) {
const confirmResult = await this.$confirm(
'此操作将永久删除该商品, 是否继续?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).catch(err => err)
if (confirmResult !== 'confirm') {
return this.$message.info('已经取消删除!')
}
const { data: res } = await this.$http.delete(`goods/${id}`)
if (res.meta.status !== 200) {
return this.$message.error('删除失败!')
}
this.$message.success('删除成功!')
this.getGoodsList()
},
goAddpage() {
this.$router.push('/goods/add')
}
}
}
增加商品
在商品分类中点击新增商品,则跳转到新增商品窗口
import _ from 'lodash'
export default {
data() {
return {
activeIndex: '0',
// 添加商品的表单数据对象
addForm: {
goods_name: '',
goods_price: 0,
goods_weight: 0,
goods_number: 0,
// 商品所属的分类数组
goods_cat: [],
// 图片的数组
pics: [],
// 商品的详情描述
goods_introduce: '',
attrs: []
},
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' }
]
},
// 商品分类列表
catelist: [],
cateProps: {
label: 'cat_name',
value: 'cat_id',
children: 'children'
},
// 动态参数列表数据
manyTableData: [],
// 静态属性列表数据
onlyTableData: [],
// 上传图片的URL地址
uploadURL: 'http://127.0.0.1:8888/api/private/v1/upload',
// 图片上传组件的headers请求头对象
headerObj: {
Authorization: window.sessionStorage.getItem('token')
},
previewPath: '',
previewVisible: false
}
},
created() {
this.getCateList()
},
methods: {
// 获取所有商品分类数据
async getCateList() {
const { data: res } = await this.$http.get('categories')
if (res.meta.status !== 200) {
return this.$message.error('获取商品分类数据失败!')
}
this.catelist = res.data
console.log(this.catelist)
},
// 级联选择器选中项变化,会触发这个函数
handleChange() {
console.log(this.addForm.goods_cat)
if (this.addForm.goods_cat.length !== 3) {
this.addForm.goods_cat = []
}
},
beforeTabLeave(activeName, oldActiveName) {
// console.log('即将离开的标签页名字是:' + oldActiveName)
// console.log('即将进入的标签页名字是:' + activeName)
// return false
if (oldActiveName === '0' && this.addForm.goods_cat.length !== 3) {
this.$message.error('请先选择商品分类!')
return false
}
},
async tabClicked() {
// console.log(this.activeIndex)
// 证明访问的是动态参数面板
if (this.activeIndex === '1') {
const { data: res } = await this.$http.get(
`categories/${this.cateId}/attributes`,
{
params: { sel: 'many' }
}
)
if (res.meta.status !== 200) {
return this.$message.error('获取动态参数列表失败!')
}
console.log(res.data)
res.data.forEach(item => {
item.attr_vals =
item.attr_vals.length === 0 ? [] : item.attr_vals.split(' ')
})
this.manyTableData = res.data
} else if (this.activeIndex === '2') {
const { data: res } = await this.$http.get(
`categories/${this.cateId}/attributes`,
{
params: { sel: 'only' }
}
)
if (res.meta.status !== 200) {
return this.$message.error('获取静态属性失败!')
}
console.log(res.data)
this.onlyTableData = res.data
}
},
// 处理图片预览效果
handlePreview(file) {
console.log(file)
this.previewPath = file.response.data.url
this.previewVisible = true
},
// 处理移除图片的操作
handleRemove(file) {
// console.log(file)
// 1. 获取将要删除的图片的临时路径
const filePath = file.response.data.tmp_path
// 2. 从 pics 数组中,找到这个图片对应的索引值
const i = this.addForm.pics.findIndex(x => x.pic === filePath)
// 3. 调用数组的 splice 方法,把图片信息对象,从 pics 数组中移除
this.addForm.pics.splice(i, 1)
console.log(this.addForm)
},
// 监听图片上传成功的事件
handleSuccess(response) {
console.log(response)
// 1. 拼接得到一个图片信息对象
const picInfo = { pic: response.data.tmp_path }
// 2. 将图片信息对象,push 到pics数组中
this.addForm.pics.push(picInfo)
console.log(this.addForm)
},
// 添加商品
add() {
this.$refs.addFormRef.validate(async valid => {
if (!valid) {
return this.$message.error('请填写必要的表单项!')
}
// 执行添加的业务逻辑
// lodash cloneDeep(obj)
const form = _.cloneDeep(this.addForm)
form.goods_cat = form.goods_cat.join(',')
// 处理动态参数
this.manyTableData.forEach(item => {
const newInfo = {
attr_id: item.attr_id,
attr_value: item.attr_vals.join(' ')
}
this.addForm.attrs.push(newInfo)
})
// 处理静态属性
this.onlyTableData.forEach(item => {
const newInfo = { attr_id: item.attr_id, attr_value: item.attr_vals }
this.addForm.attrs.push(newInfo)
})
form.attrs = this.addForm.attrs
console.log(form)
// 发起请求添加商品
// 商品的名称,必须是唯一的
const { data: res } = await this.$http.post('goods', form)
if (res.meta.status !== 201) {
return this.$message.error('添加商品失败!')
}
this.$message.success('添加商品成功!')
this.$router.push('/goods')
})
}
},
computed: {
cateId() {
if (this.addForm.goods_cat.length === 3) {
return this.addForm.goods_cat[2]
}
return null
}
}
}
.el-checkbox {
margin: 0 10px 0 0 !important;
}
.previewImg {
width: 100%;
}
.btnAdd {
margin-top: 15px;
}
分类参数
在分类参数中选择一件商品,可以为其添加静态或者动态参数,这个参数可以展示在移动端商品的属性中。
选择商品分类:
export default {
data() {
return {
// 商品分类列表
catelist: [],
// 级联选择框的配置对象
cateProps: {
value: 'cat_id',
label: 'cat_name',
children: 'children'
},
// 级联选择框双向绑定到的数组
selectedCateKeys: [],
// 被激活的页签的名称
activeName: 'many',
// 动态参数的数据
manyTableData: [],
// 静态属性的数据
onlyTableData: [],
// 控制添加对话框的显示与隐藏
addDialogVisible: false,
// 添加参数的表单数据对象
addForm: {
attr_name: ''
},
// 添加表单的验证规则对象
addFormRules: {
attr_name: [
{ required: true, message: '请输入参数名称', trigger: 'blur' }
]
},
// 控制修改对话框的显示与隐藏
editDialogVisible: false,
// 修改的表单数据对象
editForm: {},
// 修改表单的验证规则对象
editFormRules: {
attr_name: [
{ required: true, message: '请输入参数名称', trigger: 'blur' }
]
}
}
},
created() {
this.getCateList()
},
methods: {
// 获取所有的商品分类列表
async getCateList() {
const { data: res } = await this.$http.get('categories')
if (res.meta.status !== 200) {
return this.$message.error('获取商品分类失败!')
}
this.catelist = res.data
console.log(this.catelist)
},
// 级联选择框选中项变化,会触发这个函数
handleChange() {
this.getParamsData()
},
// tab 页签点击事件的处理函数
handleTabClick() {
console.log(this.activeName)
this.getParamsData()
},
// 获取参数的列表数据
async getParamsData() {
// 证明选中的不是三级分类
if (this.selectedCateKeys.length !== 3) {
this.selectedCateKeys = []
this.manyTableData = []
this.onlyTableData = []
return
}
// 证明选中的是三级分类
console.log(this.selectedCateKeys)
// 根据所选分类的Id,和当前所处的面板,获取对应的参数
const { data: res } = await this.$http.get(
`categories/${this.cateId}/attributes`,
{
params: { sel: this.activeName }
}
)
if (res.meta.status !== 200) {
return this.$message.error('获取参数列表失败!')
}
res.data.forEach(item => {
item.attr_vals = item.attr_vals ? item.attr_vals.split(' ') : []
// 控制文本框的显示与隐藏
item.inputVisible = false
// 文本框中输入的值
item.inputValue = ''
})
console.log(res.data)
if (this.activeName === 'many') {
this.manyTableData = res.data
} else {
this.onlyTableData = res.data
}
},
// 监听添加对话框的关闭事件
addDialogClosed() {
this.$refs.addFormRef.resetFields()
},
// 点击按钮,添加参数
addParams() {
this.$refs.addFormRef.validate(async valid => {
if (!valid) return
const { data: res } = await this.$http.post(
`categories/${this.cateId}/attributes`,
{
attr_name: this.addForm.attr_name,
attr_sel: this.activeName
}
)
if (res.meta.status !== 201) {
return this.$message.error('添加参数失败!')
}
this.$message.success('添加参数成功!')
this.addDialogVisible = false
this.getParamsData()
})
},
// 点击按钮,展示修改的对话框
async showEditDialog(attrId) {
// 查询当前参数的信息
const { data: res } = await this.$http.get(
`categories/${this.cateId}/attributes/${attrId}`,
{
params: { attr_sel: this.activeName }
}
)
if (res.meta.status !== 200) {
return this.$message.error('获取参数信息失败!')
}
this.editForm = res.data
this.editDialogVisible = true
},
// 重置修改的表单
editDialogClosed() {
this.$refs.editFormRef.resetFields()
},
// 点击按钮,修改参数信息
editParams() {
this.$refs.editFormRef.validate(async valid => {
if (!valid) return
const { data: res } = await this.$http.put(
`categories/${this.cateId}/attributes/${this.editForm.attr_id}`,
{ attr_name: this.editForm.attr_name, attr_sel: this.activeName }
)
if (res.meta.status !== 200) {
return this.$message.error('修改参数失败!')
}
this.$message.success('修改参数成功!')
this.getParamsData()
this.editDialogVisible = false
})
},
// 根据Id删除对应的参数项
async removeParams(attrId) {
const confirmResult = await this.$confirm(
'此操作将永久删除该参数, 是否继续?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).catch(err => err)
// 用户取消了删除的操作
if (confirmResult !== 'confirm') {
return this.$message.info('已取消删除!')
}
// 删除的业务逻辑
const { data: res } = await this.$http.delete(
`categories/${this.cateId}/attributes/${attrId}`
)
if (res.meta.status !== 200) {
return this.$message.error('删除参数失败!')
}
this.$message.success('删除参数成功!')
this.getParamsData()
},
// 文本框失去焦点,或摁下了 Enter 都会触发
async handleInputConfirm(row) {
if (row.inputValue.trim().length === 0) {
row.inputValue = ''
row.inputVisible = false
return
}
// 如果没有return,则证明输入的内容,需要做后续处理
row.attr_vals.push(row.inputValue.trim())
row.inputValue = ''
row.inputVisible = false
// 需要发起请求,保存这次操作
this.saveAttrVals(row)
},
// 将对 attr_vals 的操作,保存到数据库
async saveAttrVals(row) {
// 需要发起请求,保存这次操作
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('修改参数项成功!')
},
// 点击按钮,展示文本输入框
showInput(row) {
row.inputVisible = true
// 让文本框自动获得焦点
// $nextTick 方法的作用,就是当页面上元素被重新渲染之后,才会指定回调函数中的代码
this.$nextTick(_ => {
this.$refs.saveTagInput.$refs.input.focus()
})
},
// 删除对应的参数可选项
handleClose(i, row) {
row.attr_vals.splice(i, 1)
this.saveAttrVals(row)
}
},
computed: {
// 如果按钮需要被禁用,则返回true,否则返回false
isBtnDisabled() {
if (this.selectedCateKeys.length !== 3) {
return true
}
return false
},
// 当前选中的三级分类的Id
cateId() {
if (this.selectedCateKeys.length === 3) {
return this.selectedCateKeys[2]
}
return null
},
// 动态计算标题的文本
titleText() {
if (this.activeName === 'many') {
return '动态参数'
}
return '静态属性'
}
}
}
.cat_opt {
margin: 15px 0;
}
.el-tag {
margin: 10px;
}
.input-new-tag {
width: 120px;
}
订单管理
订单列表
订单管理的实现和用户管理有很多类似的地方,都是向后端发送请求然后渲染到页面上
{{scope.row.is_send}}
{{scope.row.create_time | dateFormat}}
{{activity.context}}
import cityData from './citydata.js'
export default {
data() {
return {
queryInfo: {
query: '',
pagenum: 1,
pagesize: 10
},
total: 0,
orderlist: [],
addressVisible: false,
addressForm: {
address1: [],
address2: ''
},
addressFormRules: {
address1: [
{ required: true, message: '请选择省市区县', trigger: 'blur' }
],
address2: [
{ required: true, message: '请填写详细地址', trigger: 'blur' }
]
},
cityData,
progressVisible: false,
progressInfo: []
}
},
created() {
this.getOrderList()
},
methods: {
async getOrderList() {
const { data: res } = await this.$http.get('orders', {
params: this.queryInfo
})
if (res.meta.status !== 200) {
return this.$message.error('获取订单列表失败!')
}
console.log(res)
this.total = res.data.total
this.orderlist = res.data.goods
},
handleSizeChange(newSize) {
this.queryInfo.pagesize = newSize
this.getOrderList()
},
handleCurrentChange(newPage) {
this.queryInfo.pagenum = newPage
this.getOrderList()
},
// 展示修改地址的对话框
showBox() {
this.addressVisible = true
},
addressDialogClosed() {
this.$refs.addressFormRef.resetFields()
},
async showProgressBox() {
const { data: res } = await this.$http.get('/kuaidi/804909574412544580')
if (res.meta.status !== 200) {
return this.$message.error('获取物流进度失败!')
}
this.progressInfo = res.data
this.progressVisible = true
console.log(this.progressInfo)
}
}
}
@import '../../plugins/timeline/timeline.css';
@import '../../plugins/timeline-item/timeline-item.css';
.el-cascader {
width: 100%;
}
数据统计
数据报表
数据统计部分用到了echarts,从后端获得数据后通过 _.merge()将数据组合在一起,最后渲染在页面上
// 1. 导入 echarts
import echarts from 'echarts'
import _ from 'lodash'
export default {
data() {
return {
// 需要合并的数据
options: {
title: {
text: '用户来源'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#E9EEF3'
}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
boundaryGap: false
}
],
yAxis: [
{
type: 'value'
}
]
}
}
},
created() {},
// 此时,页面上的元素,已经被渲染完毕了!
async mounted() {
// 3. 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'))
const { data: res } = await this.$http.get('reports/type/1')
if (res.meta.status !== 200) {
return this.$message.error('获取折线图数据失败!')
}
// 4. 准备数据和配置项
const result = _.merge(res.data, this.options)
// 5. 展示数据
myChart.setOption(result)
},
methods: {}
}
项目git地址
目录中有后端以及sql文件,按照说明运行即可
电商系统前端: 电商管理系统前端
学习资源
黑马程序员前端
推荐链接
发表评论