因为原先平台绑定设备是通过一个界面进行人工选择绑定或一个人一个人绑定设备。如下:
但有时候需要在几千个里选择出几百个,那这种方式就不大现实了,需要另外一种方法。
目前相到可以通过导入批量数据进行绑定的方式。
一、前端
主要是显示选择文件与设备
<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); } } }