位置: IT常识 - 正文

vue项目实战-电商后台管理系统(vue实战开发项目视频)

编辑:rootadmin
vue项目实战-电商后台管理系统 项目简介:

推荐整理分享vue项目实战-电商后台管理系统(vue实战开发项目视频),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:最全vue项目实战,vue实例完整项目源码,vue实战开发项目视频,vuejs项目,vuecli项目实战,vue项目实战教程,vuecli项目实战,vue项目实战教程,内容如对您有帮助,希望把文章链接给更多的朋友!

该项目为电商后台的管理系统。设计了登录页面。

管理人员需要通过输入正确的用户名和密码才能登录。登陆成功之后进入管理页面:

管理页面由五个子模块组成:用户管理,权限管理,商品管理,订单管理,数据统计;

每个子模块有若干子模块组成,用户管理下->用户列表,权限管理->角色列表,权限管理,商品管理->商品列表,分类参数,商品分配,订单管理->订单列表,数据统计->数据报表

登录页面

登录页面中对用户输入的内容进行预校验,如果不符合要求则,则不向后端发送请求,同事挂载路由守卫,防止强制跳转。同时设置令牌校验,避免重复登录。如果用户输入格式正确的用户名以及密码时,向后端发送请求,请求通过则跳转到管理页面,否则返回登录页面。

路由导航守卫:

// 挂载路由导航守卫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()})

登录页面核心代码:

<template> <div class="login_container"> <div class="login_box"> <!-- 头像区域 --> <div class="avatar_box"> <img src="../assets/logo.png" alt=""> </div> <!-- 登录表单区域 --> <el-form ref="loginFormRef" :model="loginForm" :rules="loginFormRules" label-width="0px" class="login_form"> <!-- 用户名 --> <el-form-item prop="username"> <el-input v-model="loginForm.username" prefix-icon="iconfont icon-user"></el-input> </el-form-item> <!-- 密码 --> <el-form-item prop="password"> <el-input v-model="loginForm.password" prefix-icon="iconfont icon-3702mima" type="password"></el-input> </el-form-item> <!-- 按钮区域 --> <el-form-item class="btns"> <el-button type="primary" @click="login">登录</el-button> <el-button type="info" @click="resetLoginForm">重置</el-button> </el-form-item> </el-form> </div> </div></template><script>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') }) } }}</script><style lang="less" scoped>.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;}</style>菜单实现

管理页面有一个侧面的两级菜单,菜单的数据来自于后端,点击二级菜单会跳转到相应的子页面中。在el-menu中设置router属性,即可通过index添加到路由上进行跳转。

<template> <el-container class="home-container"> <!-- 头部区域 --> <el-header> <div> <img src="../assets/heima.png" alt=""> <span>电商后台管理系统</span> </div> <el-button type="info" @click="logout">退出</el-button> </el-header> <!-- 页面主体区域 --> <el-container> <!-- 侧边栏 --> <el-aside :width="isCollapse ? '64px' : '200px'"> <div class="toggle-button" @click="toggleCollapse">|||</div> <!-- 侧边栏菜单区域 --> <el-menu background-color="#333744" text-color="#fff" active-text-color="#409EFF" unique-opened :collapse="isCollapse" :collapse-transition="false" router :default-active="activePath"> <!-- 一级菜单 --> <el-submenu :index="item.id + ''" v-for="item in menulist" :key="item.id"> <!-- 一级菜单的模板区域 --> <template slot="title"> <!-- 图标 --> <i :class="iconsObj[item.id]"></i> <!-- 文本 --> <span>{{item.authName}}</span> </template> <!-- 二级菜单 --> <el-menu-item :index="'/' + subItem.path" v-for="subItem in item.children" :key="subItem.id" @click="saveNavState('/' + subItem.path)"> <template slot="title"> <!-- 图标 --> <i class="el-icon-menu"></i> <!-- 文本 --> <span>{{subItem.authName}}</span> </template> </el-menu-item> </el-submenu> </el-menu> </el-aside> <!-- 右侧内容主体 --> <el-main> <!-- 路由占位符 --> <router-view></router-view> </el-main> </el-container> </el-container></template><script>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 } }}</script><style lang="less" scoped>.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;}</style>用户管理用户列表vue项目实战-电商后台管理系统(vue实战开发项目视频)

用户管理下有用户列表,这里渲染了后端的用户列表,可以编辑用户信息,删除用户,为用户分配角色,还可以对用户是否禁用进行管理;除此之外,还添加了查询用户,添加用户,和分页功能。

核心代码:

<template> <div> <!-- 面包屑导航区域 --> <el-breadcrumb separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item> <el-breadcrumb-item>用户管理</el-breadcrumb-item> <el-breadcrumb-item>用户列表</el-breadcrumb-item> </el-breadcrumb> <!-- 卡片视图区域 --> <el-card> <!-- 搜索与添加区域 --> <el-row :gutter="20"> <el-col :span="8"> <el-input placeholder="请输入内容" v-model="queryInfo.query" clearable @clear="getUserList"> <el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button> </el-input> </el-col> <el-col :span="4"> <el-button type="primary" @click="addDialogVisible = true">添加用户</el-button> </el-col> </el-row> <!-- 用户列表区域 --> <el-table :data="userlist" border stripe> <el-table-column type="index"></el-table-column> <el-table-column label="姓名" prop="username"></el-table-column> <el-table-column label="邮箱" prop="email"></el-table-column> <el-table-column label="电话" prop="mobile"></el-table-column> <el-table-column label="角色" prop="role_name"></el-table-column> <el-table-column label="状态"> <template slot-scope="scope"> <el-switch v-model="scope.row.mg_state" @change="userStateChanged(scope.row)"> </el-switch> </template> </el-table-column> <el-table-column label="操作" width="180px"> <template slot-scope="scope"> <!-- 修改按钮 --> <el-button type="primary" icon="el-icon-edit" size="mini" @click="showEditDialog(scope.row.id)"></el-button> <!-- 删除按钮 --> <el-button type="danger" icon="el-icon-delete" size="mini" @click="removeUserById(scope.row.id)"></el-button> <!-- 分配角色按钮 --> <el-tooltip effect="dark" content="分配角色" placement="top" :enterable="false"> <el-button type="warning" icon="el-icon-setting" size="mini" @click="setRole(scope.row)"></el-button> </el-tooltip> </template> </el-table-column> </el-table> <!-- 分页区域 --> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[1, 2, 5, 10]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total"> </el-pagination> </el-card> <!-- 添加用户的对话框 --> <el-dialog title="添加用户" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed"> <!-- 内容主体区域 --> <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="70px"> <el-form-item label="用户名" prop="username"> <el-input v-model="addForm.username"></el-input> </el-form-item> <el-form-item label="密码" prop="password"> <el-input v-model="addForm.password"></el-input> </el-form-item> <el-form-item label="邮箱" prop="email"> <el-input v-model="addForm.email"></el-input> </el-form-item> <el-form-item label="手机" prop="mobile"> <el-input v-model="addForm.mobile"></el-input> </el-form-item> </el-form> <!-- 底部区域 --> <span slot="footer" class="dialog-footer"> <el-button @click="addDialogVisible = false">取 消</el-button> <el-button type="primary" @click="addUser">确 定</el-button> </span> </el-dialog> <!-- 修改用户的对话框 --> <el-dialog title="修改用户" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed"> <el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px"> <el-form-item label="用户名"> <el-input v-model="editForm.username" disabled></el-input> </el-form-item> <el-form-item label="邮箱" prop="email"> <el-input v-model="editForm.email"></el-input> </el-form-item> <el-form-item label="手机" prop="mobile"> <el-input v-model="editForm.mobile"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="editDialogVisible = false">取 消</el-button> <el-button type="primary" @click="editUserInfo">确 定</el-button> </span> </el-dialog> <!-- 分配角色的对话框 --> <el-dialog title="分配角色" :visible.sync="setRoleDialogVisible" width="50%" @close="setRoleDialogClosed"> <div> <p>当前的用户:{{userInfo.username}}</p> <p>当前的角色:{{userInfo.role_name}}</p> <p>分配新角色: <el-select v-model="selectedRoleId" placeholder="请选择"> <el-option v-for="item in rolesList" :key="item.id" :label="item.roleName" :value="item.id"> </el-option> </el-select> </p> </div> <span slot="footer" class="dialog-footer"> <el-button @click="setRoleDialogVisible = false">取 消</el-button> <el-button type="primary" @click="saveRoleInfo">确 定</el-button> </span> </el-dialog> </div></template><script>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 = {} } }}</script><style lang="less" scoped></style>权限管理角色列表

角色列表中可以创建新的角色,创建的新的角色可以在用户管理中赋予用户,同时可以为已有的角色赋予权限

<template> <div> <!-- 面包屑导航区域 --> <el-breadcrumb separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item> <el-breadcrumb-item>权限管理</el-breadcrumb-item> <el-breadcrumb-item>角色列表</el-breadcrumb-item> </el-breadcrumb> <!-- 卡片视图 --> <el-card> <!-- 添加角色按钮区域 --> <el-row> <el-col> <el-button type="primary">添加角色</el-button> </el-col> </el-row> <!-- 角色列表区域 --> <el-table :data="rolelist" border stripe> <!-- 展开列 --> <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"> <!-- 通过 for 循环 嵌套渲染二级权限 --> <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> <!-- <pre> {{scope.row}} </pre> --> </template> </el-table-column> <!-- 索引列 --> <el-table-column type="index"></el-table-column> <el-table-column label="角色名称" prop="roleName"></el-table-column> <el-table-column label="角色描述" prop="roleDesc"></el-table-column> <el-table-column label="操作" width="300px"> <template slot-scope="scope"> <el-button size="mini" type="primary" icon="el-icon-edit">编辑</el-button> <el-button size="mini" type="danger" icon="el-icon-delete">删除</el-button> <el-button size="mini" type="warning" icon="el-icon-setting" @click="showSetRightDialog(scope.row)">分配权限</el-button> </template> </el-table-column> </el-table> </el-card> <!-- 分配权限的对话框 --> <el-dialog title="分配权限" :visible.sync="setRightDialogVisible" width="50%" @close="setRightDialogClosed"> <!-- 树形控件 --> <el-tree :data="rightslist" :props="treeProps" show-checkbox node-key="id" default-expand-all :default-checked-keys="defKeys" ref="treeRef"></el-tree> <span slot="footer" class="dialog-footer"> <el-button @click="setRightDialogVisible = false">取 消</el-button> <el-button type="primary" @click="allotRights">确 定</el-button> </span> </el-dialog> </div></template><script>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 } }}</script><style lang="less" scoped>.el-tag { margin: 7px;}.bdtop { border-top: 1px solid #eee;}.bdbottom { border-bottom: 1px solid #eee;}.vcenter { display: flex; align-items: center;}</style>权限列表

权限列表对不同的权限做出展示,只发送一个请求即可获取所有需要的数据

<template> <div> <!-- 面包屑导航区域 --> <el-breadcrumb separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item> <el-breadcrumb-item>权限管理</el-breadcrumb-item> <el-breadcrumb-item>权限列表</el-breadcrumb-item> </el-breadcrumb> <!-- 卡片视图 --> <el-card> <el-table :data="rightsList" border stripe> <el-table-column type="index"></el-table-column> <el-table-column label="权限名称" prop="authName"></el-table-column> <el-table-column label="路径" prop="path"></el-table-column> <el-table-column label="权限等级" prop="level"> <template slot-scope="scope"> <el-tag v-if="scope.row.level === '0'">一级</el-tag> <el-tag type="success" v-else-if="scope.row.level === '1'">二级</el-tag> <el-tag type="warning" v-else>三级</el-tag> </template> </el-table-column> </el-table> </el-card> </div></template><script>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) } }}</script><style lang="less" scoped></style>商品管理商品分类<template> <div> <!-- 面包屑导航区域 --> <el-breadcrumb separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item> <el-breadcrumb-item>商品管理</el-breadcrumb-item> <el-breadcrumb-item>商品分类</el-breadcrumb-item> </el-breadcrumb> <!-- 卡片视图区域 --> <el-card> <el-row> <el-col> <el-button type="primary" @click="showAddCateDialog">添加分类</el-button> </el-col> </el-row> <!-- 表格 --> <tree-table class="treeTable" :data="catelist" :columns="columns" :selection-type="false" :expand-type="false" show-index index-text="#" border :show-row-hover="false"> <!-- 是否有效 --> <template slot="isok" slot-scope="scope"> <i class="el-icon-success" v-if="scope.row.cat_deleted === false" style="color: lightgreen;"></i> <i class="el-icon-error" v-else style="color: red;"></i> </template> <!-- 排序 --> <template slot="order" slot-scope="scope"> <el-tag size="mini" v-if="scope.row.cat_level===0">一级</el-tag> <el-tag type="success" size="mini" v-else-if="scope.row.cat_level===1">二级</el-tag> <el-tag type="warning" size="mini" v-else>三级</el-tag> </template> <!-- 操作 --> <template slot="opt"> <el-button type="primary" icon="el-icon-edit" size="mini">编辑</el-button> <el-button type="danger" icon="el-icon-delete" size="mini">删除</el-button> </template> </tree-table> <!-- 分页区域 --> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="querInfo.pagenum" :page-sizes="[3, 5, 10, 15]" :page-size="querInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total"> </el-pagination> </el-card> <!-- 添加分类的对话框 --> <el-dialog title="添加分类" :visible.sync="addCateDialogVisible" width="50%" @close="addCateDialogClosed"> <!-- 添加分类的表单 --> <el-form :model="addCateForm" :rules="addCateFormRules" ref="addCateFormRef" label-width="100px"> <el-form-item label="分类名称:" prop="cat_name"> <el-input v-model="addCateForm.cat_name"></el-input> </el-form-item> <el-form-item label="父级分类:"> <!-- options 用来指定数据源 --> <!-- props 用来指定配置对象 --> <el-cascader expand-trigger="hover" :options="parentCateList" :props="cascaderProps" v-model="selectedKeys" @change="parentCateChanged" clearable change-on-select> </el-cascader> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="addCateDialogVisible = false">取 消</el-button> <el-button type="primary" @click="addCate">确 定</el-button> </span> </el-dialog> </div></template><script>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 } }}</script><style lang="less" scoped>.treeTable { margin-top: 15px;}.el-cascader { width: 100%;}</style>商品列表<template> <div> <!-- 面包屑导航区域 --> <el-breadcrumb separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item> <el-breadcrumb-item>商品管理</el-breadcrumb-item> <el-breadcrumb-item>商品列表</el-breadcrumb-item> </el-breadcrumb> <!-- 卡片视图区域 --> <el-card> <el-row :gutter="20"> <el-col :span="8"> <el-input placeholder="请输入内容" v-model="queryInfo.query" clearable @clear="getGoodsList"> <el-button slot="append" icon="el-icon-search" @click="getGoodsList"></el-button> </el-input> </el-col> <el-col :span="4"> <el-button type="primary" @click="goAddpage">添加商品</el-button> </el-col> </el-row> <!-- table表格区域 --> <el-table :data="goodslist" border stripe> <el-table-column type="index"></el-table-column> <el-table-column label="商品名称" prop="goods_name"></el-table-column> <el-table-column label="商品价格(元)" prop="goods_price" width="95px"></el-table-column> <el-table-column label="商品重量" prop="goods_weight" width="70px"></el-table-column> <el-table-column label="创建时间" prop="add_time" width="140px"> <template slot-scope="scope"> {{scope.row.add_time | dateFormat}} </template> </el-table-column> <el-table-column label="操作" width="130px"> <template slot-scope="scope"> <el-button type="primary" icon="el-icon-edit" size="mini"></el-button> <el-button type="danger" icon="el-icon-delete" size="mini" @click="removeById(scope.row.goods_id)"></el-button> </template> </el-table-column> </el-table> <!-- 分页区域 --> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[5, 10, 15, 20]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total" background> </el-pagination> </el-card> </div></template><script>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') } }}</script><style lang="less" scoped></style>增加商品

在商品分类中点击新增商品,则跳转到新增商品窗口

<template> <div> <!-- 面包屑导航区域 --> <el-breadcrumb separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item> <el-breadcrumb-item>商品管理</el-breadcrumb-item> <el-breadcrumb-item>添加商品</el-breadcrumb-item> </el-breadcrumb> <!-- 卡片视图 --> <el-card> <!-- 提示区域 --> <el-alert title="添加商品信息" type="info" center show-icon :closable="false"> </el-alert> <!-- 步骤条区域 --> <el-steps :space="200" :active="activeIndex - 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栏区域 --> <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="100px" label-position="top"> <el-tabs v-model="activeIndex" :tab-position="'left'" :before-leave="beforeTabLeave" @tab-click="tabClicked"> <el-tab-pane label="基本信息" name="0"> <el-form-item label="商品名称" prop="goods_name"> <el-input v-model="addForm.goods_name"></el-input> </el-form-item> <el-form-item label="商品价格" prop="goods_price"> <el-input v-model="addForm.goods_price" type="number"></el-input> </el-form-item> <el-form-item label="商品重量" prop="goods_weight"> <el-input v-model="addForm.goods_weight" type="number"></el-input> </el-form-item> <el-form-item label="商品数量" prop="goods_number"> <el-input v-model="addForm.goods_number" type="number"></el-input> </el-form-item> <el-form-item label="商品分类" prop="goods_cat"> <el-cascader expand-trigger="hover" :options="catelist" :props="cateProps" v-model="addForm.goods_cat" @change="handleChange"> </el-cascader> </el-form-item> </el-tab-pane> <el-tab-pane label="商品参数" name="1"> <!-- 渲染表单的Item项 --> <el-form-item :label="item.attr_name" v-for="item in manyTableData" :key="item.attr_id"> <!-- 复选框组 --> <el-checkbox-group v-model="item.attr_vals"> <el-checkbox :label="cb" v-for="(cb, i) in item.attr_vals" :key="i" border></el-checkbox> </el-checkbox-group> </el-form-item> </el-tab-pane> <el-tab-pane label="商品属性" name="2"> <el-form-item :label="item.attr_name" v-for="item in onlyTableData" :key="item.attr_id"> <el-input v-model="item.attr_vals"></el-input> </el-form-item> </el-tab-pane> <el-tab-pane label="商品图片" name="3"> <!-- action 表示图片要上传到的后台API地址 --> <el-upload :action="uploadURL" :on-preview="handlePreview" :on-remove="handleRemove" list-type="picture" :headers="headerObj" :on-success="handleSuccess"> <el-button size="small" type="primary">点击上传</el-button> </el-upload> </el-tab-pane> <el-tab-pane label="商品内容" name="4"> <!-- 富文本编辑器组件 --> <quill-editor v-model="addForm.goods_introduce"></quill-editor> <!-- 添加商品的按钮 --> <el-button type="primary" class="btnAdd" @click="add">添加商品</el-button> </el-tab-pane> </el-tabs> </el-form> </el-card> <!-- 图片预览 --> <el-dialog title="图片预览" :visible.sync="previewVisible" width="50%"> <img :src="previewPath" alt="" class="previewImg"> </el-dialog> </div></template><script>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 } }}</script><style lang="less" scoped>.el-checkbox { margin: 0 10px 0 0 !important;}.previewImg { width: 100%;}.btnAdd { margin-top: 15px;}</style>分类参数

在分类参数中选择一件商品,可以为其添加静态或者动态参数,这个参数可以展示在移动端商品的属性中。

<template> <div> <!-- 面包屑导航区域 --> <el-breadcrumb separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item> <el-breadcrumb-item>商品管理</el-breadcrumb-item> <el-breadcrumb-item>参数列表</el-breadcrumb-item> </el-breadcrumb> <!-- 卡片视图区域 --> <el-card> <!-- 警告区域 --> <el-alert show-icon title="注意:只允许为第三级分类设置相关参数!" type="warning" :closable="false"></el-alert> <!-- 选择商品分类区域 --> <el-row class="cat_opt"> <el-col> <span>选择商品分类:</span> <!-- 选择商品分类的级联选择框 --> <el-cascader expand-trigger="hover" :options="catelist" :props="cateProps" v-model="selectedCateKeys" @change="handleChange"> </el-cascader> </el-col> </el-row> <!-- tab 页签区域 --> <el-tabs v-model="activeName" @tab-click="handleTabClick"> <!-- 添加动态参数的面板 --> <el-tab-pane label="动态参数" name="many"> <!-- 添加参数的按钮 --> <el-button type="primary" size="mini" :disabled="isBtnDisabled" @click="addDialogVisible=true">添加参数</el-button> <!-- 动态参数表格 --> <el-table :data="manyTableData" border stripe> <!-- 展开行 --> <el-table-column type="expand"> <template slot-scope="scope"> <!-- 循环渲染Tag标签 --> <el-tag v-for="(item, i) in scope.row.attr_vals" :key="i" closable @close="handleClose(i, scope.row)">{{item}}</el-tag> <!-- 输入的文本框 --> <el-input class="input-new-tag" v-if="scope.row.inputVisible" v-model="scope.row.inputValue" 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> </el-table-column> <!-- 索引列 --> <el-table-column type="index"></el-table-column> <el-table-column label="参数名称" prop="attr_name"></el-table-column> <el-table-column label="操作"> <template slot-scope="scope"> <el-button size="mini" type="primary" icon="el-icon-edit" @click="showEditDialog(scope.row.attr_id)">编辑</el-button> <el-button size="mini" type="danger" icon="el-icon-delete" @click="removeParams(scope.row.attr_id)">删除</el-button> </template> </el-table-column> </el-table> </el-tab-pane> <!-- 添加静态属性的面板 --> <el-tab-pane label="静态属性" name="only"> <!-- 添加属性的按钮 --> <el-button type="primary" size="mini" :disabled="isBtnDisabled" @click="addDialogVisible=true">添加属性</el-button> <!-- 静态属性表格 --> <el-table :data="onlyTableData" border stripe> <!-- 展开行 --> <el-table-column type="expand"> <template slot-scope="scope"> <!-- 循环渲染Tag标签 --> <el-tag v-for="(item, i) in scope.row.attr_vals" :key="i" closable @close="handleClose(i, scope.row)">{{item}}</el-tag> <!-- 输入的文本框 --> <el-input class="input-new-tag" v-if="scope.row.inputVisible" v-model="scope.row.inputValue" 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> </el-table-column> <!-- 索引列 --> <el-table-column type="index"></el-table-column> <el-table-column label="属性名称" prop="attr_name"></el-table-column> <el-table-column label="操作"> <template slot-scope="scope"> <el-button size="mini" type="primary" icon="el-icon-edit" @click="showEditDialog(scope.row.attr_id)">编辑</el-button> <el-button size="mini" type="danger" icon="el-icon-delete" @click="removeParams(scope.row.attr_id)">删除</el-button> </template> </el-table-column> </el-table> </el-tab-pane> </el-tabs> </el-card> <!-- 添加参数的对话框 --> <el-dialog :title="'添加' + titleText" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed"> <!-- 添加参数的对话框 --> <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="100px"> <el-form-item :label="titleText" prop="attr_name"> <el-input v-model="addForm.attr_name"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="addDialogVisible = false">取 消</el-button> <el-button type="primary" @click="addParams">确 定</el-button> </span> </el-dialog> <!-- 修改参数的对话框 --> <el-dialog :title="'修改' + titleText" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed"> <!-- 添加参数的对话框 --> <el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="100px"> <el-form-item :label="titleText" prop="attr_name"> <el-input v-model="editForm.attr_name"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="editDialogVisible = false">取 消</el-button> <el-button type="primary" @click="editParams">确 定</el-button> </span> </el-dialog> </div></template><script>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 '静态属性' } }}</script><style lang="less" scoped>.cat_opt { margin: 15px 0;}.el-tag { margin: 10px;}.input-new-tag { width: 120px;}</style>订单管理订单列表

订单管理的实现和用户管理有很多类似的地方,都是向后端发送请求然后渲染到页面上

<template> <div> <!-- 面包屑导航区域 --> <el-breadcrumb separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item> <el-breadcrumb-item>订单管理</el-breadcrumb-item> <el-breadcrumb-item>订单列表</el-breadcrumb-item> </el-breadcrumb> <!-- 卡片视图区域 --> <el-card> <el-row> <el-col :span="8"> <el-input placeholder="请输入内容"> <el-button slot="append" icon="el-icon-search"></el-button> </el-input> </el-col> </el-row> <!-- 订单列表数据 --> <el-table :data="orderlist" border stripe> <el-table-column type="index"></el-table-column> <el-table-column label="订单编号" prop="order_number"></el-table-column> <el-table-column label="订单价格" prop="order_price"></el-table-column> <el-table-column label="是否付款" prop="pay_status"> <template slot-scope="scope"> <el-tag type="success" v-if="scope.row.pay_status === '1'">已付款</el-tag> <el-tag type="danger" v-else>未付款</el-tag> </template> </el-table-column> <el-table-column label="是否发货" prop="is_send"> <template slot-scope="scope"> <template> {{scope.row.is_send}} </template> </template> </el-table-column> <el-table-column label="下单时间" prop="create_time"> <template slot-scope="scope"> {{scope.row.create_time | dateFormat}} </template> </el-table-column> <el-table-column label="操作"> <template> <el-button size="mini" type="primary" icon="el-icon-edit" @click="showBox"></el-button> <el-button size="mini" type="success" icon="el-icon-location" @click="showProgressBox"></el-button> </template> </el-table-column> </el-table> <!-- 分页区域 --> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[5, 10, 15]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total"> </el-pagination> </el-card> <!-- 修改地址的对话框 --> <el-dialog title="修改地址" :visible.sync="addressVisible" width="50%" @close="addressDialogClosed"> <el-form :model="addressForm" :rules="addressFormRules" ref="addressFormRef" label-width="100px"> <el-form-item label="省市区/县" prop="address1"> <el-cascader :options="cityData" v-model="addressForm.address1"></el-cascader> </el-form-item> <el-form-item label="详细地址" prop="address2"> <el-input v-model="addressForm.address2"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="addressVisible = false">取 消</el-button> <el-button type="primary" @click="addressVisible = false">确 定</el-button> </span> </el-dialog> <!-- 展示物流进度的对话框 --> <el-dialog title="物流进度" :visible.sync="progressVisible" width="50%"> <!-- 时间线 --> <el-timeline> <el-timeline-item v-for="(activity, index) in progressInfo" :key="index" :timestamp="activity.time"> {{activity.context}} </el-timeline-item> </el-timeline> </el-dialog> </div></template><script>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) } }}</script><style lang="less" scoped>@import '../../plugins/timeline/timeline.css';@import '../../plugins/timeline-item/timeline-item.css';.el-cascader { width: 100%;}</style>数据统计数据报表

数据统计部分用到了echarts,从后端获得数据后通过 _.merge()将数据组合在一起,最后渲染在页面上

<template> <div> <!-- 面包屑导航区域 --> <el-breadcrumb separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item> <el-breadcrumb-item>数据统计</el-breadcrumb-item> <el-breadcrumb-item>数据报表</el-breadcrumb-item> </el-breadcrumb> <!-- 卡片视图区域 --> <el-card> <!-- 2. 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main" style="width: 750px;height:400px;"></div> </el-card> </div></template><script>// 1. 导入 echartsimport 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: {}}</script><style lang="less" scoped></style>项目git地址

目录中有后端以及sql文件,按照说明运行即可

电商系统前端: 电商管理系统前端

学习资源

黑马程序员前端

本文链接地址:https://www.jiuchutong.com/zhishi/296127.html 转载请保留说明!

上一篇:基于Java+Springboot+vue在线版权登记管理系统设计实现

下一篇:React 框架(react框架和vue哪个用的人多)

  • 财税2012年15号文件作废
  • 车辆出现质量问题
  • 本月发生费用未支付会计处理
  • 费用化的研发支出是否可以加计扣除
  • 资产负债表期初和期末的关系
  • 税收滞纳金计入营业外支出的哪一项
  • 未开票收入下月开票怎么做分录
  • 兼营行为的税务处理办法
  • 个人房产租金收入如何纳税申报
  • 资产处置收益结转损益
  • 外经证预缴税款怎么计算
  • 代扣代缴个人所得税手续费是否缴纳增值税
  • 分摊费用怎么说合适
  • 暂估出库是什么意思
  • 企业员工应付未付的工资该如何写其会计分录?
  • 低值易耗品按三年摊销吗
  • 退预付账款会计分录
  • 合伙制公司有董事会吗
  • 怎么查找企业核算报告
  • 合作社能否开具专用发票
  • 三种类型的同期资料文档准备时间和提交税务机关时限有什么要求?
  • 红字发票不小心点了暂存怎么办
  • 有质量问题的产品案例
  • 计提的利息收入交所得税吗
  • 季度所得税申报可以弥补以前年度亏损吗
  • 超市预付卡过了还能退吗
  • 金蝶软件测试笔试题及答案
  • 拨号的用户名
  • 鸿蒙系统桌面布局图片怎么设置
  • 以前年度损益调整会计分录
  • 高速过路费抵扣进项怎么填报
  • 收到其他公司的罚款会计分录
  • dghm.exe是什么程序
  • 公允价值变动损益借贷方向
  • 高新企业政府补贴政策
  • inputtypefile 文件名
  • php cmd
  • php trait用法
  • yolo v5超详细解析
  • 户外电源需要要充电吗
  • 2020信息采集
  • 报账单大写金额负数填写方式
  • 个体工商户生产经营所得税税率表
  • 企业跨区变更地址迁入地核验码怎么查询
  • 报废车怎么处理最划算
  • 股权转让个人所得税怎么算
  • 低值易耗品属于周转材料吗
  • 跨年度冲红字发票账务处理
  • 账上存货太多实收怎么办
  • 员工出差车票属于哪个科目
  • 计提社保和工资一起怎么做账
  • 代理赚差价违法吗
  • 采购业务 货物收到 发票收到
  • 金蝶的数量金额明细账是怎么做的
  • 去年的物业费今年收到了可以确认收入吗
  • 中小型企业产品定位方案
  • 金税盘费用不交会怎么样
  • 租赁办公楼
  • 哪些税费计入管理费用
  • 车子报废车子怎么处理
  • arp攻击的原理及防范
  • 加载dll错误是什么意思
  • win7系统分辨率调错了黑屏
  • centos dvd安装
  • OS X 10.10 Yosemite的新特性与iOS联系更紧密
  • ssh实现登录功能
  • win7系统怎么设置屏幕常亮
  • win10开机出现microsoft
  • windows mobile应用
  • windows10电脑屏保怎么取消
  • 用什么命令最简单
  • linux用户文件权限
  • jquery form表单
  • javascript闭包详解
  • node.js中的http.response.setHeader方法使用说明
  • python中str的用法
  • dom教学
  • 税务个人廉洁谈话记录内容
  • 江西发票查询真伪查询
  • 国税发票如何查真伪查询
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设