package com.jeesite.modules.mes.service; import cn.hutool.extra.qrcode.QrCodeUtil; import com.jeesite.common.codec.DesUtils; import com.jeesite.common.collect.ListUtils; import com.jeesite.common.config.Global; import com.jeesite.common.lang.DateUtils; import com.jeesite.common.lang.StringUtils; import com.jeesite.common.utils.excel.ExcelExport; import com.jeesite.modules.mes.entity.MesLineProcessUser; import com.jeesite.modules.mes.entity.MesUserAuthExport; import com.jeesite.modules.sys.dao.UserRoleDao; import com.jeesite.modules.sys.entity.EmpUser; import com.jeesite.modules.sys.entity.Role; import com.jeesite.modules.sys.entity.User; import com.jeesite.modules.sys.entity.UserRole; import com.jeesite.modules.sys.service.EmpUserService; import com.jeesite.modules.sys.service.RoleService; import com.jeesite.modules.sys.service.UserService; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.ClientAnchor; import org.apache.poi.ss.usermodel.Drawing; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.util.Units; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** * 员工权限导出 Service */ @Service public class MesEmpUserExportService { private static final int QRCODE_COLUMN_INDEX = 2; private static final int QRCODE_SIZE = 200; private static final int QRCODE_DISPLAY_SIZE_PX = 120; private static final float QRCODE_ROW_HEIGHT = 95F; private static final float MIN_ROW_HEIGHT = 15F; private static final float LINE_HEIGHT = 15F; /** ExcelExport 会先写标题行和表头行,数据从第 3 行开始 */ private static final int DATA_ROW_OFFSET = 2; private static final int[] COLUMN_WIDTH_CHARS = {14, 18, 22, 50}; private static final String MULTI_VALUE_SEPARATOR = "、"; @Autowired private EmpUserService empUserService; @Autowired private UserService userService; @Autowired private RoleService roleService; @Autowired private UserRoleDao userRoleDao; @Autowired private MesLineProcessUserService mesLineProcessUserService; /** * 组装员工权限导出数据(一行一个用户) */ public List findUserAuthExportList() { List userList = empUserService.findList(new EmpUser()); if (ListUtils.isEmpty(userList)) { return new ArrayList<>(); } Map loginCodeMap = buildLoginCodeMap(userList); Map roleNameMap = buildRoleNameMap(); Map> userRoleMap = buildUserRoleMap(roleNameMap); Map> userOprnoMap = buildUserOprnoMap(); String secretKey = Global.getConfig("shiro.loginSubmit.secretKey"); List result = new ArrayList<>(); for (EmpUser user : userList) { if (user == null || StringUtils.isBlank(user.getUserCode())) { continue; } MesUserAuthExport row = new MesUserAuthExport(); row.setUserName(user.getUserName()); row.setRoleNames(joinList(userRoleMap.get(user.getUserCode()))); row.setOprnoAuth(defaultDisplay(formatOprnos(userOprnoMap.get(user.getUserCode())))); String loginCode = loginCodeMap.get(user.getUserCode()); if (StringUtils.isNotBlank(loginCode)) { row.setQrcode(DesUtils.encode(loginCode, secretKey)); } result.add(row); } return result; } /** * 导出员工权限 Excel(二维码列嵌入图片) */ public void exportUserAuth(HttpServletResponse response) { List list = findUserAuthExportList(); List qrcodeContents = new ArrayList<>(list.size()); for (MesUserAuthExport row : list) { qrcodeContents.add(row.getQrcode()); row.setQrcode(""); } String fileName = "员工权限导出" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx"; try (ExcelExport ee = new ExcelExport("员工权限导出", MesUserAuthExport.class)) { ee.setDataList(list); finalizeExportSheet(ee.getWorkbook(), list.size(), qrcodeContents); ee.write(response, fileName); } } private void finalizeExportSheet(Workbook workbook, int dataSize, List qrcodeContents) { if (workbook == null || dataSize <= 0) { return; } Sheet sheet = workbook.getNumberOfSheets() > 0 ? workbook.getSheetAt(0) : null; if (sheet == null) { return; } for (int i = 0; i < COLUMN_WIDTH_CHARS.length; i++) { sheet.setColumnWidth(i, COLUMN_WIDTH_CHARS[i] * 256); } Drawing drawing = sheet.createDrawingPatriarch(); for (int i = 0; i < dataSize; i++) { int rowIndex = i + DATA_ROW_OFFSET; Row row = sheet.getRow(rowIndex); if (row == null) { continue; } float textHeight = MIN_ROW_HEIGHT; for (int col = 0; col < COLUMN_WIDTH_CHARS.length; col++) { if (col == QRCODE_COLUMN_INDEX) { continue; } Cell cell = row.getCell(col); if (cell == null) { continue; } applyWrapStyle(workbook, cell); textHeight = Math.max(textHeight, calculateWrapHeight(getCellStringValue(cell), COLUMN_WIDTH_CHARS[col])); } boolean hasQrcode = i < qrcodeContents.size() && StringUtils.isNotBlank(qrcodeContents.get(i)); float rowHeight = Math.max(textHeight, hasQrcode ? QRCODE_ROW_HEIGHT : MIN_ROW_HEIGHT); row.setHeightInPoints(rowHeight); if (hasQrcode) { appendQrcodeImage(workbook, drawing, row, rowIndex, qrcodeContents.get(i)); } } } private void applyWrapStyle(Workbook workbook, Cell cell) { CellStyle style = workbook.createCellStyle(); CellStyle existing = cell.getCellStyle(); if (existing != null) { style.cloneStyleFrom(existing); } style.setWrapText(true); style.setVerticalAlignment(VerticalAlignment.CENTER); style.setAlignment(HorizontalAlignment.CENTER); cell.setCellStyle(style); } private void appendQrcodeImage(Workbook workbook, Drawing drawing, Row row, int rowIndex, String content) { Cell cell = row.getCell(QRCODE_COLUMN_INDEX); if (cell == null) { cell = row.createCell(QRCODE_COLUMN_INDEX); } cell.setCellValue(""); byte[] pngBytes = QrCodeUtil.generatePng(content, QRCODE_SIZE, QRCODE_SIZE); int pictureIndex = workbook.addPicture(pngBytes, Workbook.PICTURE_TYPE_PNG); int margin = Units.pixelToEMU(4); int size = Units.pixelToEMU(QRCODE_DISPLAY_SIZE_PX); ClientAnchor anchor = drawing.createAnchor(margin, margin, margin + size, margin + size, QRCODE_COLUMN_INDEX, rowIndex, QRCODE_COLUMN_INDEX, rowIndex); drawing.createPicture(anchor, pictureIndex); } private float calculateWrapHeight(String text, int columnWidthChars) { if (StringUtils.isBlank(text)) { return MIN_ROW_HEIGHT; } int maxLineLength = Math.max(columnWidthChars, 1); String[] lines = text.split("\\R"); int totalLines = 0; for (String line : lines) { totalLines += Math.max(1, (int) Math.ceil((double) line.length() / maxLineLength)); } return Math.min(totalLines * LINE_HEIGHT + 5F, 409F); } private String getCellStringValue(Cell cell) { if (cell == null) { return ""; } if (cell.getCellType() == CellType.STRING) { return cell.getStringCellValue(); } if (cell.getCellType() == CellType.NUMERIC) { return String.valueOf(cell.getNumericCellValue()); } return ""; } private Map buildLoginCodeMap(List userList) { Map loginCodeMap = new HashMap<>(); for (EmpUser user : userList) { if (user == null || StringUtils.isBlank(user.getUserCode())) { continue; } if (StringUtils.isNotBlank(user.getLoginCode())) { loginCodeMap.put(user.getUserCode(), user.getLoginCode()); continue; } User fullUser = userService.get(user.getUserCode()); if (fullUser != null && StringUtils.isNotBlank(fullUser.getLoginCode())) { loginCodeMap.put(user.getUserCode(), fullUser.getLoginCode()); } } return loginCodeMap; } private Map buildRoleNameMap() { Map roleNameMap = new HashMap<>(); List roleList = roleService.findList(new Role()); if (ListUtils.isEmpty(roleList)) { return roleNameMap; } for (Role role : roleList) { if (role != null && StringUtils.isNotBlank(role.getRoleCode())) { roleNameMap.put(role.getRoleCode(), StringUtils.defaultString(role.getRoleName(), role.getRoleCode())); } } return roleNameMap; } private Map> buildUserRoleMap(Map roleNameMap) { Map> userRoleMap = new HashMap<>(); List userRoleList = userRoleDao.findList(new UserRole()); if (ListUtils.isEmpty(userRoleList)) { return userRoleMap; } for (UserRole userRole : userRoleList) { if (userRole == null || StringUtils.isBlank(userRole.getUserCode())) { continue; } String roleName = roleNameMap.getOrDefault(userRole.getRoleCode(), userRole.getRoleCode()); userRoleMap.computeIfAbsent(userRole.getUserCode(), k -> new ArrayList<>()).add(roleName); } return userRoleMap; } private Map> buildUserOprnoMap() { return mesLineProcessUserService.findList(new MesLineProcessUser()).stream() .filter(item -> item != null && StringUtils.isNotBlank(item.getUserCode())) .collect(Collectors.groupingBy(MesLineProcessUser::getUserCode)); } private String formatOprnos(List processUsers) { if (ListUtils.isEmpty(processUsers)) { return ""; } Set items = new LinkedHashSet<>(); for (MesLineProcessUser processUser : processUsers) { if (processUser != null && StringUtils.isNotBlank(processUser.getOprno())) { items.add(processUser.getOprno()); } } return joinSet(items); } private String joinList(List list) { if (ListUtils.isEmpty(list)) { return ""; } return String.join(MULTI_VALUE_SEPARATOR, list); } private String joinSet(Set set) { if (set == null || set.isEmpty()) { return ""; } return String.join(MULTI_VALUE_SEPARATOR, set); } private String defaultDisplay(String value) { return StringUtils.isBlank(value) ? "无" : value; } }