因为原先平台绑定设备是通过一个界面进行人工选择绑定或一个人一个人绑定设备。如下:
但有时候需要在几千个里选择出几百个,那这种方式就不大现实了,需要另外一种方法。
目前相到可以通过导入批量数据进行绑定的方式。
一、前端
主要是显示选择文件与设备
<template>
<div class="import-bind" v-loading="fullscreenLoading" element-loading-text="文件上传中">
<div class="detail">
导入说明:本功能为批量导入用户绑定设备用,每次导入名单建议100名左右,要求导入的用户已经存在了。
</div>
<div class="form-row">
<div class="name">资料导入</div>
<input id="file" style="display:none" type="file" @change="fileChosen" />
<el-input v-model="fileName" :disabled="true" style="width:260px;margin-left:20px"></el-input>
<el-button type="primary" @click="getFile()" style="width:130px;margin-left:20px">选择文件</el-button><a
href="http://face.oss-cn-qingdao.aliyuncs.com/FRS/data_template/201709/fabc5813-e589-4e99-9bd7-22b3c09a54.xlsx">
<el-button type="primary" style="width:150px;margin-left:15px">资料模版下载</el-button></a>
</div><span v-show="fileTip1" style="color:red;margin-left:30px;">文件格式错误,请提交xls或xlsx格式文件</span>
<div class="form-row">
<div class="name">识别设备</div>
<select-devices-popup v-model="devId"></select-devices-popup>
</div>
<el-button type="primary" @click="uploadFirstFile()"
style="width:120px;margin-left:137px;margin-top:50px;">确定</el-button>
<el-dialog title="提示" :visible.sync="dialogVisible" :before-close="handleClose">
<div v-if="portReady"><span>导入成功!</span></div>
<div v-else=""><span>导入失败!</span><span>导入数据存在问题,请修改后重新上传。查看</span><span style="color:#00A1E9;cursor:pointer"
@click="gotoErrorDetail">错误明细</span></div>
<el-button type="primary" @click="dialogVisible = false" style="width:120px;margin-top:50px;">确 定</el-button>
<el-button type="cancel" @click="dialogVisible = false" style="width:120px;margin-top:50px;">取 消</el-button>
</el-dialog>
</div>
</template>
<script>
import appApi from '@/common/js/allApi.js'
import $ from 'jquery'
import selectDevicesPopup from '@/components/select-devices-popup.vue'
export default {
components: {
selectDevicesPopup,
},
data() {
return {
fileList: [],
fileName: '',
largeFile: '',
singleFile: 1024 * 1024, //单次上传大小
tempPath: '',
counter: 0,
missTimeMax: 0, //单次上传最大丢包次数
devId: '',
excelPath: '',
fileTip1: false,
dialogVisible: false,
portReady: false,
fullscreenLoading: false
}
},
mounted() {},
methods: {
getFile: function() {
document.getElementById('file').click()
},
fileChosen: function() {
var fname = document.getElementById('file').files[0].name
this.fileName = fname
var type = fname.split('.')
var filetype = type[type.length - 1]
if (filetype != 'xls' && filetype != 'xlsx') {
this.fileTip1 = true
} else {
this.fileTip1 = false
}
},
//先传小文件
uploadFirstFile: function() {
var vm = this
if (this.fileName != '') {
if (
this.fileTip1 == true
) {
} else {
var file = document.getElementById('file').files[0]
var size = file.size
var data = new FormData()
data.append('file', file)
data.append('fileName', file.name)
data.append('filePath', '')
data.append('isFirst', 'true')
data.append('start', '0')
data.append('fileSplitSize', size)
// data.append('loginId', sessionStorage.getItem('birdloginid'));
vm.fullscreenLoading = true
$.ajax({
processData: false, // 告诉jquery不要处理发送的数据
contentType: false, // 告诉jquery不要设置content-Type请求头
url: appApi.importStaff, //员工管理里更改的,从大文件上传-》上传文件
type: 'POST',
headers: { token: sessionStorage.token },
data: data,
success: function(msg) {
console.log("uploadFirstFile msg=",msg);
if (msg.code == '1') {
vm.excelPath = msg.data.filePath
if (msg.data.currentSize == size) {
vm.tempPath = ''
vm.counter = 0
vm.importBind()
} else {
vm.tempPath = msg.data.filePath
vm.missTimeMax = 0
vm.counter++
vm.uploadFirstFile()
}
} else {
if (vm.missTimeMax < 10) {
vm.missTimeMax++
vm.uploadFirstFile()
} else {
vm.fullscreenLoading = false
vm.$message({
type: 'warning',
message: '当前网络不稳定,请重试!'
})
}
}
},
error: function(error) {
vm.fullscreenLoading = false
}
})
}
} else {
vm.$message({
type: 'error',
message: '请同时上传基础资料和头像!'
})
}
},
//后台输入绑定解析文件
importBind: function() {
var vm = this
var data = {
companyId: sessionStorage.companyId,
excelPath: this.excelPath,
devId: this.devId,
}
$.ajax({
url: appApi.importBind,
type: 'POST',
data: data,
headers: { token: sessionStorage.token },
success: function(msg) {
vm.fullscreenLoading = false
if (msg.code == '0') {
//文件内容错误
vm.$message({
type: 'error',
message: msg.message
})
} else if (msg.code == '1') {
//成功
vm.dialogVisible = true
vm.portReady = true
} else if (msg.code == '2') {
if(!msg.data) {
vm.$message({
type: 'error',
message: msg.message
})
} else {
//有错误数据
vm.dialogVisible = true
vm.portReady = false
window.dataList = msg.data.dataList
window.imgList = msg.data.imgMap
}
}
},
error: function(xhr, type, errorThrown) {}
})
},
gotoErrorDetail() {
this.$router.push({
path: '/error-log'
})
},
handleClose() {}
}
}
</script>
<style scoped lang='stylus'>
.import-bind
padding-left 15px
.detail
padding-top 15px
.form-row
margin-left 30px
margin-top 50px
.name
display inline-block
width 90px
text-align right
.select-devices-popup
display inline-block
margin-left 20px
.list {
list-style: none;
}
ul li {
margin-bottom: 10px;
}
.head-submit {
cursor: pointer;
height: 140px;
width: 140px;
border: 2px dashed #ccc;
border-radius: 3px;
margin-left: 110px;
margin-top: -70px;
text-align: center;
line-height: 140px;
}
.el-dialog__body > .el-button--primary {
margin-left: calc(50% - 130px);
}
</style>
界面如下:
二、后端代码
接口代码
@PostMapping("/importBind")
@ApiOperation("批量导入员工数据绑定设备")
public ResultBean<?> importBind(@ApiParam(name = "excelPath", value = "基础信息文件存储URL", required = true) @RequestParam String excelPath,
@ApiParam(name = "companyId", value = "企业ID", required = true) @RequestParam Integer companyId,
@ApiParam(name = "devId", value = "设备ID(','分隔)") @RequestParam(required = false) String devId) {
// 错误信息存储列表
List<UserErrorInfo> userErrorList = new ArrayList<>();
List<String> imgErrorList = new ArrayList<>();
Assert.notNull(companyId, ReturnCode.Params_Error);
userService.importBind(companyId, getLoginId(), excelPath, userErrorList, imgErrorList, devId);
// 返回结果
if (userErrorList.size() == 0 && imgErrorList.size() == 0) {
return Results.success();
} else {
Map<String, Object> errorLists = new HashMap<>();
errorLists.put("dataList", userErrorList);
errorLists.put("imgMap", imgErrorList);
return new ResultBean<>(2, ReturnCode.File_Exist_Error_Data.getDetail(), errorLists);
}
}
绑定的主要逻辑如下:
@Override
public void importBind(Integer companyId, Integer loginId, String excelPath, List<UserErrorInfo> userErrorList,
List<String> imgErrorList, String devId) {
// 1. 解析EXCEL数据映射成原始数据信息列表
List<Map<String, Object>> dataList = parseExcelToRawdata(excelPath);
// 2. 过滤原始数据信息, 并转换成员工信息列表
List<User> users = filterToUsersForBind(companyId, loginId, dataList, userErrorList);
// 3. 批量绑定设备
if(users.size()>0)
{
batchBind(users,devId);
}
}
@Transactional
@OperLogInject("批量绑定员工信息")
public void batchBind(List<User> users, String devId) {
if (!devId.isEmpty() && !users.isEmpty()) {
String userId = String.join(",", users.stream().map(u -> u.getId().toString()).collect(Collectors.toList()));
try {
ResultBean<?> bindResult = devService.bindUser(devId,null, userId, true,1);
Assert.isTrue(bindResult.getCode() == 1, ReturnCode.User_Bind_Error);
} catch (Exception e) {
throw new CustomException(ReturnCode.User_Bind_Error);
}
}
}