取消按钮和关闭
// 点击确定时触发 btnOK() { this.$refs.deptForm.validate(async isOK => { if (isOK) { // 表示可以提交了 await addDepartments({ ...this.formData, pid: this.treeNode.id }) // 调用新增接口 添加父部门的id this.$emit('addDepts') // 告诉父组件 新增数据成功 重新拉取数据 // update:props名称 this.$emit('update:showDialog', false) } }) }
取消时重置数据和校验
btnCancel() { this.$refs.deptForm.resetFields() // 重置校验字段 this.$emit('update:showDialog', false) // 关闭 }
需要在el-dialog中监听其close事件
<el-dialog title="新增部门" :visible="showDialog" @close="btnCancel">
本节任务
新增功能-提交-取消-关闭
编辑部门功能实现数据回写
目标
:实现编辑部门的功能
点击编辑弹出层,记录当前节点
编辑部门功能实际上和新增窗体采用的是一个组件,只不过我们需要将新增场景变成编辑场景
首先点击编辑部门时, 调用父组件编辑方法 tree-tools.vue
this.$emit('editDepts', this.treeNode)
父组件弹层,赋值当前编辑节点
<tree-tools slot-scope="obj" :tree-node="obj.data" @delDepts="getDepartments" @editDepts="editDepts" /> // 编辑部门节点 editDepts(node) { // 首先打开弹层 this.showDialog = true this.node = node // 赋值操作的节点 }
父组件调用子组件的获取详情方法
编辑时,我们需要获取点击部门的信息
封装获取部门信息的模块 src/api/departments.js
/** * * 获取部门详情 * ***/ export function getDepartDetail(id) { return request({ url: `/company/department/${id}` }) }
在什么时候获取部门详情?
我们可以在调用编辑方法 editDepts
中通过ref
调用add-dept.vue
的实例方法
// 1.导入方法 import { 其他内容, getDepartDetail } from '@/api/departments' // 2.获取部门详情方法,提供外父组件调用 async getDepartDetail(id) { // 请求来的数据回显给表单 this.formData = await getDepartDetail(id) }
// 1.放置弹层组件增加ref属性,值为addDept <!-- 放置新增弹层组件 --> <add-dept ref="addDept" :show-dialog.sync="showDialog" :tree-node="node" @addDepts="getDepartments" /> // 2. 点击编辑触发的父组件的方法 editDepts(node) { this.showDialog = true // 显示新增组件弹层 this.node = node // 存储传递过来的node数据 // 我们需要在这个位置 调用子组件的方法 // 父组件 调用子组件的方法,通过 $refs.addDept找到该组件,调用他的方法,传递数据给他 this.$refs.addDept.getDepartDetail(node.id) // 直接调用子组件中的方法 传入一个id }
根据计算属性显示控制标题
需要根据当前的场景区分显示的标题
计算属性
如何判断新增还是编辑
computed: { showTitle() { return this.formData.id ? '编辑部门' : '新增子部门' } },
同时发现,el-form中的resetFields不能重置非表单中的数据,所以在取消的位置需要强制加上 重置数据
btnCancel() { // 重置数据 因为resetFields 只能重置 表单上的数据 非表单上的 比如 编辑中id 不能重置 this.formData = { name: '', code: '', manager: '', introduce: '' } // 关闭弹层 this.$emit('update:showDialog', false) // 清除之前的校验 可以重置数据 只能重置 定义在data中的数据 this.$refs.deptForm.resetFields() }
同时支持编辑和新增场景
封装编辑接口,保存区分场景
接下来,需要在点击确定时,同时支持新增部门和编辑部门两个场景,我们可以根据formData是否有id进行区分
封装编辑部门接口 src/api/departments.js
/** * 编辑部门 * * ***/ export function updateDepartments(data) { return request({ url: `/company/department/${data.id}`, method: 'put', data }) }
点击确定时,进行场景区分
// 点击确定时触发 btnOK() { this.$refs.deptForm.validate(async isOK => { if (isOK) { // 要分清楚现在是编辑还是新增 if (this.formData.id) { // 编辑模式 调用编辑接口 await updateDepartments(this.formData) } else { // 新增模式 await addDepartments({ ...this.formData, pid: this.treeNode.id }) // 调用新增接口 添加父部门的id } // 表示可以提交了 this.$emit('addDepts') // 告诉父组件 新增数据成功 重新拉取数据 // update:props名称 this.$emit('update:showDialog', false) } }) },
校验规则支持编辑场景下的校验
除此之外,我们发现原来的校验规则实际和编辑部门有些冲突,所以需要进一步处理
// 现在定义一个函数 这个函数的目的是 去找 同级部门下 是否有重复的部门名称 const checkNameRepeat = async(rule, value, callback) => { // 先要获取最新的组织架构数据 const { depts } = await getDepartments() // 检查重复规则 需要支持两种 新增模式 / 编辑模式 // depts是所有的部门数据 // 如何去找技术部所有的子节点 let isRepeat = false if (this.formData.id) { // 有id就是编辑模式 // 编辑 张三 => 校验规则 除了我之外 同级部门下 不能有叫张三的 isRepeat = depts.filter(item => item.id !== this.formData.id && item.pid === this.treeNode.pid).some(item => item.name === value) } else { // 没id就是新增模式 isRepeat = depts.filter(item => item.pid === this.treeNode.id).some(item => item.name === value) } isRepeat ? callback(new Error(`同级部门下已经有${value}的部门了`)) : callback() } // 检查编码重复 const checkCodeRepeat = async(rule, value, callback) => { // 先要获取最新的组织架构数据 // 检查重复规则 需要支持两种 新增模式 / 编辑模式 const { depts } = await getDepartments() let isRepeat = false if (this.formData.id) { // 编辑模式 因为编辑模式下 不能算自己 isRepeat = depts.some(item => item.id !== this.formData.id && item.code === value && value) } else { // 新增模式 isRepeat = depts.some(item => item.code === value && value) // 这里加一个 value不为空 因为我们的部门有可能没有code } isRepeat ? callback(new Error(`组织架构中已经有部门使用${value}编码`)) : callback() }
至此,整个组织架构, 我们完成了,组织架构读取 / 新增部门 / 删除部门 / 编辑部门
如图
提交代码
本节任务
编辑部门功能实现
给数据获取添加加载进度条
目标
给当前组织架构添加加载进度条
由于获取数据的延迟性,为了更好的体验,可以给页面增加一个Loading进度条,采用element的指令解决方案即可
定义loading变量
loading: false // 用来控制进度弹层的显示和隐藏
赋值变量给指令
<div v-loading="loading" class="dashboard-container">
获取方法前后设置变量
async getDepartments() { this.loading = true const result = await getDepartments() this.departs = transListToTreeData(result.depts, '') this.company = { name: result.companyName, manager: '负责人', id: '' } this.loading = false }
建立公司角色页面的基本结构
目标
建立公司页面的基本结构
根据以上的结构,我们采用element-ui的组件实现
src/views/setting/index.vue
<template> <div class="dashboard-container"> <div class="app-container"> <el-card> <el-tabs> <!-- 放置页签 --> <el-tab-pane label="角色管理"> <!-- 新增角色按钮 --> <el-row style="height:60px"> <el-button icon="el-icon-plus" size="small" type="primary" >新增角色</el-button> </el-row> <!-- 表格 --> <el-table border=""> <el-table-column label="序号" width="120" /> <el-table-column label="角色名称" width="240" /> <el-table-column label="描述" /> <el-table-column label="操作"> <el-button size="small" type="success">分配权限</el-button> <el-button size="small" type="primary">编辑</el-button> <el-button size="small" type="danger">删除</el-button> </el-table-column> </el-table> <!-- 分页组件 --> <el-row type="flex" justify="center" align="middle" style="height: 60px"> <!-- 分页组件 --> <el-pagination layout="prev,pager,next" /> </el-row> </el-tab-pane> <el-tab-pane label="公司信息"> <el-alert title="对公司名称、公司地址、营业执照、公司地区的更新,将使得公司资料被重新审核,请谨慎修改" type="info" show-icon :closable="false" /> <el-form label-width="120px" style="margin-top:50px"> <el-form-item label="公司名称"> <el-input disabled style="width:400px" /> </el-form-item> <el-form-item label="公司地址"> <el-input disabled style="width:400px" /> </el-form-item> <el-form-item label="邮箱"> <el-input disabled style="width:400px" /> </el-form-item> <el-form-item label="备注"> <el-input type="textarea" :rows="3" disabled style="width:400px" /> </el-form-item> </el-form> </el-tab-pane> </el-tabs> </el-card> </div> </div> </template>
提交代码
本节任务
建立公司页面的基本结构
读取公司角色信息
目标
: 封装公司角色请求,读取公司角色信息
读取角色列表数据
首先,封装读取角色的信息的请求 src/api/setting.js
/** * 获取角色列表 * ***/ export function getRoleList(params) { return request({ url: '/sys/role', params }) }
params是查询参数,里面需要携带分页信息
然后,在页面中调用接口获取数据,绑定表格数据 src/views/setting/index.vue
import { getRoleList } from '@/api/setting' export default { data() { return { list: [], // 承接数组 page: { // 放置页码及相关数据 page: 1, pagesize: 10, total: 0 // 记录总数 } } }, created() { this.getRoleList() // 获取角色列表 }, methods: { async getRoleList() { const { total, rows } = await getRoleList(this.page) this.page.total = total this.list = rows }, changePage(newPage) { // newPage是当前点击的页码 this.page.page = newPage // 将当前页码赋值给当前的最新页码 this.getRoleList() } } }
绑定表格数据
<el-table border="" :data="list"> <el-table-column align="center" type="index" label="序号" width="120" /> <el-table-column align="center" prop="name" label="名称" width="240" /> <el-table-column align="center" prop="description" label="描述" /> <el-table-column align="center" label="操作"> <el-button size="small" type="success">分配权限</el-button> <el-button size="small" type="primary">编辑</el-button> <el-button size="small" type="danger">删除</el-button> </el-table-column> </el-table>
绑定分页数据
<!-- 放置分页组件 --> <el-row type="flex" justify="center" align="middle" style="height:60px"> <el-pagination :current-page="page.page" :page-size="page.pagesize" :total="page.total" layout="prev, pager, next" @current-change="changePage" /> </el-row>
读取公司信息数据
第二个tab页,我们同样需要读取数据
封装读取公司信息的api src/api/setting.js
/** * 获取公司信息 * **/ export function getCompanyInfo(companyId) { return request({ url: `/company/${companyId}` }) }
设定表单信息变量
data() { return { ..., formData: {} // // 表单信息变量 } }
绑定公司表单数据
<el-form label-width="120px" style="margin-top:50px"> <el-form-item label="公司名称"> <el-input v-model="formData.name" disabled style="width:400px" /> </el-form-item> <el-form-item label="公司地址"> <el-input v-model="formData.companyAddress" disabled style="width:400px" /> </el-form-item> <el-form-item label="邮箱"> <el-input v-model="formData.mailbox" disabled style="width:400px" /> </el-form-item> <el-form-item label="备注"> <el-input v-model="formData.remarks" type="textarea" :rows="3" disabled style="width:400px" /> </el-form-item> </el-form>
请求中的companyId来自哪里?它来自我们登录成功之后的用户资料,所以我们需要在该组件中使用vuex数据
src/store/getters.js
companyId: state => state.user.userInfo.companyId // 建立对于user模块的companyId的快捷访问
页面组件中
import { mapGetters } from 'vuex' // 导入辅助函数 computed: { ...mapGetters(['companyId']) },
初始化时调用接口
// 获取的公司的信息 async getCompanyInfo() { this.formData = await getCompanyInfo(this.companyId) } created() { this.getRoleList() // 获取角色列表 this.getCompanyInfo() },
提交代码
本节任务
读取公司角色信息
删除角色功能
目标
实现删除角色的功能
封装删除角色的api
/** ** * 删除角色 * * ****/ export function deleteRole(id) { return request({ url: `/sys/role/${id}`, method: 'delete' }) }
删除功能实现
// 删除角色事件 async deleteRole(id) { // 提示 try { await this.$confirm('确认删除该角色吗') // 只有点击了确定 才能进入到下方 await deleteRole(id) // 调用删除接口 // 如果不是第一页,且只有一个元素,删除成功,则需要把页码-1,重新拉取列表 if (this.list.length === 1 && this.page.page !== 1) { this.page.page-- } this.getRoleList() // 重新加载数据 this.$message.success('删除角色成功') } catch (error) { console.log(error) } },
删除按钮注册事件
<!-- 作用域插槽 --> <template slot-scope="{ row }"> <el-button size="small" type="success">分配权限</el-button> <el-button size="small" type="primary">编辑</el-button> <el-button size="small" type="danger" @click="deleteRole(row.id)">删除</el-button> </template>
提交代码
编辑角色功能
目标
: 实现编辑角色的功能
封装编辑接口,新建编辑弹层
封装编辑角色的功能api
/** * * 修改角色 * ***/ export function updateRole(data) { return request({ url: `/sys/role/${data.id}`, data, method: 'put' }) } /** * 获取角色详情 * **/ export function getRoleDetail(id) { return request({ url: `/sys/role/${id}` }) }
定义编辑弹层数据
data(){ return{ ..., // 其他变量 // 弹框显示变量 showDialog: false, // 专门接收新增或者编辑的编辑的表单数据 roleForm: {}, // 验证规则 rules: { name: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }] } } }
编辑弹层结构
<el-dialog title="编辑弹层" :visible="showDialog" @close="btnCancel"> <el-form ref="roleForm" :model="roleForm" :rules="rules" label-width="120px"> <el-form-item label="角色名称" prop="name"> <el-input v-model="roleForm.name" /> </el-form-item> <el-form-item label="角色描述"> <el-input v-model="roleForm.description" /> </el-form-item> </el-form> <!-- 底部 --> <el-row slot="footer" type="flex" justify="center"> <el-col :span="6"> <el-button size="small" @click="btnCancel">取消</el-button> <el-button size="small" type="primary" @click="btnOK">确定</el-button> </el-col> </el-row> </el-dialog>