# 09vue_admin **Repository Path**: null_211_3661/09vue_admin ## Basic Information - **Project Name**: 09vue_admin - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-01-14 - **Last Updated**: 2024-01-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 09vue_admin 项目步骤: # element-ui的使用 ``` 1、创建脚手架 vue create admin 2、直接进入element-ui官网 https://element.eleme.cn/2.0/#/zh-CN/component/quickstart 3、element-ui的使用 main.js中使用element-ui // 导入element-ui import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) ``` # 12.登录退出-渲染Login组件并实现路由重定向 ``` 1、component下创建Login.vue组件 2、App.vue中提供坑位 router-view
3、router.js 匹配路由规则并重定向到login组件 routes: [ { path: '/', redirect: "/login" }, { path: '/login', name: 'login', component: Login } ] ``` # 登录页面的绘制 15.登录退出-绘制登录表单区域 + 16.登录退出-绘制带icon的input输入框 ``` 1、Login.vue组件 布局
2、main.js引入公共样式 // 导入字体图标 import './assets/fonts/iconfont.css' // 导入全局样式表 import './assets/css/global.css' ``` # 18.登录退出-实现表单数据验证 ``` 步骤分析: 1、给el-form绑定表单属性以及上相数据绑定 2、定义双向数据绑定的数据+校验表单规则 登录 重置 ==== 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' } ] } ``` # 19.登录退出-实现表单的重置功能 ``` 1、实现白哦单属于重置 // 点击重置按钮,重置登录表单 resetLoginForm() { // // console.log(this); this.$refs.loginFormRef.resetFields() }, ``` # 23.登录退出-完善登录之后的操作 + 24.登录退出-路由导航守卫控制页面访问权限 ``` Login.vue 登录成功: window.sessionStorage.setItem('token', res.data.token) router.js 路由拦截 /*路由导航守卫*/ router.beforeEach((to, from, next) => { if (to.path == "/login") return next(); // 获取token const tokenStr = window.sessionStorage.getItem("token"); if(!tokenStr) return next("/login"); next(); }) ``` # 25.登录退出-实现退出功能 ``` Home.vue 给推出按钮绑定点击事件 点击:清除缓存+跳转回Login.vue logout() { window.sessionStorage.clear() this.$router.push('/login') } ``` # 26.语法处理-处理项目中的ESLint语法报错问题 ``` 处理ESLint警告 1、在项目根目录添加 .prettierrc 文件 { "semi":false, "singleQuote":true } 2、打开.eslintrc.js文件,禁用对 space-before-function-paren 的检查: rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'space-before-function-paren' : 0 }, ``` # 27.语法处理-修改element-ui组件的按需导入形式 ``` ===== 之前写法: // 导入element-ui // import ElementUI from 'element-ui' // import 'element-ui/lib/theme-chalk/index.css' // Vue.use(ElementUI) ==== 现在写法: import './plugins/element.js' import 'element-ui/lib/theme-chalk/index.css' *********** plugins/element.js import Vue from 'vue' import { Button, Form, FormItem, Input, Message } from 'element-ui' Vue.use(Button) Vue.use(Form) Vue.use(FormItem) Vue.use(Input) Vue.prototype.$message = Message ``` day4 ``` 首页布局 Home.vue Header 退出 Aside Main 样式: .home-container { height: 100%; } .el-header{ background-color:#373D41; } .el-aside{ background-color:#333744; } .el-main{ background-color:#eaedf1; } ======顶部布局,侧边栏布局 ``` # 04.主页-通过axios拦截器添加token验证 ``` 后台除了登录接口之外,都需要token权限验证,我们可以通过添加axios请求拦截器来添加token,以保证拥有获取数据的权限 在main.js中添加代码,在将axios挂载到vue原型之前添加下面的代码 //请求在到达服务器之前,先会调用use中的这个回调函数来添加请求头信息 axios.interceptors.request.use(config=>{ //为请求头对象,添加token验证的Authorization字段 config.headers.Authorization = window.sessionStorage.getItem("token") return config }) ``` # 抽离接口到api/index.js ``` 1、src/api/index.js import axios from 'axios' // 配置请求的跟路径 axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/'; axios.interceptors.request.use(config => { // console.log(config) config.headers.Authorization = window.sessionStorage.getItem('token') // 在最后必须 return config return config }) //添加响应拦截器 axios.interceptors.response.use(function (response) { // 对响应数据做点什么 return response; }, function (error) { // 对响应错误做点什么 return Promise.reject(error); }); export const login_api = (params=>{ return axios.post("login",params); }) export const login_api = (params=>{ return axios.post("login",params); }) 2、login.vue 1、import { login_api } from '@/api' 2、const {data:res}=await login_api(this.loginForm); 3、main.js import "./api/index.js" ``` # 06.主页-通过双层for循环渲染左侧菜单 ``` 解决点击以及菜单出现所有的都跟着展开的问题 出现问题的原因:el-submenu 后面的index的值是一致的并且要是一个字符串 解决方法: :index="item.id+''" ``` # 07.主页-为选中项设置字体颜色并添加分类图标 ``` 1、在data中定义一个对象 iconsObj: { '125':'iconfont icon-user', '103':'iconfont icon-tijikongjian', '101':'iconfont icon-shangpin', '102':'iconfont icon-danju', '145':'iconfont icon-baobiao' } 2、将对象显示在结构中 3、二级图标显示 ``` # 08.主页-每次只能打开一个菜单项并解决边框问题 ``` 4、水平收起+默认只展开一个菜单 ``` # 09.主页-实现侧边栏的折叠与展开效果 ```
|||
||| ``` # 10.主页-实现首页路由的重定向效果 ``` 步骤分析: 1、router.js====配置路由:重定向redirect 并配置子路由 import Welcome from './components/Welcome.vue' { path: '/home', name: 'home', component: Home, redirect: "/welcome",children: [ { path: '/welcome', name: 'Welcome', component: Welcome }, ] }, 2、home.vue==== ``` # 11.主页-实现侧边栏路由链接的改造 ``` 步骤: 1、 index的值就是路由跳转的值 可直接将获取的二级分类的值显示在index上即可 ``` # 13.用户列表-在sessionStorage中保存左侧菜单的激活状态 ``` 1、给二级子菜单绑定点击事件 并将二级菜单的path存储到本地缓存 /* 菜单高亮 */ saveNavState(activePath){ console.log(activePath,8); window.sessionStorage.setItem("activePath",activePath); this.activePath=activePath; } 2、激活当前选中的 ===使用 default-active 值跟route跳转时的index的值保持一致 :default-active="activePath" 3、初次进入获取本地缓存 显示上一次的选中状态 creatd(){ this.activePath = window.sessionStorage.getItem('activePath')} ``` # 16.用户列表-使用el-table组件渲染基本的用户列表 ``` ``` # 17.用户列表-为表格添加索引列 + 18.用户列表-自定义状态列的显示效果 ``` ``` # 19.用户列表-通过作用域插槽渲染操作列 ``` ``` # 20.用户列表-实现分页效果 ``` // 监听 pagesize 改变的事件 handleSizeChange(val) { console.log(`每页 ${val} 条`) this.queryInfo.pagesize=val; this.getUserList() }, // 监听 页码值 改变的事件 handleCurrentChange(val) { console.log(`当前页: ${val}`) this.queryInfo.pagenum=val; this.getUserList() } ``` # 21.用户列表-修改用户状态 ``` 1、给看管绑定点击事件 change事件是官方文档中提供的事件 2、点击时需要传入当前行的id+状态值 使用scope.row可以获取 3、点击发送请求 传入杜颖的参数 id + type /* 修改用户状态 */ async userStateChanged(userinfo){ const {data:res}=await userStateChanged_api({uId:userinfo.id,type:userinfo.mg_state}); console.log(res.meta.status,23); if(res.meta.status!==200){ return this.$message({ message: '更新用户状态失败', type: 'error' }); }else{ this.$message({ message: '更新用户状态成功', type: 'success' }); } } ``` # 22.用户列表-实现搜索功能 ``` 1、给表单添加clearable属性 目的是在输入时可以显示删除按钮 2、给删除按钮绑定clear事件 就不根据条件搜索直接调用用户列表即可恢复初始状态 3、给搜索按钮绑定点击事件 表单双向数据绑定 queryInfo.query 那么发送请求就会根据query获取数据 ``` # 23.添加用户-渲染添加用户的对话框 ``` 1、给添加按钮绑定点击事件==== 添加用户 ========== 2、对话框布局 取 消 确 定 data(){ return { addDialogVisible:false } } ``` # 25.添加用户-自定义邮箱和手机号的校验规则 ``` 1、data函数返回值return外 定义自定义规则 2、data韩慧返回值return内 定义其他校验规则 // 验证邮箱的规则 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('请输入合法的手机号')) } ========// 添加表单的验证规则对象 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' } ] } ``` # 26.添加用户-实现添加表单的重置操作 ``` 实现点击对话框的 删除按钮 表单值 应该恢复到初始化状态 // 监听添加用户对话框的关闭事件 addDialogClosed(){ this.$refs.addFormRef.resetFields(); } ``` # 28.添加用户-调用API接口完成添加用户的操作 ``` 步骤分析: 1、给安妮绑定点击事件 2、对当前表单进行校验 匹配成功即可发送请求不成功不发送 3、发送请求传入参数 4、获取返回来的结果集成功后 1、显示成功的提示框 2、关闭对话框 3、重新获取对话列表 // 点击按钮,添加新用户 addUser() { this.$refs.addFormRef.validate(async valid=>{ if(!valid) return; // 可以发起添加用户的网络请求 const {data:res}=await users_api(this.addForm); console.log(res,88); if(res.meta.status!==201) return this.$message.error('添加用户失败!'); this.$message.success('添加用户成功!') // 隐藏添加用户的对话框 this.addDialogVisible = false // 重新获取用户列表数据 this.getUserList() }) } ``` # 02.修改用户-根据Id查询对应的用户信息+展示数据 ``` 1、编辑按钮绑定点击事件显示会话框 并传当前点击行的id 2、修改用户的对话框 取 消 确 定 3、显示对话框 ShowEditDialog 1、根据id发送请求获取用户信息 2、将获取的用户信息进行判断 3、将获取的用户信息赋值给 editForm 这样对话框中的表单双向数据绑定即会显示在表单上 4、对话框显示 // 修改用户 async ShowEditDialog(id){ console.log(id,22); const {data:res}=await getUsersId_api(id); console.log(res,77); if(res.meta.status!==200) return this.$message.error('查询用户信息失败!'); this.editForm=res.data; this.editDialogVisible=true; }, ``` # 04.修改用户-实现修改用户表单的重置操作 ``` // 监听修改用户对话框的关闭事件 editDialogClosed(){ this.$refs.editFormRef.resetFields(); } ``` # 06.修改用户-提交表单完成用户信息的修改 ``` /* 编辑用户提交 */ export const editUserInfo_api = (params=>{ return axios.put(`users/${params.id}`,{email:params.email,mobile:params.mobile}); }) editUserInfo() { this.$refs.editFormRef.validate(async valid => { console.log(valid, 7) if (!valid) return const { data: res } = await editUserInfo_api(this.editForm) if (res.meta.status !== 200) return this.$message.error('查询用户信息失败!') // 关闭对话框 this.editDialogVisible = false // 刷新数据列表 this.getUserList() // 提示修改成功 this.$message.success('更新用户信息成功!') }) } ``` # 08.删除用户-调用API完成删除用户的操作 ``` 1、绑定点击事件 调用会话提示框 this.$confirm() 2、将promise对象进行改造 成async await 接受返回值 3、获取点击会话框的返回值根据其返回值来判断点击的是取消还是确认 4、取消就提示已取消 5、点击的是确认就根据id发送请求 1、根据状态值判断!=200提示删除失败 2、否则提示成功的提示 3、重新获取数据列表 // 根据Id删除对应的用户信息 async removeUserById(id) { const confirmResult = await this.$confirm( '此操作将永久删除该文件, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ) // .then(() => { // this.$message({ // type: 'success', // message: '删除成功!' // }); // }) .catch(err => err) //console.log(confirmResult,78); if (confirmResult != 'confirm') { return this.$message.info('已取消删除') } const { data: res } = await removeUserById_api(id) if (res.meta.status !== 200) return this.$message.error('删除用户失败!') // 提示删除成功 this.$message.success('删除用户信息成功!') // 刷新数据列表 this.getUserList() } } ``` # 权限列表 ``` 实现步骤: 1、在components/power/Rights.vue组件 2、匹配路由规则 3、Rights.vue中布局页面 4、发送请求获取权限列表 ===========请求type="list" /* 权限列表 */ export const getRightsList_api = (()=>{ return axios.get(`rights/list`); }) ===============请求权限列表数据 async getRightsList() { const { data: res } = await getRightsList_api() if (res.meta.status !== 200) { return this.$message.error('获取权限列表失败!') } this.rightsList = res.data console.log(this.rightsList,8899) } =============页面布局 ``` # 15.介绍 用户-角色-权限 三者之间的关系 # 24.角色列表-通过第三层for循环渲染一、二、三级权限 ``` 步骤分析: 1、一级 1、第一层循环可以得出总共有多少行,即第一层有多少个 2、每行中分为两列 即一级为一列【称为左边列】,二级+三级为每行中的第二列 【称为右边列】 对右边列又分为两列【即二级+三级】 2、二级 1、可以根据一级循环得到的每一项的children,对右边列中的放二级+三级的盒子进行循环可以得到二级有多少行 3、三级 1、对三级直接根据二级的children进行循环,可以得到三级有多少个 添加角色 ``` # 26.角色列表-点击删除权限按钮弹出确认提示框 ``` 1、给每个按钮身上添加属性 closable 2、给三级权限删除按钮绑定点击事件 @close="removeRightById" {{item3.authName}} 3、删除权限的对话提示 async removeRightById() { // 弹框提示用户是否要删除 const confirmResult = await this.$confirm( '此操作将永久删除该文件, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ).catch(err => err); if (confirmResult != 'confirm') { return this.$message.info('已取消删除') } ``` # 27.角色列表-完成删除角色下指定权限的功能 ``` 1、给每个权限绑定的事件上传入参数 传入角色id+权限id ====scope.row.id是角色id {{item3.authName}} {{item1.authName}} {{item2.authName}} 2、发送请求删除权限==返回的是当前角色的所有权限数据 ====将返回值重新赋值当前权限即可实时删除 const {data:res}=await removeRightById_api({roleId:role.id,rightId:rightId}); if (res.meta.status !== 200) { return this.$message.error('删除权限失败!') } console.log(res,7788); role.children=res.data; /* 根据Id删除对应的权限 */ export const removeRightById_api = ((params)=>{ return axios.delete(`roles/${params.roleId}/rights/${params.rightId}`); }) ``` # 30.分配权限-优化树形控件的展示效果 ``` 1、按钮绑定点击事件 2、对话框显示后发生请求 1、显示对话框 2、将获取的数据传给树形结构 取 消 确 定 ======= /* 分配权限按钮点击显示对话框树形结构 */ async showSetRightDialog() { const { data: res } = await getRightsTree_api() console.log(res, 23) if (res.meta.status !== 200) { return this.$message.error('获取角色列表失败!') } this.setRightDialogVisible = true this.rightslist = res.data }, 3、树形结构配置项 1、定义 treeProps树形告诉树形结构显示 rightslist 中的 authName值, 以children为节点 2、定义其他属性 show-checkbox 显示复选框 node-key="id" 显示唯一值,获取 的到时就是id default-expand-all 展开所有的节点 // 树形控件的属性绑定对象 treeProps: { label: 'authName', children: 'children' }, ``` # 32.分配权限-加载当前角色已有的权限 + 33.分配权限-在关闭对话框时重置defKeys数组 ``` 1、定义属性 default-checked-keys 2、data中设置 defKeys:[] 3、封装函数 getLeafKeys(传入角色对象,传入数组) 1、对对象中的children循环遍历 对每一个children进行调用 知道获取对象中每一层中的children判断其子节点有误children 有:说明还有子节点 没有:说明就没有子节点,就直接将子节点中的id添加到数组中,停止当前这个对象的循环 4、进行调用: @click="showSetRightDialog(scope.row) :default-checked-keys="defKeys" 是用来根据权限id的值来显示是否选中 // 默认选中的节点Id值数组 defKeys: [], /* 分配权限按钮点击显示对话框树形结构 */ async showSetRightDialog(role) { console.log(role,7788); const { data: res } = await getRightsTree_api() console.log(res, 23) if (res.meta.status !== 200) { return this.$message.error('获取角色列表失败!') } this.setRightDialogVisible = true this.rightslist = res.data; // 递归获取三级节点的Id this.getLeafKeys(role,this.defKeys); }, // 通过递归的形式,获取角色下所有三级权限的id,并保存到 defKeys 数组中 getLeafKeys(node,arr){ // 如果当前 node 节点不包含 children 属性,则是三级节点 if(!node.children){ // console.log(arr,666); return arr.push(node.id); }; node.children.forEach(item => this.getLeafKeys(item,arr)); } 5、点击关闭对话框 再打开发现每次显示的权限都是一样的,原因: 之前选中后给defKeys传了id 再次进入这个defKeys支部会改变 因为页面也没有刷新 所以不会改变 解决办法:每次点击关闭就让其defKeys=[] ``` # 34.分配权限-调用API完成分配权限的功能 ``` 步骤分析: 1、获取权限的id 一级二级三级都需要获取 返回一个数组 2、将获取的id以字符串‘,’返回 const keys = [ ...this.$refs.treeRef.getCheckedKeys(), ...this.$refs.treeRef.getHalfCheckedKeys() ] var rids = keys.join(',') 3、发送请求 传入roleId + rids 1、roleId在点击分配授权的时候显示对话框 插槽传值中有角色id,将角色id在对话框显示的时候赋值给data中 的roleId /* 分配权限按钮点击显示对话框树形结构 */ async showSetRightDialog(role) { console.log(role, 7788) this.roleId = role.id const { data: res } = await getRightsTree_api() console.log(res, 23) if (res.meta.status !== 200) { return this.$message.error('获取角色列表失败!') } this.setRightDialogVisible = true this.rightslist = res.data // 递归获取三级节点的Id this.getLeafKeys(role, this.defKeys) }, 2、api/index.js 封装请求函数 /* 角色授权 type=tree*/ export const allotRights_api = ((params) => { return axios.post(`roles/${params.roleId}/rights`,{rids:params.rids}); }) 3、发送请求即成功后重新获取数据 async allotRights() { const keys = [ ...this.$refs.treeRef.getCheckedKeys(), ...this.$refs.treeRef.getHalfCheckedKeys() ] var rids = keys.join(',') console.log(rids, 7788) const { data: res } = await allotRights_api({ roleId: this.roleId, rids: rids }) console.log(res, 778) if (res.meta.status !== 200) { return this.$message.error('分配权限失败!') } this.$message.success('分配权限成功!') this.getRolesList() this.setRightDialogVisible = false } ``` # 分配角色 ``` 步骤分析: 1、分配角色按钮绑定点击事件 调用封装函数 @click="setRole(scope.row)" 1、传入角色信息 scrope.row 包含有用户 2、调用封装函数 setRole(userInfo) userInfo={ create_time: 1486720211 email: "adsfad@qq.com" id: 500 mg_state: true mobile: "12345678" role_name: "超级管理员" username: "admin" } 3、将userInfo值赋值给this.userInfo 3、显示对话框 this.setRoleDialogVisible = true 4、发送请求获取 获取角色列表 并将角色列表赋值给 this.rolesList // 展示分配角色的对话框 async setRole(userInfo) { console.log(userInfo,78); this.userInfo = userInfo this.setRoleDialogVisible = true const { data: res } = await getRolesList_api() //console.log(res,4455); if (res.meta.status !== 200) { return this.$message.error('获取角色列表失败!') } this.rolesList = res.data }, 2、点击分配角色确认按钮 @click="saveRoleInfo" 1、判断是否选中分配新角色 2、发送请求 1.3.7. 分配用户角色 === users/:id/role === put 3、获取数据后判断返回值 4、关闭对话框 5、显示成功后的提示 6、刷新角色数据 重新获取用户列表 // 点击按钮,分配角色 async saveRoleInfo() { if (!this.selectedRoleId) { return this.$message.error('请选择要分配的角色!') } const { data: res } = await saveRoleInfo_api({ id: this.userInfo.id, rid: this.selectedRoleId }) console.log(res, 87) if (res.meta.status !== 200) { return this.$message.error('更新角色失败!') } this.$message.success('更新角色成功!') this.getUserList() this.setRoleDialogVisible = false }, 3、监听关闭对话框 情况下拉框的id值+用户信息 // 监听分配角色对话框的关闭事件 setRoleDialogClosed() { this.selectedRoleId = '' this.userInfo = {} } ``` # 商品分类列表数据获取 ``` 步骤分析: 1、创建组件后再组件中定义数据属性 2、封装axios请求接口===注意get传参 3、发送请求获取数据,将数据和总条数赋值 return { // 查询条件 querInfo: { type: 3, pagenum: 1, pagesize: 5 }, // 商品分类的数据列表,默认为空 catelist: [], total:"" } /* 商品分类列表 */ export const getCateList_api = ((params) => { return axios.get(`categories`,{ params: params }); }) // 获取商品分类数据 async getCateList() { const { data: res } = await getCateList_api( this.querInfo); if (res.meta.status !== 200) { return this.$message.error('获取商品分类失败!') } console.log(res.data,1) // 把数据列表,赋值给 catelist this.catelist = res.data.result // 为总数据条数赋值 this.total = res.data.total } ``` # vue-table-with-tree-grid 的使用 ``` https://www.npmjs.com/package/vue-table-with-tree-grid 使用步骤: import ZkTable from 'vue-table-with-tree-grid' Vue.use(ZkTable) 局部使用组件 Cate.vue 1、导入组件 2、挂载组件 3、定义columns 4、模板配置 =====1 import {getCateList_api} from "@/api"; =====2 components:{ TreeTable } =====3 // 商品分类的数据列表,默认为空 catelist: [], total:"", // 为table指定列的定义 columns: [ { label: '分类名称', prop: 'cat_name' }, { label: '是否有效', // 表示,将当前列定义为模板列 type: 'template', // 表示当前这一列使用模板名称 template: 'isok' }, { label: '排序', // 表示,将当前列定义为模板列 type: 'template', // 表示当前这一列使用模板名称 template: 'order' }, { label: '操作', // 表示,将当前列定义为模板列 type: 'template', // 表示当前这一列使用模板名称 template: 'opt' } ], =====4 ``` # 分页的实现 ``` 步骤分析: 1、导入组件模块 2、触发两个事件获取当前页和每页显示条数获取其值,重置queryInfo中的pagenum和pagesize,然后重新获取数据 =====1 =====2 /* 分页 */ handleSizeChange(val) { console.log(`每页 ${val} 条`); this.querInfo.pagesize=val; this.getCateList() }, handleCurrentChange(val) { console.log(`当前页: ${val}`); this.querInfo.pagenum=val; this.getCateList() } ``` # 对话框显示 + 渲染级联选择器 ``` 步骤分析 1、绑定点击事件显示对话框 2、获取商品分类数据 根据type=2获取 3、使用Cascader 级联选择器 实现下拉框 4、配置下拉框属性显示数据 =====1 取 消 确 定 =====2 // 控制添加分类对话框的显示与隐藏 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: [] =====3 /* 添加 */ //显示对话框 showAddCateDialog() { this.addCateDialogVisible = true this.getParentCateList() }, // 获取父级分类的数据列表 async getParentCateList() { this.querInfo.type = 2 const { data: res } = await getCateList_api(this.querInfo) if (res.meta.status !== 200) { return this.$message.error('获取父级分类数据失败!') } console.log(res.data, 2) this.parentCateList = res.data.result }, // 选择项发生变化触发这个函数 parentCateChanged() { console.log(this.selectedKeys, 222) }, ``` # 添加分类 + 对话框关闭功能 ``` 步骤分析: 1、选中下拉框就判断是否有选中,根据长度来判断 1、父级分类的Id :根据长度来判断 长度大于0 就获取选中的id的数组中第一个值,可以根据数组长度来决定 2、当前分类的等级赋值:根据选中下拉框的id的长度来决定分类的等级 3、如果没有选中下拉框,那么 父级分类的Id=当前分类的等级赋值=0 2、关闭对话框 1、清空下拉框+表单值 对表单进行重置 2、父级分类的Id=当前分类的等级赋值=0 3、点击确认按钮 1、校验表单 2、根据请求传递参数 3、成功后关闭对话框,给出成功的提示 4、重新获取数据列表 parentCateChanged() { console.log(this.selectedKeys, 222) // 如果 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 return } else { // 父级分类的Id this.addCateForm.cat_pid = 0 // 为当前分类的等级赋值 this.addCateForm.cat_level = 0 } }, // 监听对话框的关闭事件,重置表单数据 addCateDialogClosed() { this.$refs.addCateFormRef.resetFields() this.selectedKeys = [] this.addCateForm.cat_level = 0 this.addCateForm.cat_pid = 0 }, // // 点击按钮,添加新的分类 addCate() { this.$refs.addCateFormRef.validate(async valid => { if (!valid) return const { data: res } = await addCate_api(this.addCateForm) if (res.meta.status !== 201) { return this.$message.error('获取父级分类数据失败!') } console.log(res, 22) this.$message.success('添加分类成功!') this.getCateList() this.addCateDialogVisible = false }) } ``` # 分类参数 联级数据显示 ``` 此处数据展示跟商品管理实现步骤一致 可参考Cate.vue =====1 选择商品分类: =====2 return { // 商品分类列表 catelist: [], // 级联选择框的配置对象 cateProps: { value: 'cat_id', label: 'cat_name', children: 'children' }, selectedCateKeys: [] } =====3 // 获取所有的商品分类列表 async getCateList() { const { data: res } = await getCateList_api() if (res.meta.status !== 200) { return this.$message.error('获取商品分类失败!') } this.catelist = res.data console.log(this.catelist) }, handleChange() { // 证明选中的不是三级分类 if (this.selectedCateKeys.length !== 3) { this.selectedCateKeys = [] return } } ```