<template>
<div class="employees-container">
<div class="app-container">
<page-tools>
<template #left>
<div class="tips">
<i class="el-icon-info" />
<span>本月: 社保在缴 公积金在缴</span>
</div>
</template>
<template #right>
<el-button type="warning" size="small" @click="$router.push('/import')">excel导入</el-button>
<el-button type="danger" size="small" @click="exportExcel">excel导出</el-button>
<el-button type="primary" size="small" @click="addEmployee">新增员工</el-button>
</template>
</page-tools>
<el-card style="margin-top: 10px;">
<el-table border :data="list">
<el-table-column label="序号" type="index" />
<el-table-column label="姓名" prop="username" />
<el-table-column label="工号" prop="workNumber" />
<!--
prop指定一个字段名称 此时原样输出 后端返回什么就显示什么
如果你想做定制化 拿到源数据利用作用域插槽 再做优化
-->
<el-table-column label="聘用形式">
<template #default="{row}">
<!--
差值表达式 内部支持三元运算 函数调用等等
如果格式化的情况只有两种 -> 三元表达式
如果格式化的情况很多 -> 格式化函数
方案:格式化的函数 {{fn()}} 渲染出来的是什么?渲染的函数的返回值
思路:把拿到的源数据作为实参传入格式化函数 在函数内部做一些格式化 最终return出去
-->
{{ formatEmployee(row.formOfEmployment) }}
</template>
</el-table-column>
<el-table-column label="部门" prop="departmentName" />
<el-table-column label="入职时间" width="180" prop="timeOfEntry">
<template #default="{row}">
{{ formatTime(row.timeOfEntry) }}
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200">
<template #default="{row}">
<el-button type="text" size="small" @click="goDetail(row.id)">查看</el-button>
<el-button type="text" size="small">分配角色</el-button>
<el-button type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--
分页器组件
layout: 定制分页器的结构 上一页 下一页 页数 跳转 切换条数
分页逻辑: 总条数 / 每页条数 = 页数 总条数一定要传 每页条数默认10条
点击分页切换table数据显示: 点击时拿到当前的页数 -> 使用这个页数获取新的数据重新交给list
传给后端的size可以和分页组件要求的每页条数不一致吗?
这里必须一致 否则后端的分页逻辑和前端的分页对不上!!!
如果后端一共20条数据 传给后端的size=10 后端的数据可以分俩页出来
如果前端size=5 前端可以分4页出来 请求3页4页哪里还有数据呀??
-->
<el-pagination
layout="prev, pager, next"
:total="total"
:page-size="params.size"
@current-change="pageChange"
/>
</el-card>
</div>
<add-employee-vue
:dialog-visible="dialogVisible"
@close-dialog="closeDialog"
/>
</div>
</template>
<script>
/**
新增
1. 抽离一个子组件 把弹框的部分放到子组件内部
2. 把子组件在index.vue中引入 形成一个父子嵌套的关系
3. 通过父传子的方式 实现弹框的打开
4. 通过子传父的方式 实现弹框的关闭
*/
import { fetchEmployeeList } from '@/api/employee'
import dayjs from 'dayjs'
import addEmployeeVue from './components/add-employee.vue'
import { getExportData } from '@/utils/excel'
export default {
name: 'EmployeeIndex',
components: {
addEmployeeVue
},
data() {
return {
list: [],
params: {
page: 1,
size: 10
},
total: 0,
dialogVisible: false
}
},
mounted() {
this.getList()
},
methods: {
async getList() {
const res = await fetchEmployeeList(this.params)
this.list = res.rows
this.total = res.total
},
formatEmployee(value) {
// 把value按照需求格式化
// 1 -> 正式 2 -> 非正式 4->其他
// 前端枚举优化: 先把所有的对应关系通过对象定义出来 + 对象的取值 -> 策略模式 优化多分支语句的
const MAP = {
1: '正式',
2: '非正式',
4: '其它'
}
return MAP[value]
// if (value === '1') {
// return '正式'
// } else if (value === '2') {
// return '非正式'
// } else {
// return '其他'
// }
},
formatTime(value) {
return dayjs(value).format('YYYY-MM-DD')
},
pageChange(page) {
this.params.page = page
this.getList()
},
addEmployee() {
this.dialogVisible = true
},
closeDialog() {
this.dialogVisible = false
},
// 导出
exportExcel() {
// import是一个动态导入模块的语法
// 只有用到它的时候才会动态加载 进行打包不会出现在打出的包里 不会占用体积
import('@/vendor/Export2Excel').then(async excel => {
// 一个表格最重要俩部分 1.表头 theader 2.表体 tbody
// 1. 先请求当前页的最新的数据
const res = await fetchEmployeeList(this.params) // res -> 对象数组
// 2. 把后端最新数据格式化成插件需要的格式
const headerRelation = {
'姓名': 'username',
'手机号': 'mobile',
'入职日期': 'timeOfEntry',
'工号': 'workNumber',
'聘用形式': 'formOfEmployment',
'部门': 'departmentName'
}
const { data } = getExportData(res.rows, headerRelation)
// 3. 配置到对应的位置即可
excel.export_json_to_excel({
header: Object.keys(headerRelation), // 配置表头的位置 -> 数组格式
data: data, // 配置表体的位置 -> 二维数组
filename: 'excel-employee', // 文件名称
autoWidth: true, // 单元格宽度是否自动撑开
bookType: 'xlsx' // excle文件类型
})
})
},
goDetail(id) {
// query + path
this.$router.push({
path: '/detail',
query: {
id
}
})
}
}
}
</script>
其中的数据格式化代码
/**
* @description: 获取导出时的表头数据和表格数据
* @param {*} { sourceData:后端返回的源数据,header:表格头中因为对应关系}
* @return {*}
*/
// 处理函数中对key判断如果发生当前它是聘用形式 通过枚举做一下处理 返回中文
// 枚举处理函数 根据1/2返回正式或者非正式
function transEmployment(value) {
const TYPES = {
1: '正式',
2: '非正式'
}
return TYPES[value]
}
export function getExportData(sourceData, headerRelation) {
const data = sourceData.map(item => {
const arr = []
Object.values(headerRelation).forEach(key => {
// 关键位置:把所有的value不做任何处理直接扔到了数组中 导致excel是源数据
// 如果是当前要处理的是聘用形式 就先转化一步再添加到数组中
if (key === 'formOfEmployment') {
const formatValue = transEmployment(item[key])
arr.push(formatValue)
} else {
arr.push(item[key])
}
})
return arr
})
return {
data
}
}
/**
* @description: 获取导入时的处理之后的接口数据
* @param {*} results
* @return {*}
*/
export function getImportJsData(results, headerRelation) {
const newArr = []
// 将所有的中文key转换成英文key 然后添加到新数组中
results.forEach(item => {
const map = {}
Object.keys(item).forEach(key => {
map[headerRelation[key]] = item[key]
})
newArr.push(map)
})
// 时间处理
newArr.forEach(item => {
Object.keys(item).forEach(key => {
if (key === 'timeOfEntry') {
item[key] = new Date(formatDate(item[key], '/'))
}
})
})
return newArr
}
export function formatDate(numb, format) {
const time = new Date((numb - 1) * 24 * 3600000 + 1)
time.setYear(time.getFullYear() - 70)
const year = time.getFullYear() + ''
const month = time.getMonth() + 1 + ''
const date = time.getDate() - 1 + ''
if (format && format.length === 1) {
return year + format + (month < 10 ? '0' + month : month) + format + (date < 10 ? '0' + date : date)
}
return year + (month < 10 ? '0' + month : month) + (date < 10 ? '0' + date : date)
}
下载Excel表格的俩种方式
前端主导方案图
后端主导方案图