From 4e3a045a42b48b943aa5366c7c2fe991f4556309 Mon Sep 17 00:00:00 2001 From: andy <1042025947@qq.com> Date: Sat, 12 Jul 2025 11:57:47 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=AF=BC=E5=87=BA,=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8E=A8=E9=80=81=E9=87=91=E8=9D=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- evo-admin/pom.xml | 9 + .../java/com/evo/common/annotation/Excel.java | 13 +- .../java/com/evo/common/utils/ParamUtils.java | 2 +- .../com/evo/common/utils/poi/ExcelUtil.java | 2 + .../com/evo/common/utils/poi/ExcelUtil1.java | 1889 +++++++++++++++++ .../poi/handler/ExcelFieldHandlerAdapter.java | 20 + .../{ => handler}/ExcelHandlerAdapter.java | 2 +- .../SysStaffExcelFieldHandlerAdapter.java | 30 + .../evo/kingdeeUtils/KingdeeRequestUtils.java | 109 + .../exception/KingdeeException.java | 29 + .../com/evo/kingdeeUtils/kenum/BaseEnum.java | 24 + .../kingdeeUtils/kenum/KingdeeParamsEnum.java | 97 + .../kingdeeUtils/mapper/LogKingDeeMapper.java | 16 + .../com/evo/kingdeeUtils/vo/LogKingDee.java | 38 + .../controller/RzSubsidyInfoController.java | 2 - .../domain/RzSubsidyInfo.java | 3 + .../system/controller/SysStaffController.java | 14 +- .../java/com/evo/system/domain/SysStaff.java | 2 + .../com/evo/system/domain/vo/SysStaffVo.java | 698 +----- .../evo/system/service/ISysStaffService.java | 8 + .../service/impl/SysStaffServiceImpl.java | 83 +- .../lib/k3cloud-webapi-sdk-java11-v8.2.0.jar | Bin 0 -> 57197 bytes .../mapper/system/SysStaffMapper.xml | 5 +- 23 files changed, 2397 insertions(+), 698 deletions(-) create mode 100644 evo-admin/src/main/java/com/evo/common/utils/poi/ExcelUtil1.java create mode 100644 evo-admin/src/main/java/com/evo/common/utils/poi/handler/ExcelFieldHandlerAdapter.java rename evo-admin/src/main/java/com/evo/common/utils/poi/{ => handler}/ExcelHandlerAdapter.java (92%) create mode 100644 evo-admin/src/main/java/com/evo/common/utils/poi/handler/impl/SysStaffExcelFieldHandlerAdapter.java create mode 100644 evo-admin/src/main/java/com/evo/kingdeeUtils/KingdeeRequestUtils.java create mode 100644 evo-admin/src/main/java/com/evo/kingdeeUtils/exception/KingdeeException.java create mode 100644 evo-admin/src/main/java/com/evo/kingdeeUtils/kenum/BaseEnum.java create mode 100644 evo-admin/src/main/java/com/evo/kingdeeUtils/kenum/KingdeeParamsEnum.java create mode 100644 evo-admin/src/main/java/com/evo/kingdeeUtils/mapper/LogKingDeeMapper.java create mode 100644 evo-admin/src/main/java/com/evo/kingdeeUtils/vo/LogKingDee.java create mode 100644 evo-admin/src/main/resources/lib/k3cloud-webapi-sdk-java11-v8.2.0.jar diff --git a/evo-admin/pom.xml b/evo-admin/pom.xml index 7906769..ae0e554 100644 --- a/evo-admin/pom.xml +++ b/evo-admin/pom.xml @@ -214,6 +214,15 @@ nashorn-core 15.4 + + + + com.kingdee.bos + k3cloud-webapi-sdk-java11 + v8.2.0 + system + ${project.basedir}/src/main/resources/lib/k3cloud-webapi-sdk-java11-v8.2.0.jar + diff --git a/evo-admin/src/main/java/com/evo/common/annotation/Excel.java b/evo-admin/src/main/java/com/evo/common/annotation/Excel.java index 1e58bbc..b147861 100644 --- a/evo-admin/src/main/java/com/evo/common/annotation/Excel.java +++ b/evo-admin/src/main/java/com/evo/common/annotation/Excel.java @@ -5,9 +5,11 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.math.BigDecimal; + +import com.evo.common.utils.poi.handler.ExcelFieldHandlerAdapter; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.IndexedColors; -import com.evo.common.utils.poi.ExcelHandlerAdapter; +import com.evo.common.utils.poi.handler.ExcelHandlerAdapter; /** * 自定义导出Excel数据注解 @@ -148,6 +150,15 @@ public @interface Excel */ public Class handler() default ExcelHandlerAdapter.class; + /** + * 自定义数据处理器 + */ + public boolean customExcelField() default false; + /** + * 自定义数据处理器 + */ + public Class excelFieldHandler() default ExcelFieldHandlerAdapter.class; + /** * 自定义数据处理器参数 */ diff --git a/evo-admin/src/main/java/com/evo/common/utils/ParamUtils.java b/evo-admin/src/main/java/com/evo/common/utils/ParamUtils.java index b14e87a..210844a 100644 --- a/evo-admin/src/main/java/com/evo/common/utils/ParamUtils.java +++ b/evo-admin/src/main/java/com/evo/common/utils/ParamUtils.java @@ -284,7 +284,7 @@ public class ParamUtils { * @return */ public static List getFullPaidLeave(){ - RzSysParam param= paramService.getRzSysParam("全薪发放的假期", "full_paid_leave","54,56,58,59,60","全薪发放的假期; 54-年休假,56-婚假,58-陪产假,59-丧假,60-工伤假"); + RzSysParam param= paramService.getRzSysParam("全薪发放的假期", "full_paid_leave","54,56,57,58,59,60","全薪发放的假期; 54-年休假, 56-婚假,57-产假,58-陪产假,59-丧假,60-工伤假 (55-调休假 这是个特殊的假期, 加班会自动抵扣)"); return Collections.asList(param.getParamValue().split(",")).stream().filter(StringUtils::isNotEmpty).map(Long::valueOf).collect(Collectors.toList()); } diff --git a/evo-admin/src/main/java/com/evo/common/utils/poi/ExcelUtil.java b/evo-admin/src/main/java/com/evo/common/utils/poi/ExcelUtil.java index 2733761..f7771bb 100644 --- a/evo-admin/src/main/java/com/evo/common/utils/poi/ExcelUtil.java +++ b/evo-admin/src/main/java/com/evo/common/utils/poi/ExcelUtil.java @@ -24,6 +24,8 @@ import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; + +import com.evo.common.utils.poi.handler.ExcelHandlerAdapter; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.reflect.FieldUtils; diff --git a/evo-admin/src/main/java/com/evo/common/utils/poi/ExcelUtil1.java b/evo-admin/src/main/java/com/evo/common/utils/poi/ExcelUtil1.java new file mode 100644 index 0000000..0b19ce3 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/common/utils/poi/ExcelUtil1.java @@ -0,0 +1,1889 @@ +package com.evo.common.utils.poi; + +import com.evo.common.annotation.Excel; +import com.evo.common.annotation.Excel.ColumnType; +import com.evo.common.annotation.Excel.Type; +import com.evo.common.annotation.Excels; +import com.evo.common.config.EvoConfig; +import com.evo.common.core.domain.AjaxResult; +import com.evo.common.core.text.Convert; +import com.evo.common.exception.UtilException; +import com.evo.common.utils.Collections; +import com.evo.common.utils.DateUtils; +import com.evo.common.utils.DictUtils; +import com.evo.common.utils.StringUtils; +import com.evo.common.utils.file.FileTypeUtils; +import com.evo.common.utils.file.FileUtils; +import com.evo.common.utils.file.ImageUtils; +import com.evo.common.utils.poi.handler.ExcelHandlerAdapter; +import com.evo.common.utils.reflect.ReflectUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.RegExUtils; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.apache.poi.hssf.usermodel.*; +import org.apache.poi.ooxml.POIXMLDocumentPart; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.*; +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Excel相关处理 + * + * @author evo + */ +public class ExcelUtil1 +{ + private static final Logger log = LoggerFactory.getLogger(ExcelUtil1.class); + + public static final String FORMULA_REGEX_STR = "=|-|\\+|@"; + + public static final String[] FORMULA_STR = { "=", "-", "+", "@" }; + + /** + * 用于dictType属性数据存储,避免重复查缓存 + */ + public Map sysDictMap = new HashMap(); + + /** + * Excel sheet最大行数,默认65536 + */ + public static final int sheetSize = 65536; + + /** + * 工作表名称 + */ + private String sheetName; + + /** + * 导出类型(EXPORT:导出数据;IMPORT:导入模板) + */ + private Type type; + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 导入导出数据列表 + */ + private List list; + + /** + * 注解列表 + */ + private List fields; + + /** + * 当前行号 + */ + private int rownum; + + /** + * 标题 + */ + private String title; + + /** + * 最大高度 + */ + private short maxHeight; + + /** + * 合并后最后行数 + */ + private int subMergedLastRowNum = 0; + + /** + * 合并后开始行数 + */ + private int subMergedFirstRowNum = 1; + + /** + * 对象的子列表方法 + */ + private Method subMethod; + + /** + * 对象的子列表属性 + */ + private List subFields; + + /** + * 统计列表 + */ + private Map statistics = new HashMap(); + + /** + * 数字格式 + */ + private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); + + /** + * 实体对象 + */ + public Class clazz; + + /** + * 需要排除列属性 + */ + public String[] excludeFields; + + /** + */ + private Integer tsSize = 0; + + private Map> customTitleMap; + + public ExcelUtil1(Class clazz) + { + this.clazz = clazz; + } + + /** + * 隐藏Excel中列属性 + * + * @param fields 列属性名 示例[单个"name"/多个"id","name"] + * @throws Exception + */ + public void hideColumn(String... fields) + { + this.excludeFields = fields; + } + + public void init(List list, String sheetName, String title, Type type) + { + if (list == null) + { + list = new ArrayList(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + this.title = title; + createExcelField(); + createWorkbook(); + createCustom(); + createTitle(); + createSubHead(); + } + + /** + * 获取特殊数据 + */ + public void createCustom(){ + for (Object[] objects : fields) + { + Excel attr = (Excel) objects[1]; + if(attr.customExcelField()){ + if(customTitleMap == null){ + customTitleMap = Collections.emptyMap(); + } + List titles = buildExcelFieldHandler(attr); + customTitleMap.put(attr.name(), titles); + tsSize = tsSize + titles.size(); + } + + } + } + + public List buildExcelFieldHandler(Excel excel){ + try + { + Object instance = excel.excelFieldHandler().newInstance(); + Method formatMethod = excel.excelFieldHandler().getMethod("buildExcel"); + return (List) formatMethod.invoke(instance); + } + catch (Exception e) + { + e.printStackTrace(); + log.error("不能格式化数据 " + excel.handler(), e.getMessage()); + } + return Collections.emptyList(); + } + + /** + * 创建excel第一行标题 + */ + public void createTitle() + { + if (StringUtils.isNotEmpty(title)) + { + subMergedFirstRowNum++; + subMergedLastRowNum++; + int titleLastCol = this.fields.size() - 1 + tsSize; + if (isSubList()) + { + titleLastCol = titleLastCol + subFields.size() - 1; + } + Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0); + titleRow.setHeightInPoints(30); + Cell titleCell = titleRow.createCell(0); + titleCell.setCellStyle(styles.get("title")); + titleCell.setCellValue(title); + sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol)); + } + } + + /** + * 创建对象的子列表名称 + */ + public void createSubHead() + { + if (isSubList()) + { + subMergedFirstRowNum++; + subMergedLastRowNum++; + Row subRow = sheet.createRow(rownum); + int excelNum = 0; + for (Object[] objects : fields) + { + Excel attr = (Excel) objects[1]; + Cell headCell1 = subRow.createCell(excelNum); + headCell1.setCellValue(attr.name()); + headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + excelNum++; + } + int headFirstRow = excelNum - 1; + int headLastRow = headFirstRow + subFields.size() - 1; + if (headLastRow > headFirstRow) + { + sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow)); + } + rownum++; + } + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(InputStream is) + { + List list = null; + try + { + list = importExcel(is, 0); + } + catch (Exception e) + { + log.error("导入Excel异常{}", e.getMessage()); + throw new UtilException(e.getMessage()); + } + finally + { + IOUtils.closeQuietly(is); + } + return list; + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @param titleNum 标题占用行数 + * @return 转换后集合 + */ + public List importExcel(InputStream is, int titleNum) throws Exception + { + return importExcel(StringUtils.EMPTY, is, titleNum); + } + + /** + * 对excel表单指定表格索引名转换成list + * + * @param sheetName 表格索引名 + * @param titleNum 标题占用行数 + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(String sheetName, InputStream is, int titleNum) throws Exception + { + this.type = Type.IMPORT; + this.wb = WorkbookFactory.create(is); + List list = new ArrayList(); + // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet + Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0); + if (sheet == null) + { + throw new IOException("文件sheet不存在"); + } + boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook); + Map pictures; + if (isXSSFWorkbook) + { + pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb); + } + else + { + pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb); + } + // 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1 + int rows = sheet.getLastRowNum(); + if (rows > 0) + { + // 定义一个map用于存放excel列的序号和field. + Map cellMap = new HashMap(); + // 获取表头 + Row heard = sheet.getRow(titleNum); + for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) + { + Cell cell = heard.getCell(i); + if (StringUtils.isNotNull(cell)) + { + String value = this.getCellValue(heard, i).toString(); + cellMap.put(value, i); + } + else + { + cellMap.put(null, i); + } + } + // 有数据时才处理 得到类的所有field. + List fields = this.getFields(); + Map fieldsMap = new HashMap(); + for (Object[] objects : fields) + { + Excel attr = (Excel) objects[1]; + Integer column = cellMap.get(attr.name()); + if (column != null) + { + fieldsMap.put(column, objects); + } + } + for (int i = titleNum + 1; i <= rows; i++) + { + // 从第2行开始取数据,默认第一行是表头. + Row row = sheet.getRow(i); + // 判断当前行是否是空行 + if (isRowEmpty(row)) + { + continue; + } + T entity = null; + for (Map.Entry entry : fieldsMap.entrySet()) + { + Object val = this.getCellValue(row, entry.getKey()); + + // 如果不存在实例则新建. + entity = (entity == null ? clazz.newInstance() : entity); + // 从map中得到对应列的field. + Field field = (Field) entry.getValue()[0]; + Excel attr = (Excel) entry.getValue()[1]; + // 取得类型,并根据对象类型设置值. + Class fieldType = field.getType(); + if (String.class == fieldType) + { + String s = Convert.toStr(val); + if (StringUtils.endsWith(s, ".0")) + { + val = StringUtils.substringBefore(s, ".0"); + } + else + { + String dateFormat = field.getAnnotation(Excel.class).dateFormat(); + if (StringUtils.isNotEmpty(dateFormat)) + { + val = parseDateToStr(dateFormat, val); + } + else + { + val = Convert.toStr(val); + } + } + } + else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) + { + val = Convert.toInt(val); + } + else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) + { + val = Convert.toLong(val); + } + else if (Double.TYPE == fieldType || Double.class == fieldType) + { + val = Convert.toDouble(val); + } + else if (Float.TYPE == fieldType || Float.class == fieldType) + { + val = Convert.toFloat(val); + } + else if (BigDecimal.class == fieldType) + { + val = Convert.toBigDecimal(val); + } + else if (Date.class == fieldType) + { + if (val instanceof String) + { + val = DateUtils.parseDate(val); + } + else if (val instanceof Double) + { + val = DateUtil.getJavaDate((Double) val); + } + } + else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) + { + val = Convert.toBool(val, false); + } + if (StringUtils.isNotNull(fieldType)) + { + String propertyName = field.getName(); + if (StringUtils.isNotEmpty(attr.targetAttr())) + { + propertyName = field.getName() + "." + attr.targetAttr(); + } + if (StringUtils.isNotEmpty(attr.readConverterExp())) + { + val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); + } + else if (StringUtils.isNotEmpty(attr.dictType())) + { + if (!sysDictMap.containsKey(attr.dictType() + val)) + { + String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); + sysDictMap.put(attr.dictType() + val, dictValue); + } + val = sysDictMap.get(attr.dictType() + val); + } + else if (!attr.handler().equals(ExcelHandlerAdapter.class)) + { + val = dataFormatHandlerAdapter(val, attr, null); + } + else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) + { + PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey()); + if (image == null) + { + val = ""; + } + else + { + byte[] data = image.getData(); + val = FileUtils.writeImportBytes(data); + } + } + ReflectUtils.invokeSetter(entity, propertyName, val); + } + } + list.add(entity); + } + } + return list; + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult exportExcel(List list, String sheetName) + { + return exportExcel(list, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public AjaxResult exportExcel(List list, String sheetName, String title) + { + this.init(list, sheetName, title, Type.EXPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName) + { + exportExcel(response, list, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName, String title) + { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(list, sheetName, title, Type.EXPORT); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult importTemplateExcel(String sheetName) + { + return importTemplateExcel(sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public AjaxResult importTemplateExcel(String sheetName, String title) + { + this.init(null, sheetName, title, Type.IMPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public void importTemplateExcel(HttpServletResponse response, String sheetName) + { + importTemplateExcel(response, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public void importTemplateExcel(HttpServletResponse response, String sheetName, String title) + { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(null, sheetName, title, Type.IMPORT); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public void exportExcel(HttpServletResponse response) + { + try + { + writeSheet(); + wb.write(response.getOutputStream()); + } + catch (Exception e) + { + log.error("导出Excel异常{}", e.getMessage()); + } + finally + { + IOUtils.closeQuietly(wb); + } + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public AjaxResult exportExcel() + { + OutputStream out = null; + try + { + writeSheet(); + String filename = encodingFilename(sheetName); + out = new FileOutputStream(getAbsoluteFile(filename)); + wb.write(out); + return AjaxResult.success(filename); + } + catch (Exception e) + { + log.error("导出Excel异常{}", e.getMessage()); + throw new UtilException("导出Excel失败,请联系网站管理员!"); + } + finally + { + IOUtils.closeQuietly(wb); + IOUtils.closeQuietly(out); + } + } + + /** + * 创建写入数据到Sheet + */ + public void writeSheet() + { + // 取出一共有多少个sheet. + int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize)); + for (int index = 0; index < sheetNo; index++) + { + createSheet(sheetNo, index); + + // 产生一行 + Row row = sheet.createRow(rownum); + int column = 0; + // 写入各个字段的列头名称 + for (Object[] os : fields) + { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType())) + { + for (Field subField : subFields) + { + Excel subExcel = subField.getAnnotation(Excel.class); + this.createHeadCell(null, subExcel, row, column++); + } + }else if(excel.customExcelField()){ + for (String title : customTitleMap.get(excel.name())){ + this.createHeadCell(title, excel, row, column++); + } + } + else + { + this.createHeadCell(null, excel, row, column++); + } + } + if (Type.EXPORT.equals(type)) + { + fillExcelData(index, row); + addStatisticsRow(); + } + } + } + + /** + * 填充excel数据 + * + * @param index 序号 + * @param row 单元格行 + */ + @SuppressWarnings("unchecked") + public void fillExcelData(int index, Row row) + { + int startNo = index * sheetSize; + int endNo = Math.min(startNo + sheetSize, list.size()); + int rowNo = (1 + rownum) - startNo; + for (int i = startNo; i < endNo; i++) + { + rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo; + row = sheet.createRow(rowNo); + // 得到导出对象. + T vo = (T) list.get(i); + Collection subList = null; + if (isSubList()) + { + if (isSubListValue(vo)) + { + subList = getListCellValue(vo); + subMergedLastRowNum = subMergedLastRowNum + subList.size(); + } + else + { + subMergedFirstRowNum++; + subMergedLastRowNum++; + } + } + int column = 0; + for (Object[] os : fields){ + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList)) + { + boolean subFirst = false; + for (Object obj : subList) + { + if (subFirst) + { + rowNo++; + row = sheet.createRow(rowNo); + } + List subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class); + int subIndex = 0; + for (Field subField : subFields) + { + if (subField.isAnnotationPresent(Excel.class)) + { + subField.setAccessible(true); + Excel attr = subField.getAnnotation(Excel.class); + this.addCell(attr, row, (T) obj, subField, column + subIndex); + } + subIndex++; + } + subFirst = true; + } + this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size(); + }else if(excel.customExcelField()){ + for (String title : customTitleMap.get(excel.name())){ + this.addCell(title, excel, row, vo, field, column++); + } + } + else + { + this.addCell(excel, row, vo, field, column++); + } + } + } + } + + /** + * 创建表格样式 + * + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) + { + // 写入各条记录,每条记录对应excel表中的一行 + Map styles = new HashMap(); + CellStyle style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font titleFont = wb.createFont(); + titleFont.setFontName("Arial"); + titleFont.setFontHeightInPoints((short) 16); + titleFont.setBold(true); + style.setFont(titleFont); + DataFormat dataFormat = wb.createDataFormat(); + style.setDataFormat(dataFormat.getFormat("@")); + styles.put("title", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font totalFont = wb.createFont(); + totalFont.setFontName("Arial"); + totalFont.setFontHeightInPoints((short) 10); + style.setFont(totalFont); + styles.put("total", style); + + styles.putAll(annotationHeaderStyles(wb, styles)); + + styles.putAll(annotationDataStyles(wb)); + + return styles; + } + + /** + * 根据Excel注解创建表格头样式 + * + * @param wb 工作薄对象 + * @return 自定义样式列表 + */ + private Map annotationHeaderStyles(Workbook wb, Map styles) + { + Map headerStyles = new HashMap(); + for (Object[] os : fields) + { + Excel excel = (Excel) os[1]; + String key = StringUtils.format("header_{}_{}", excel.headerColor(), excel.headerBackgroundColor()); + if (!headerStyles.containsKey(key)) + { + CellStyle style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(excel.headerBackgroundColor().index); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBold(true); + headerFont.setColor(excel.headerColor().index); + style.setFont(headerFont); + // 设置表格头单元格文本形式 + DataFormat dataFormat = wb.createDataFormat(); + style.setDataFormat(dataFormat.getFormat("@")); + headerStyles.put(key, style); + } + } + return headerStyles; + } + + /** + * 根据Excel注解创建表格列样式 + * + * @param wb 工作薄对象 + * @return 自定义样式列表 + */ + private Map annotationDataStyles(Workbook wb) + { + Map styles = new HashMap(); + for (Object[] os : fields) + { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType())) + { + ParameterizedType pt = (ParameterizedType) field.getGenericType(); + Class subClass = (Class) pt.getActualTypeArguments()[0]; + List subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class); + for (Field subField : subFields) + { + Excel subExcel = subField.getAnnotation(Excel.class); + annotationDataStyles(styles, subField, subExcel); + } + } + else + { + annotationDataStyles(styles, field, excel); + } + } + return styles; + } + + /** + * 根据Excel注解创建表格列样式 + * + * @param styles 自定义样式列表 + * @param field 属性列信息 + * @param excel 注解信息 + */ + public void annotationDataStyles(Map styles, Field field, Excel excel) + { + String key = StringUtils.format("data_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType()); + if (!styles.containsKey(key)) + { + CellStyle style = wb.createCellStyle(); + style.setAlignment(excel.align()); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setFillForegroundColor(excel.backgroundColor().getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + dataFont.setColor(excel.color().index); + style.setFont(dataFont); + if (ColumnType.TEXT == excel.cellType()) + { + DataFormat dataFormat = wb.createDataFormat(); + style.setDataFormat(dataFormat.getFormat("@")); + } + styles.put(key, style); + } + } + + /** + * 创建单元格 + */ + public Cell createHeadCell(String title, Excel attr, Row row, int column) + { + // 创建列 + Cell cell = row.createCell(column); + // 写入列信息 + cell.setCellValue(((attr.customExcelField() && StringUtils.isNotEmpty(title)) ? title : attr.name())); + setDataValidation(attr, row, column); + cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + if (isSubList()) + { + // 填充默认样式,防止合并单元格样式失效 + sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType()))); + if (attr.needMerge()) + { + sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column)); + } + } + return cell; + } + + /** + * 设置单元格信息 + * + * @param value 单元格值 + * @param attr 注解相关 + * @param cell 单元格信息 + */ + public void setCellVo(Object value, Excel attr, Cell cell) + { + if (ColumnType.STRING == attr.cellType() || ColumnType.TEXT == attr.cellType()) + { + String cellValue = Convert.toStr(value); + // 对于任何以表达式触发字符 =-+@开头的单元格,直接使用tab字符作为前缀,防止CSV注入。 + if (StringUtils.startsWithAny(cellValue, FORMULA_STR)) + { + cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0"); + } + if (value instanceof Collection && StringUtils.equals("[]", cellValue)) + { + cellValue = StringUtils.EMPTY; + } + cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix()); + } + else if (ColumnType.NUMERIC == attr.cellType()) + { + if (StringUtils.isNotNull(value)) + { + cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); + } + } + else if (ColumnType.IMAGE == attr.cellType()) + { + ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); + String imagePath = Convert.toStr(value); + if (StringUtils.isNotEmpty(imagePath)) + { + byte[] data = ImageUtils.getImage(imagePath); + getDrawingPatriarch(cell.getSheet()).createPicture(anchor, + cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); + } + } + } + + /** + * 获取画布 + */ + public static Drawing getDrawingPatriarch(Sheet sheet) + { + if (sheet.getDrawingPatriarch() == null) + { + sheet.createDrawingPatriarch(); + } + return sheet.getDrawingPatriarch(); + } + + /** + * 获取图片类型,设置图片插入类型 + */ + public int getImageType(byte[] value) + { + String type = FileTypeUtils.getFileExtendName(value); + if ("JPG".equalsIgnoreCase(type)) + { + return Workbook.PICTURE_TYPE_JPEG; + } + else if ("PNG".equalsIgnoreCase(type)) + { + return Workbook.PICTURE_TYPE_PNG; + } + return Workbook.PICTURE_TYPE_JPEG; + } + + /** + * 创建表格样式 + */ + public void setDataValidation(Excel attr, Row row, int column) + { + if (attr.name().indexOf("注:") >= 0) + { + sheet.setColumnWidth(column, 6000); + } + else + { + // 设置列宽 + sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); + } + if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0 || attr.comboReadDict()) + { + String[] comboArray = attr.combo(); + if (attr.comboReadDict()) + { + if (!sysDictMap.containsKey("combo_" + attr.dictType())) + { + String labels = DictUtils.getDictLabels(attr.dictType()); + sysDictMap.put("combo_" + attr.dictType(), labels); + } + String val = sysDictMap.get("combo_" + attr.dictType()); + comboArray = StringUtils.split(val, DictUtils.SEPARATOR); + } + if (comboArray.length > 15 || StringUtils.join(comboArray).length() > 255) + { + // 如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到 + setXSSFValidationWithHidden(sheet, comboArray, attr.prompt(), 1, 100, column, column); + } + else + { + // 提示信息或只能选择不能输入的列内容. + setPromptOrValidation(sheet, comboArray, attr.prompt(), 1, 100, column, column); + } + } + } + + /** + * 添加单元格 + */ + public Cell addCell(String title, Excel attr, Row row, T vo, Field field, int column) + { + Cell cell = null; + try + { + // 设置行高 + row.setHeight(maxHeight); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) + { + // 创建cell + cell = row.createCell(column); + if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) + { + CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column); + sheet.addMergedRegion(cellAddress); + } + cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType()))); + + // 用于读取对象中的属性 + Object value = getTargetValue(title, vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + String separator = attr.separator(); + String dictType = attr.dictType(); + if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) + { + cell.setCellValue(parseDateToStr(dateFormat, value)); + } + else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) + { + cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); + } + else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) + { + if (!sysDictMap.containsKey(dictType + value)) + { + String lable = convertDictByExp(Convert.toStr(value), dictType, separator); + sysDictMap.put(dictType + value, lable); + } + cell.setCellValue(sysDictMap.get(dictType + value)); + } + else if (value instanceof BigDecimal && -1 != attr.scale()) + { + cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue()); + } + else if (!attr.handler().equals(ExcelHandlerAdapter.class)) + { + cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell)); + } + else + { + // 设置列类型 + setCellVo(value, attr, cell); + } + addStatisticsData(column, Convert.toStr(value), attr); + } + } + catch (Exception e) + { + log.error("导出Excel失败{}", e); + } + return cell; + } + + + /** + * 添加单元格 + */ + public Cell addCell(Excel attr, Row row, T vo, Field field, int column) + { + Cell cell = null; + try + { + // 设置行高 + row.setHeight(maxHeight); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) + { + // 创建cell + cell = row.createCell(column); + if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) + { + CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column); + sheet.addMergedRegion(cellAddress); + } + cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType()))); + + // 用于读取对象中的属性 + Object value = getTargetValue(null, vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + String separator = attr.separator(); + String dictType = attr.dictType(); + if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) + { + cell.setCellValue(parseDateToStr(dateFormat, value)); + } + else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) + { + cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); + } + else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) + { + if (!sysDictMap.containsKey(dictType + value)) + { + String lable = convertDictByExp(Convert.toStr(value), dictType, separator); + sysDictMap.put(dictType + value, lable); + } + cell.setCellValue(sysDictMap.get(dictType + value)); + } + else if (value instanceof BigDecimal && -1 != attr.scale()) + { + cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue()); + } + else if (!attr.handler().equals(ExcelHandlerAdapter.class)) + { + cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell)); + } + else + { + // 设置列类型 + setCellVo(value, attr, cell); + } + addStatisticsData(column, Convert.toStr(value), attr); + } + } + catch (Exception e) + { + log.error("导出Excel失败{}", e); + } + return cell; + } + + /** + * 设置 POI XSSFSheet 单元格提示或选择框 + * + * @param sheet 表单 + * @param textlist 下拉框显示的内容 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, + int firstCol, int endCol) + { + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1"); + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + DataValidation dataValidation = helper.createValidation(constraint, regions); + if (StringUtils.isNotEmpty(promptContent)) + { + // 如果设置了提示信息则鼠标放上去提示 + dataValidation.createPromptBox("", promptContent); + dataValidation.setShowPromptBox(true); + } + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) + { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } + else + { + dataValidation.setSuppressDropDownArrow(false); + } + sheet.addValidationData(dataValidation); + } + + /** + * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框). + * + * @param sheet 要设置的sheet. + * @param textlist 下拉框显示的内容 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol) + { + String hideSheetName = "combo_" + firstCol + "_" + endCol; + Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据 + for (int i = 0; i < textlist.length; i++) + { + hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]); + } + // 创建名称,可被其他单元格引用 + Name name = wb.createName(); + name.setNameName(hideSheetName + "_data"); + name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length); + DataValidationHelper helper = sheet.getDataValidationHelper(); + // 加载下拉列表内容 + DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data"); + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, regions); + if (StringUtils.isNotEmpty(promptContent)) + { + // 如果设置了提示信息则鼠标放上去提示 + dataValidation.createPromptBox("", promptContent); + dataValidation.setShowPromptBox(true); + } + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) + { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } + else + { + dataValidation.setSuppressDropDownArrow(false); + } + + sheet.addValidationData(dataValidation); + // 设置hiddenSheet隐藏 + wb.setSheetHidden(wb.getSheetIndex(hideSheet), true); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) + { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) + { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) + { + for (String value : propertyValue.split(separator)) + { + if (itemArray[0].equals(value)) + { + propertyString.append(itemArray[1] + separator); + break; + } + } + } + else + { + if (itemArray[0].equals(propertyValue)) + { + return itemArray[1]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) + { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) + { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) + { + for (String value : propertyValue.split(separator)) + { + if (itemArray[1].equals(value)) + { + propertyString.append(itemArray[0] + separator); + break; + } + } + } + else + { + if (itemArray[1].equals(propertyValue)) + { + return itemArray[0]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 解析字典值 + * + * @param dictValue 字典值 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String convertDictByExp(String dictValue, String dictType, String separator) + { + return DictUtils.getDictLabel(dictType, dictValue, separator); + } + + /** + * 反向解析值字典值 + * + * @param dictLabel 字典标签 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典值 + */ + public static String reverseDictByExp(String dictLabel, String dictType, String separator) + { + return DictUtils.getDictValue(dictType, dictLabel, separator); + } + + /** + * 数据处理器 + * + * @param value 数据值 + * @param excel 数据注解 + * @return + */ + public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell) + { + try + { + Object instance = excel.handler().newInstance(); + Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class, Cell.class, Workbook.class }); + value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb); + } + catch (Exception e) + { + log.error("不能格式化数据 " + excel.handler(), e.getMessage()); + } + return Convert.toStr(value); + } + + /** + * 合计统计信息 + */ + private void addStatisticsData(Integer index, String text, Excel entity) + { + if (entity != null && entity.isStatistics()) + { + Double temp = 0D; + if (!statistics.containsKey(index)) + { + statistics.put(index, temp); + } + try + { + temp = Double.valueOf(text); + } + catch (NumberFormatException e) + { + } + statistics.put(index, statistics.get(index) + temp); + } + } + + /** + * 创建统计行 + */ + public void addStatisticsRow() + { + if (statistics.size() > 0) + { + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + Set keys = statistics.keySet(); + Cell cell = row.createCell(0); + cell.setCellStyle(styles.get("total")); + cell.setCellValue("合计"); + + for (Integer key : keys) + { + cell = row.createCell(key); + cell.setCellStyle(styles.get("total")); + cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); + } + statistics.clear(); + } + } + + /** + * 编码文件名 + */ + public String encodingFilename(String filename) + { + filename = UUID.randomUUID() + "_" + filename + ".xlsx"; + return filename; + } + + /** + * 获取下载路径 + * + * @param filename 文件名称 + */ + public String getAbsoluteFile(String filename) + { + String downloadPath = EvoConfig.getDownloadPath() + filename; + File desc = new File(downloadPath); + if (!desc.getParentFile().exists()) + { + desc.getParentFile().mkdirs(); + } + return downloadPath; + } + + /** + * 获取bean中的属性值 + * + * @param vo 实体对象 + * @param field 字段 + * @param excel 注解 + * @return 最终的属性值 + * @throws Exception + */ + private Object getTargetValue(String title, T vo, Field field, Excel excel) throws Exception + { + Object o = field.get(vo); + if (StringUtils.isNotEmpty(excel.targetAttr())){ + String target = excel.targetAttr(); + if (target.contains(".")) + { + String[] targets = target.split("[.]"); + for (String name : targets) + { + o = getValue(o, name); + } + } + else + { + o = getValue(o, target); + } + } + if(excel.customExcelField() && StringUtils.isNotEmpty(title)){ + o = ((Map)o).get(title); + } + return o; + } + + /** + * 以类的属性的get方法方法形式获取值 + * + * @param o + * @param name + * @return value + * @throws Exception + */ + private Object getValue(Object o, String name) throws Exception + { + if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) + { + Class clazz = o.getClass(); + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + o = field.get(o); + } + return o; + } + + /** + * 得到所有定义字段 + */ + private void createExcelField() + { + this.fields = getFields(); + this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); + this.maxHeight = getRowHeight(); + } + + /** + * 获取字段注解信息 + */ + public List getFields() + { + List fields = new ArrayList(); + List tempFields = new ArrayList<>(); + tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); + tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); + for (Field field : tempFields) + { + if (!ArrayUtils.contains(this.excludeFields, field.getName())) + { + // 单注解 + if (field.isAnnotationPresent(Excel.class)) + { + Excel attr = field.getAnnotation(Excel.class); + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) + { + field.setAccessible(true); + fields.add(new Object[] { field, attr }); + } + if (Collection.class.isAssignableFrom(field.getType())) + { + subMethod = getSubMethod(field.getName(), clazz); + ParameterizedType pt = (ParameterizedType) field.getGenericType(); + Class subClass = (Class) pt.getActualTypeArguments()[0]; + this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class); + } + } + + // 多注解 + if (field.isAnnotationPresent(Excels.class)) + { + Excels attrs = field.getAnnotation(Excels.class); + Excel[] excels = attrs.value(); + for (Excel attr : excels) + { + if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr()) + && (attr != null && (attr.type() == Type.ALL || attr.type() == type))) + { + field.setAccessible(true); + fields.add(new Object[] { field, attr }); + } + } + } + } + } + return fields; + } + + /** + * 根据注解获取最大行高 + */ + public short getRowHeight() + { + double maxHeight = 0; + for (Object[] os : this.fields) + { + Excel excel = (Excel) os[1]; + maxHeight = Math.max(maxHeight, excel.height()); + } + return (short) (maxHeight * 20); + } + + /** + * 创建一个工作簿 + */ + public void createWorkbook() + { + this.wb = new SXSSFWorkbook(500); + this.sheet = wb.createSheet(); + wb.setSheetName(0, sheetName); + this.styles = createStyles(wb); + } + + /** + * 创建工作表 + * + * @param sheetNo sheet数量 + * @param index 序号 + */ + public void createSheet(int sheetNo, int index) + { + // 设置工作表的名称. + if (sheetNo > 1 && index > 0) + { + this.sheet = wb.createSheet(); + this.createTitle(); + wb.setSheetName(index, sheetName + index); + } + } + + /** + * 获取单元格值 + * + * @param row 获取的行 + * @param column 获取单元格列号 + * @return 单元格值 + */ + public Object getCellValue(Row row, int column) + { + if (row == null) + { + return row; + } + Object val = ""; + try + { + Cell cell = row.getCell(column); + if (StringUtils.isNotNull(cell)) + { + if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) + { + val = cell.getNumericCellValue(); + if (DateUtil.isCellDateFormatted(cell)) + { + val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 + } + else + { + if ((Double) val % 1 != 0) + { + val = new BigDecimal(val.toString()); + } + else + { + val = new DecimalFormat("0").format(val); + } + } + } + else if (cell.getCellType() == CellType.STRING) + { + val = cell.getStringCellValue(); + } + else if (cell.getCellType() == CellType.BOOLEAN) + { + val = cell.getBooleanCellValue(); + } + else if (cell.getCellType() == CellType.ERROR) + { + val = cell.getErrorCellValue(); + } + + } + } + catch (Exception e) + { + return val; + } + return val; + } + + /** + * 判断是否是空行 + * + * @param row 判断的行 + * @return + */ + private boolean isRowEmpty(Row row) + { + if (row == null) + { + return true; + } + for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) + { + Cell cell = row.getCell(i); + if (cell != null && cell.getCellType() != CellType.BLANK) + { + return false; + } + } + return true; + } + + /** + * 获取Excel2003图片 + * + * @param sheet 当前sheet对象 + * @param workbook 工作簿对象 + * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData + */ + public static Map getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook) + { + Map sheetIndexPicMap = new HashMap(); + List pictures = workbook.getAllPictures(); + if (!pictures.isEmpty()) + { + for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) + { + HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor(); + if (shape instanceof HSSFPicture) + { + HSSFPicture pic = (HSSFPicture) shape; + int pictureIndex = pic.getPictureIndex() - 1; + HSSFPictureData picData = pictures.get(pictureIndex); + String picIndex = anchor.getRow1() + "_" + anchor.getCol1(); + sheetIndexPicMap.put(picIndex, picData); + } + } + return sheetIndexPicMap; + } + else + { + return sheetIndexPicMap; + } + } + + /** + * 获取Excel2007图片 + * + * @param sheet 当前sheet对象 + * @param workbook 工作簿对象 + * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData + */ + public static Map getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook) + { + Map sheetIndexPicMap = new HashMap(); + for (POIXMLDocumentPart dr : sheet.getRelations()) + { + if (dr instanceof XSSFDrawing) + { + XSSFDrawing drawing = (XSSFDrawing) dr; + List shapes = drawing.getShapes(); + for (XSSFShape shape : shapes) + { + if (shape instanceof XSSFPicture) + { + XSSFPicture pic = (XSSFPicture) shape; + XSSFClientAnchor anchor = pic.getPreferredSize(); + CTMarker ctMarker = anchor.getFrom(); + String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol(); + sheetIndexPicMap.put(picIndex, pic.getPictureData()); + } + } + } + } + return sheetIndexPicMap; + } + + /** + * 格式化不同类型的日期对象 + * + * @param dateFormat 日期格式 + * @param val 被格式化的日期对象 + * @return 格式化后的日期字符 + */ + public String parseDateToStr(String dateFormat, Object val) + { + if (val == null) + { + return ""; + } + String str; + if (val instanceof Date) + { + str = DateUtils.parseDateToStr(dateFormat, (Date) val); + } + else if (val instanceof LocalDateTime) + { + str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val)); + } + else if (val instanceof LocalDate) + { + str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val)); + } + else + { + str = val.toString(); + } + return str; + } + + /** + * 是否有对象的子列表 + */ + public boolean isSubList() + { + return StringUtils.isNotNull(subFields) && subFields.size() > 0; + } + + /** + * 是否有对象的子列表,集合不为空 + */ + public boolean isSubListValue(T vo) + { + return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0; + } + + /** + * 获取集合的值 + */ + public Collection getListCellValue(Object obj) + { + Object value; + try + { + value = subMethod.invoke(obj, new Object[] {}); + } + catch (Exception e) + { + return new ArrayList(); + } + return (Collection) value; + } + + /** + * 获取对象的子列表方法 + * + * @param name 名称 + * @param pojoClass 类对象 + * @return 子列表方法 + */ + public Method getSubMethod(String name, Class pojoClass) + { + StringBuffer getMethodName = new StringBuffer("get"); + getMethodName.append(name.substring(0, 1).toUpperCase()); + getMethodName.append(name.substring(1)); + Method method = null; + try + { + method = pojoClass.getMethod(getMethodName.toString(), new Class[] {}); + } + catch (Exception e) + { + log.error("获取对象异常{}", e.getMessage()); + } + return method; + } +} diff --git a/evo-admin/src/main/java/com/evo/common/utils/poi/handler/ExcelFieldHandlerAdapter.java b/evo-admin/src/main/java/com/evo/common/utils/poi/handler/ExcelFieldHandlerAdapter.java new file mode 100644 index 0000000..5b4e2b7 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/common/utils/poi/handler/ExcelFieldHandlerAdapter.java @@ -0,0 +1,20 @@ +package com.evo.common.utils.poi.handler; + +import com.evo.common.annotation.Excel; + +import java.lang.reflect.Field; +import java.util.List; + +/** + * 特殊出具处理接口 + * + * @ClassName:ExcelFieldHandlerAdapter + * @date: 2025年07月12日 10:40 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface ExcelFieldHandlerAdapter { + + List buildExcel(); +} diff --git a/evo-admin/src/main/java/com/evo/common/utils/poi/ExcelHandlerAdapter.java b/evo-admin/src/main/java/com/evo/common/utils/poi/handler/ExcelHandlerAdapter.java similarity index 92% rename from evo-admin/src/main/java/com/evo/common/utils/poi/ExcelHandlerAdapter.java rename to evo-admin/src/main/java/com/evo/common/utils/poi/handler/ExcelHandlerAdapter.java index c911b71..e90efde 100644 --- a/evo-admin/src/main/java/com/evo/common/utils/poi/ExcelHandlerAdapter.java +++ b/evo-admin/src/main/java/com/evo/common/utils/poi/handler/ExcelHandlerAdapter.java @@ -1,4 +1,4 @@ -package com.evo.common.utils.poi; +package com.evo.common.utils.poi.handler; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Workbook; diff --git a/evo-admin/src/main/java/com/evo/common/utils/poi/handler/impl/SysStaffExcelFieldHandlerAdapter.java b/evo-admin/src/main/java/com/evo/common/utils/poi/handler/impl/SysStaffExcelFieldHandlerAdapter.java new file mode 100644 index 0000000..b89caef --- /dev/null +++ b/evo-admin/src/main/java/com/evo/common/utils/poi/handler/impl/SysStaffExcelFieldHandlerAdapter.java @@ -0,0 +1,30 @@ +package com.evo.common.utils.poi.handler.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.evo.common.constant.Constants; +import com.evo.common.utils.Collections; +import com.evo.common.utils.poi.handler.ExcelFieldHandlerAdapter; +import com.evo.common.utils.spring.SpringUtils; +import com.evo.personnelMatters.domain.RzSubsidyInfo; +import com.evo.personnelMatters.mapper.RzSubsidyInfoMapper; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 类 + * + * @ClassName:SysStaffExcelFieldHandlerAdapter + * @date: 2025年07月12日 10:42 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +public class SysStaffExcelFieldHandlerAdapter implements ExcelFieldHandlerAdapter { + @Override + public List buildExcel() { + return SpringUtils.getBean(RzSubsidyInfoMapper.class).selectList(new LambdaQueryWrapper().eq(RzSubsidyInfo::getDelFlag, Constants.DELETE_FLAG_0)).stream().map(RzSubsidyInfo::getName).collect(Collectors.toList()); + } +} diff --git a/evo-admin/src/main/java/com/evo/kingdeeUtils/KingdeeRequestUtils.java b/evo-admin/src/main/java/com/evo/kingdeeUtils/KingdeeRequestUtils.java new file mode 100644 index 0000000..b5201bb --- /dev/null +++ b/evo-admin/src/main/java/com/evo/kingdeeUtils/KingdeeRequestUtils.java @@ -0,0 +1,109 @@ +package com.evo.kingdeeUtils; + +import com.alibaba.fastjson2.JSON; +import com.evo.common.utils.DateUtils; +import com.evo.common.utils.spring.SpringUtils; +import com.evo.kingdeeUtils.exception.KingdeeException; +import com.evo.kingdeeUtils.kenum.BaseEnum; +import com.evo.kingdeeUtils.kenum.KingdeeParamsEnum; +import com.evo.kingdeeUtils.mapper.LogKingDeeMapper; +import com.evo.kingdeeUtils.vo.LogKingDee; +import com.kingdee.bos.webapi.sdk.K3CloudApi; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 类 + * + * @ClassName:KingdeeRequestUtils + * @date: 2025年07月11日 9:33 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +@Slf4j +public class KingdeeRequestUtils { + + /*** + * 员工保存接口 + * @param params + * 参数说明对照关系: key-value + * FName-员工姓名 + * FStaffNumber-员工编号 + * FNumber-岗位编号 + * FPostDept_FNumber_岗位所属部门编号 + */ + public static void employeeSave(Map params){ +// request(params, KingdeeParamsEnum.Employee.SAVE); + } + + /*** + * 员工禁用接口 + * @param params + * 参数说明对照关系: key-value + * Numbers-员工编码 (多个使用,分割, 即: 001,002,003) + */ + public static void employeeDisabled(Map params){ +// request(params, KingdeeParamsEnum.Employee.DISABLED); + } + + /*** + * 岗位调整 + * @param params + * 参数说明对照关系: key-value + * NeedUpDateFields-更新字段 (多个使用,分割, 如:FDept_FNumber,FPosition_FNumber ) + * FNumber-员工编号 + * FDept_FNumber-部门编号 + * FPosition_FNumber-岗位编号 + */ + public static void updateJobInfo(Map params){ +// request(params, KingdeeParamsEnum.JobInfo.UPDATE); + } + + private static void request(Map params, BaseEnum paramEnum){ + log.error("{}====> 接口调用, 参数为:{} ", paramEnum.getDes(), JSON.toJSONString(params)); + List keyList = params.entrySet().stream().map(Map.Entry::getKey).collect(Collectors.toList()); + Map requiredParams = paramEnum.getRequiredParams(); + for (String key : requiredParams.keySet()){ + if(!keyList.contains(key)){ + throw new KingdeeException(requiredParams.get(key)); + } + } + String requestParam = paramEnum.getParamJson(); + for (String key : params.keySet()){ + requestParam = requestParam.replaceAll(key+ KingdeeParamsEnum.REQUEST_PARAM_SUFFIX, params.get(key)); + } + //更新时间 + requestParam = requestParam.replaceAll("date"+KingdeeParamsEnum.REQUEST_PARAM_SUFFIX, DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date())); + String resultJson = ""; + try { + K3CloudApi client = new K3CloudApi(); + resultJson = client.save(paramEnum.getFromId(), requestParam); + log.info("{}====>接口返回结果: {}", paramEnum.getDes(), resultJson); + + } catch (Exception e) { + resultJson = e.getMessage(); + log.error("{}====>请求错误: {}", paramEnum.getDes(), e.getMessage()); + }finally { + //记录日志 + instLog(paramEnum, params, requestParam, resultJson); + } + } + + + private static void instLog(BaseEnum paramEnum, Map params, String requestInfo, String response){ + LogKingDee logKingDee = new LogKingDee(); + logKingDee.setRequestTime(new Date()); + logKingDee.setType(paramEnum.getDes()); + logKingDee.setRequestParams(JSON.toJSONString(params)); + logKingDee.setRequestInfo(requestInfo); + logKingDee.setResponse(response); + SpringUtils.getBean(LogKingDeeMapper.class).insert(logKingDee); + } + +} diff --git a/evo-admin/src/main/java/com/evo/kingdeeUtils/exception/KingdeeException.java b/evo-admin/src/main/java/com/evo/kingdeeUtils/exception/KingdeeException.java new file mode 100644 index 0000000..c7fdab4 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/kingdeeUtils/exception/KingdeeException.java @@ -0,0 +1,29 @@ +package com.evo.kingdeeUtils.exception; + +import lombok.extern.slf4j.Slf4j; + +/** + * 类 + * + * @ClassName:KingdeeException + * @date: 2025年07月11日 10:02 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +public class KingdeeException extends RuntimeException{ + + public KingdeeException(String message){ + super(message); + log.error("推送金蝶出现错误---->>>>>>>{}", message); + } + + + public KingdeeException(String message, Throwable e) + { + super(message, e); + log.error("推送金蝶出现错误---->>>>>>>错误信息{}, 异常信息:{}", message, e.getMessage()); + } + +} diff --git a/evo-admin/src/main/java/com/evo/kingdeeUtils/kenum/BaseEnum.java b/evo-admin/src/main/java/com/evo/kingdeeUtils/kenum/BaseEnum.java new file mode 100644 index 0000000..ff2dd55 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/kingdeeUtils/kenum/BaseEnum.java @@ -0,0 +1,24 @@ +package com.evo.kingdeeUtils.kenum; + +import java.util.Map; + +/** + * 枚举 + * @ClassName:BaseEnum + * @date: 2025年07月11日 10:26 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface BaseEnum { + + + + abstract Map getRequiredParams(); + + abstract String getParamJson(); + + abstract String getFromId(); + + abstract String getDes(); +} diff --git a/evo-admin/src/main/java/com/evo/kingdeeUtils/kenum/KingdeeParamsEnum.java b/evo-admin/src/main/java/com/evo/kingdeeUtils/kenum/KingdeeParamsEnum.java new file mode 100644 index 0000000..1335b0d --- /dev/null +++ b/evo-admin/src/main/java/com/evo/kingdeeUtils/kenum/KingdeeParamsEnum.java @@ -0,0 +1,97 @@ +package com.evo.kingdeeUtils.kenum; + +import com.evo.common.utils.Collections; + +import java.util.Map; + +/** + * 金蝶请求的参数类枚举 + * + * @ClassName:KingdeeRequest + * @date: 2025年07月11日 8:59 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public enum KingdeeParamsEnum { + + ; + + Enum paramEnum; + + + KingdeeParamsEnum() { + } + + KingdeeParamsEnum(Enum paramEnum) { + this.paramEnum = paramEnum; + } + + public static final String REQUEST_PARAM_SUFFIX="_param"; + + public enum JobInfo implements BaseEnum{ + UPDATE("岗位信息修改", "BD_NEWSTAFF", Collections.asMap("FNumber","员工编号不能为空","FDept_FNumber","部门编号不能为空","FPosition_FNumber","岗位编号不能为空"),"{\"NeedUpDateFields\":[NeedUpDateFields"+REQUEST_PARAM_SUFFIX+"],\"NeedReturnFields\":[],\"IsDeleteEntry\":\"true\",\"SubSystemId\":\"\",\"IsVerifyBaseDataField\":\"false\",\"IsEntryBatchFill\":\"true\",\"ValidateFlag\":\"true\",\"NumberSearch\":\"true\",\"IsAutoAdjustField\":\"true\",\"InterationFlags\":\"\",\"IgnoreInterationFlag\":\"\",\"IsControlPrecision\":\"false\",\"ValidateRepeatJson\":\"false\",\"Model\":{\"FSTAFFID\":0,\"FNumber\":\"FNumber"+REQUEST_PARAM_SUFFIX+"\",\"FPerson\":{\"FNumber\":\"FNumber"+REQUEST_PARAM_SUFFIX+"\"},\"FDept\":{\"FNumber\":\"FDept_FNumber"+REQUEST_PARAM_SUFFIX+"\"},\"FPosition\":{\"FNumber\":\"FPosition_FNumber"+REQUEST_PARAM_SUFFIX+"\"},\"FStartDate\":\"date"+REQUEST_PARAM_SUFFIX+"\",\"FEmpInfoId\":{\"FNumber\":\"FNumber"+REQUEST_PARAM_SUFFIX+"\"},\"FPOSTBILLEntity\":{\"FIsFirstPost\":false},\"FOtherEntity\":{},\"FSHRMapEntity\":{}}}"), + ; + String des; + String fromId; + Map requiredParams; + String paramJson; + JobInfo(String des, String fromId, Map requiredParams, String paramJson) { + this.des = des; + this.fromId = fromId; + this.requiredParams = requiredParams; + this.paramJson = paramJson; + } + @Override + public Map getRequiredParams() { + return this.requiredParams; + } + @Override + public String getParamJson() { + return this.paramJson; + } + @Override + public String getFromId() { + return this.fromId; + } + @Override + public String getDes() { + return this.des; + } + } + /*** + * 金蝶请求参数, 员工 + */ + public enum Employee implements BaseEnum { + SAVE("员工保存", "BD_Empinfo", Collections.asMap("FName","员工姓名不能为空","FStaffNumber","员工编号不能为空","FNumber","岗位编号不能为空"),"{\"NeedUpDateFields\":[],\"NeedReturnFields\":[],\"IsDeleteEntry\":\"true\",\"SubSystemId\":\"\",\"IsVerifyBaseDataField\":\"false\",\"IsEntryBatchFill\":\"true\",\"ValidateFlag\":\"true\",\"NumberSearch\":\"true\",\"IsAutoAdjustField\":\"true\",\"InterationFlags\":\"\",\"IgnoreInterationFlag\":\"\",\"IsControlPrecision\":\"false\",\"ValidateRepeatJson\":\"false\",\"Model\":{\"FID\":0,\"FName\":\"FName"+REQUEST_PARAM_SUFFIX+"\",\"FStaffNumber\":\"FStaffNumber"+REQUEST_PARAM_SUFFIX+"\",\"FCreateSaler\":false,\"FCreateUser\":false,\"FCreateCashier\":false,\"FJoinDate\":\"date"+REQUEST_PARAM_SUFFIX+"\",\"FSHRMapEntity\":{},\"FPostEntity\":[{\"FPostDept\":{\"FNumber\":\"FPostDept_FNumber"+REQUEST_PARAM_SUFFIX+"\"},\"FPost\":{\"FNumber\":\"FNumber"+REQUEST_PARAM_SUFFIX+"\"},\"FStaffStartDate\":\"date"+REQUEST_PARAM_SUFFIX+"\",\"FIsFirstPost\":true,\"FStaffDetails\":0}]}}"), + DISABLED("员工禁用","BD_Empinfo", Collections.asMap("Numbers","员工编码不能为空"),"{\"Numbers\":[Numbers"+REQUEST_PARAM_SUFFIX+"],\"Ids\":\"\",\"PkEntryIds\":[],\"UseOrgId\":0,\"NetworkCtrl\":\"\",\"IgnoreInterationFlag\":\"\"}") + ; + String des; + String fromId; + Map requiredParams; + String paramJson; + Employee(String des, String fromId, Map requiredParams, String paramJson) { + this.des = des; + this.fromId = fromId; + this.requiredParams = requiredParams; + this.paramJson = paramJson; + } + @Override + public Map getRequiredParams() { + return this.requiredParams; + } + @Override + public String getParamJson() { + return this.paramJson; + } + @Override + public String getFromId() { + return this.fromId; + } + @Override + public String getDes() { + return this.des; + } + } + +} diff --git a/evo-admin/src/main/java/com/evo/kingdeeUtils/mapper/LogKingDeeMapper.java b/evo-admin/src/main/java/com/evo/kingdeeUtils/mapper/LogKingDeeMapper.java new file mode 100644 index 0000000..d8a406f --- /dev/null +++ b/evo-admin/src/main/java/com/evo/kingdeeUtils/mapper/LogKingDeeMapper.java @@ -0,0 +1,16 @@ +package com.evo.kingdeeUtils.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.evo.kingdeeUtils.vo.LogKingDee; + +/** + * 金蝶日志请求接口 + * + * @ClassName:LogKingDeeMapper + * @date: 2025年07月11日 11:18 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface LogKingDeeMapper extends BaseMapper { +} diff --git a/evo-admin/src/main/java/com/evo/kingdeeUtils/vo/LogKingDee.java b/evo-admin/src/main/java/com/evo/kingdeeUtils/vo/LogKingDee.java new file mode 100644 index 0000000..b7042de --- /dev/null +++ b/evo-admin/src/main/java/com/evo/kingdeeUtils/vo/LogKingDee.java @@ -0,0 +1,38 @@ +package com.evo.kingdeeUtils.vo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 请求日志类 + * + * @ClassName:LogKingDee + * @date: 2025年07月11日 11:15 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Data +@TableName("sys_log_king_dee") +public class LogKingDee implements Serializable { + + /** 主键 */ + @TableId(type= IdType.AUTO) + private Long id; + + private String type; + + private String requestParams; + + private String requestInfo; + + private String response; + + private Date requestTime; + +} diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/controller/RzSubsidyInfoController.java b/evo-admin/src/main/java/com/evo/personnelMatters/controller/RzSubsidyInfoController.java index b786cd3..378c9aa 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/controller/RzSubsidyInfoController.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/controller/RzSubsidyInfoController.java @@ -6,10 +6,8 @@ import com.evo.common.core.domain.AjaxResult; import com.evo.common.core.page.TableDataInfo; import com.evo.common.enums.BusinessType; import com.evo.common.utils.poi.ExcelUtil; -import com.evo.personnelMatters.domain.RzSubsidy; import com.evo.personnelMatters.domain.RzSubsidyInfo; import com.evo.personnelMatters.service.IRzSubsidyInfoService; -import com.evo.personnelMatters.service.IRzSubsidyService; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzSubsidyInfo.java b/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzSubsidyInfo.java index 55b31cb..5eee152 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzSubsidyInfo.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzSubsidyInfo.java @@ -1,5 +1,7 @@ package com.evo.personnelMatters.domain; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; import com.evo.common.annotation.Excel; import com.evo.common.core.domain.BaseEntity; import lombok.Data; @@ -39,6 +41,7 @@ public class RzSubsidyInfo extends BaseEntity private String remarks; /** 删除标识 */ + @TableField(fill = FieldFill.INSERT) private String delFlag; @Override diff --git a/evo-admin/src/main/java/com/evo/system/controller/SysStaffController.java b/evo-admin/src/main/java/com/evo/system/controller/SysStaffController.java index aa70fa0..b853f2b 100644 --- a/evo-admin/src/main/java/com/evo/system/controller/SysStaffController.java +++ b/evo-admin/src/main/java/com/evo/system/controller/SysStaffController.java @@ -52,9 +52,9 @@ public class SysStaffController extends BaseController @PostMapping("/export") public void export(HttpServletResponse response, SysStaff sysStaff) { - List list = sysStaffService.selectSysStaffList(sysStaff); - ExcelUtil util = new ExcelUtil(SysStaff.class); - util.exportExcel(response, list, "员工管理数据"); + sysStaffService.exportInfo(response, sysStaff); +// ExcelUtil util = new ExcelUtil(SysStaff.class); +// util.exportExcel(response, list, "员工管理数据"); } /** * 导出员工详情 @@ -63,9 +63,11 @@ public class SysStaffController extends BaseController @PostMapping("/exportDetail") public void exportDetail(HttpServletResponse response, SysStaff sysStaff) { - List list = sysStaffService.selectSysStaffDetailList(sysStaff); - ExcelUtil util = new ExcelUtil(SysStaffVo.class); - util.exportExcel(response, list, "员工详情数据"); + + sysStaffService.exportInfo(response, sysStaff); +// List list = sysStaffService.selectSysStaffDetailList(sysStaff); +// ExcelUtil util = new ExcelUtil(SysStaffVo.class); +// util.exportExcel(response, list, "员工详情数据"); } /** * 获取员工管理详细信息 diff --git a/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java b/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java index 7970078..82371b2 100644 --- a/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java +++ b/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java @@ -47,6 +47,8 @@ public class SysStaff extends BaseEntity @TableField(exist = false) private String deptName; + private String jobCode; + /** 身份证号 */ @Excel(name = "身份证号") private String idCard; diff --git a/evo-admin/src/main/java/com/evo/system/domain/vo/SysStaffVo.java b/evo-admin/src/main/java/com/evo/system/domain/vo/SysStaffVo.java index af3ae11..7e64fa9 100644 --- a/evo-admin/src/main/java/com/evo/system/domain/vo/SysStaffVo.java +++ b/evo-admin/src/main/java/com/evo/system/domain/vo/SysStaffVo.java @@ -1,769 +1,125 @@ package com.evo.system.domain.vo; import com.evo.common.annotation.Excel; +import com.evo.common.utils.poi.handler.impl.SysStaffExcelFieldHandlerAdapter; import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + import java.math.BigDecimal; import java.util.Date; +import java.util.Map; +@Data public class SysStaffVo { - /** 姓名 */ @Excel(name = "* 姓名") private String name; + @Excel(name = "* 公司", dictType = "sys_company") + private String companyName; @Excel(name = "* 部门") private String deptName; - /** 编号 */ @Excel(name = "编号") private String code; - /** 身份证号 */ @Excel(name = "* 身份证号") private String idCard; - /** 性别 */ - @Excel(name = "性别") + @Excel(name = "性别", dictType = "sys_user_sex") private String sex; - /** 年龄 */ @Excel(name = "年龄") private Long age; - /** 电话 */ @Excel(name = "电话") private String phone; - /** 住址 */ @Excel(name = "住址") private String address; - /** 学历 */ - @Excel(name = "* 学历") + @Excel(name = "* 学历", dictType = "sys_level") private String level; - /** 专业 */ - @Excel(name = "专业") - private String major; - /** 毕业学校 */ @Excel(name = "毕业学校") private String school; - /** 银行卡号 */ - @Excel(name = "银行卡号") - private String bankNumber; - /** 开户行 */ + @Excel(name = "专业") + private String major; @Excel(name = "开户行") private String bank; - /** 入职时间 */ + @Excel(name = "银行卡号") + private String bankNumber; + + @Excel(name = "在职状态", dictType = "sys_worker_status") + private String status; @JsonFormat(pattern = "yyyy-MM-dd") @Excel(name = " * 入职时间", width = 30, dateFormat = "yyyy-MM-dd") private Date employmentDate; - /** 全额工资时间 */ - @JsonFormat(pattern = "yyyy-MM-dd") - @Excel(name = "全额工资时间", width = 30, dateFormat = "yyyy-MM-dd") - private Date wagesRatioDate; - /** 履历 */ - @Excel(name = "履历") - private String experience; - /** 试用期限 */ @Excel(name = "试用期限") private Long workerTerm; - /** 转正日期 */ @JsonFormat(pattern = "yyyy-MM-dd") @Excel(name = "转正日期", width = 30, dateFormat = "yyyy-MM-dd") private Date regularDate; - /** 离职时间 */ @JsonFormat(pattern = "yyyy-MM-dd") @Excel(name = "离职时间", width = 30, dateFormat = "yyyy-MM-dd") private Date quitDate; - /** 合同-起 */ @JsonFormat(pattern = "yyyy-MM-dd") @Excel(name = "合同-起", width = 30, dateFormat = "yyyy-MM-dd") private Date contractStart; - /** 合同-止 */ @JsonFormat(pattern = "yyyy-MM-dd") @Excel(name = "合同-止", width = 30, dateFormat = "yyyy-MM-dd") private Date contractEnd; - /** 合同类型 */ - @Excel(name = "* 合同期限") - private String contractType; @Excel(name = "* 是否新农合") private String socialSubsidy; - /** 社保 */ @Excel(name = "* 社保") private String socialType; - /** 工龄 */ @Excel(name = "工龄") private Long seniority; - - /** 是否有加班费 */ - @Excel(name = "* 加班费") - private String isOvertimePay; - /** 住宿标识 */ - @Excel(name = "* 住宿") + @Excel(name = "* 是否住宿") private String zsFlag; - /** 保密合同 */ - @Excel(name = "保密合同") - private String secrecy; - /** 工伤 */ - @Excel(name = "工伤") + @Excel(name = "工伤险") private String injury; - /** 雇主险 */ @Excel(name = "雇主险") private String insurance; - /** 介绍人 */ - @Excel(name = "介绍人") - private String introducer; - /** 是否打卡 */ - @Excel(name = "* 打卡") + @Excel(name = "* 是否打卡") private String clockIn; - /** 在职状态 */ - @Excel(name = "在职状态") - private String status; - @Excel(name = "* 公司") - private String companyName; + + @Excel(name = "基本工资") private BigDecimal basicSalary; - /** 岗位工资 */ @Excel(name = "岗位工资") private BigDecimal jobsSalary; - /** 日薪 */ @Excel(name = "日薪") private BigDecimal dailyWage; - /** 时薪 */ - @Excel(name = "时薪") - private BigDecimal hoursSalary; - /** 全勤奖 */ - @Excel(name = "全勤奖") - private BigDecimal fullFrequentlySubsidies; - /** 学历补助 */ - @Excel(name = "学历补助") - private BigDecimal levelOfEducationSubsidies; - /** 合同补助 */ - @Excel(name = "合同补助") - private BigDecimal contractSubsidies; - /** 工龄补助 */ - @Excel(name = "工龄补助") - private BigDecimal senioritySubsidies; - /** 社保补助 */ - @Excel(name = "社保补助") - private BigDecimal socialSecuritySubsidies; - - @Excel(name = "中班补助") - private BigDecimal middleSubsidies; - /** 夜班补助 */ - @Excel(name = "夜班补助") - private BigDecimal nightShiftSubsidies; - /** 夜餐补助 */ - @Excel(name = "夜餐补助") - private BigDecimal dinnerSubsidies; - /** 固定补助 */ + @Excel(name = "享有补助", customExcelField = true, excelFieldHandler= SysStaffExcelFieldHandlerAdapter.class, defaultValue = "0") + private Map subsidyMap; @Excel(name = "固定补助") private BigDecimal fixedAllowance; - /** 其他补助 */ - @Excel(name = "其他补助") - private BigDecimal otherSubsidies; - /** 早餐消费 */ - @Excel(name = "早餐消费") - private BigDecimal breakfastExpend; - /** 午餐消费 */ - @Excel(name = "午餐消费") - private BigDecimal lunchExpend; - /** 晚餐消费 */ - @Excel(name = "晚餐消费") - private BigDecimal supperExpend; - /** 离职扣款 */ - @Excel(name = "离职扣款") - private BigDecimal subsidyDeductMoney; - /** 其他扣款 */ - @Excel(name = "其他扣款") - private BigDecimal deductions; - /** 养老保险 */ + @Excel(name = "养老保险") private BigDecimal endowmentInsurance; - /** 医疗保险 */ @Excel(name = "医疗保险") private BigDecimal medicalInsurance; - /** 工伤保险 */ @Excel(name = "工伤保险") private BigDecimal employmentInjuryInsurance; - /** 生育保险 */ @Excel(name = "生育保险") private BigDecimal maternityInsurance; - /** 失业保险 */ @Excel(name = "失业保险") private BigDecimal unemploymentInsurance; - /** 公积金 */ @Excel(name = "公积金") private BigDecimal accumulationFund; - /** 子女教育 */ + @Excel(name = "子女教育") private BigDecimal childrenEducation; - /** 赡养老人 */ @Excel(name = "赡养老人") private BigDecimal supportTheOld; - /** 住房贷款 */ @Excel(name = "住房贷款") private BigDecimal housingLoans; - /** 住房租金 */ @Excel(name = "住房租金") private BigDecimal housingRents; - /** 继续教育 */ @Excel(name = "继续教育") private BigDecimal adultEducation; - /** 大病医疗 */ @Excel(name = "大病医疗") private BigDecimal treatmentForSeriousDisease; - /** 本年累计专项附加扣除 */ + @Excel(name = "本年累计专项附加扣除") private BigDecimal specialDeduction; - /** 本年累计已发工资 */ @Excel(name = "本年累计已发工资") private BigDecimal totalWages; - /** 本年累计已缴个税 */ @Excel(name = "本年累计已缴个税") private BigDecimal aggregatePersonalIncomeTax; - /** 备注 */ + @Excel(name = "备注") private String remarks; - public String getSocialSubsidy() { - return socialSubsidy; - } - - public void setSocialSubsidy(String socialSubsidy) { - this.socialSubsidy = socialSubsidy; - } - - public BigDecimal getMiddleSubsidies() { - return middleSubsidies; - } - - public void setMiddleSubsidies(BigDecimal middleSubsidies) { - this.middleSubsidies = middleSubsidies; - } - - public String getCompanyName() { - return companyName; - } - - public void setCompanyName(String companyName) { - this.companyName = companyName; - } - - public String getDeptName() { - return deptName; - } - - public void setDeptName(String deptName) { - this.deptName = deptName; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getIdCard() { - return idCard; - } - - public void setIdCard(String idCard) { - this.idCard = idCard; - } - - public String getSex() { - return sex; - } - - public void setSex(String sex) { - this.sex = sex; - } - - public Long getAge() { - return age; - } - - public void setAge(Long age) { - this.age = age; - } - - public String getPhone() { - return phone; - } - - public void setPhone(String phone) { - this.phone = phone; - } - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - public String getLevel() { - return level; - } - - public void setLevel(String level) { - this.level = level; - } - - public String getMajor() { - return major; - } - - public void setMajor(String major) { - this.major = major; - } - - public String getSchool() { - return school; - } - - public void setSchool(String school) { - this.school = school; - } - - public String getBankNumber() { - return bankNumber; - } - - public void setBankNumber(String bankNumber) { - this.bankNumber = bankNumber; - } - - public String getBank() { - return bank; - } - - public void setBank(String bank) { - this.bank = bank; - } - - public Date getEmploymentDate() { - return employmentDate; - } - - public void setEmploymentDate(Date employmentDate) { - this.employmentDate = employmentDate; - } - - public Date getWagesRatioDate() { - return wagesRatioDate; - } - - public void setWagesRatioDate(Date wagesRatioDate) { - this.wagesRatioDate = wagesRatioDate; - } - - public String getExperience() { - return experience; - } - - public void setExperience(String experience) { - this.experience = experience; - } - - public Long getWorkerTerm() { - return workerTerm; - } - - public void setWorkerTerm(Long workerTerm) { - this.workerTerm = workerTerm; - } - - public Date getRegularDate() { - return regularDate; - } - - public void setRegularDate(Date regularDate) { - this.regularDate = regularDate; - } - - public Date getQuitDate() { - return quitDate; - } - - public void setQuitDate(Date quitDate) { - this.quitDate = quitDate; - } - - public Date getContractStart() { - return contractStart; - } - - public void setContractStart(Date contractStart) { - this.contractStart = contractStart; - } - - public Date getContractEnd() { - return contractEnd; - } - - public void setContractEnd(Date contractEnd) { - this.contractEnd = contractEnd; - } - - public String getContractType() { - return contractType; - } - - public void setContractType(String contractType) { - this.contractType = contractType; - } - - public String getSocialType() { - return socialType; - } - - public void setSocialType(String socialType) { - this.socialType = socialType; - } - - public Long getSeniority() { - return seniority; - } - - public void setSeniority(Long seniority) { - this.seniority = seniority; - } - - public String getIsOvertimePay() { - return isOvertimePay; - } - - public void setIsOvertimePay(String isOvertimePay) { - this.isOvertimePay = isOvertimePay; - } - - public String getZsFlag() { - return zsFlag; - } - - public void setZsFlag(String zsFlag) { - this.zsFlag = zsFlag; - } - - public String getSecrecy() { - return secrecy; - } - - public void setSecrecy(String secrecy) { - this.secrecy = secrecy; - } - - public String getInjury() { - return injury; - } - - public void setInjury(String injury) { - this.injury = injury; - } - - public String getInsurance() { - return insurance; - } - - public void setInsurance(String insurance) { - this.insurance = insurance; - } - - public String getIntroducer() { - return introducer; - } - - public void setIntroducer(String introducer) { - this.introducer = introducer; - } - - public String getClockIn() { - return clockIn; - } - - public void setClockIn(String clockIn) { - this.clockIn = clockIn; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public BigDecimal getBasicSalary() { - return basicSalary; - } - - public void setBasicSalary(BigDecimal basicSalary) { - this.basicSalary = basicSalary; - } - - public BigDecimal getJobsSalary() { - return jobsSalary; - } - - public void setJobsSalary(BigDecimal jobsSalary) { - this.jobsSalary = jobsSalary; - } - - public BigDecimal getDailyWage() { - return dailyWage; - } - - public void setDailyWage(BigDecimal dailyWage) { - this.dailyWage = dailyWage; - } - - public BigDecimal getHoursSalary() { - return hoursSalary; - } - - public void setHoursSalary(BigDecimal hoursSalary) { - this.hoursSalary = hoursSalary; - } - - public BigDecimal getFullFrequentlySubsidies() { - return fullFrequentlySubsidies; - } - - public void setFullFrequentlySubsidies(BigDecimal fullFrequentlySubsidies) { - this.fullFrequentlySubsidies = fullFrequentlySubsidies; - } - - public BigDecimal getLevelOfEducationSubsidies() { - return levelOfEducationSubsidies; - } - - public void setLevelOfEducationSubsidies(BigDecimal levelOfEducationSubsidies) { - this.levelOfEducationSubsidies = levelOfEducationSubsidies; - } - - public BigDecimal getContractSubsidies() { - return contractSubsidies; - } - - public void setContractSubsidies(BigDecimal contractSubsidies) { - this.contractSubsidies = contractSubsidies; - } - - public BigDecimal getSenioritySubsidies() { - return senioritySubsidies; - } - - public void setSenioritySubsidies(BigDecimal senioritySubsidies) { - this.senioritySubsidies = senioritySubsidies; - } - - public BigDecimal getSocialSecuritySubsidies() { - return socialSecuritySubsidies; - } - - public void setSocialSecuritySubsidies(BigDecimal socialSecuritySubsidies) { - this.socialSecuritySubsidies = socialSecuritySubsidies; - } - - public BigDecimal getNightShiftSubsidies() { - return nightShiftSubsidies; - } - - public void setNightShiftSubsidies(BigDecimal nightShiftSubsidies) { - this.nightShiftSubsidies = nightShiftSubsidies; - } - - public BigDecimal getDinnerSubsidies() { - return dinnerSubsidies; - } - - public void setDinnerSubsidies(BigDecimal dinnerSubsidies) { - this.dinnerSubsidies = dinnerSubsidies; - } - - public BigDecimal getFixedAllowance() { - return fixedAllowance; - } - - public void setFixedAllowance(BigDecimal fixedAllowance) { - this.fixedAllowance = fixedAllowance; - } - - public BigDecimal getOtherSubsidies() { - return otherSubsidies; - } - - public void setOtherSubsidies(BigDecimal otherSubsidies) { - this.otherSubsidies = otherSubsidies; - } - - public BigDecimal getBreakfastExpend() { - return breakfastExpend; - } - - public void setBreakfastExpend(BigDecimal breakfastExpend) { - this.breakfastExpend = breakfastExpend; - } - - public BigDecimal getLunchExpend() { - return lunchExpend; - } - - public void setLunchExpend(BigDecimal lunchExpend) { - this.lunchExpend = lunchExpend; - } - - public BigDecimal getSupperExpend() { - return supperExpend; - } - - public void setSupperExpend(BigDecimal supperExpend) { - this.supperExpend = supperExpend; - } - - public BigDecimal getSubsidyDeductMoney() { - return subsidyDeductMoney; - } - - public void setSubsidyDeductMoney(BigDecimal subsidyDeductMoney) { - this.subsidyDeductMoney = subsidyDeductMoney; - } - - public BigDecimal getDeductions() { - return deductions; - } - - public void setDeductions(BigDecimal deductions) { - this.deductions = deductions; - } - - public BigDecimal getEndowmentInsurance() { - return endowmentInsurance; - } - - public void setEndowmentInsurance(BigDecimal endowmentInsurance) { - this.endowmentInsurance = endowmentInsurance; - } - - public BigDecimal getMedicalInsurance() { - return medicalInsurance; - } - - public void setMedicalInsurance(BigDecimal medicalInsurance) { - this.medicalInsurance = medicalInsurance; - } - - public BigDecimal getEmploymentInjuryInsurance() { - return employmentInjuryInsurance; - } - - public void setEmploymentInjuryInsurance(BigDecimal employmentInjuryInsurance) { - this.employmentInjuryInsurance = employmentInjuryInsurance; - } - - public BigDecimal getMaternityInsurance() { - return maternityInsurance; - } - - public void setMaternityInsurance(BigDecimal maternityInsurance) { - this.maternityInsurance = maternityInsurance; - } - - public BigDecimal getUnemploymentInsurance() { - return unemploymentInsurance; - } - - public void setUnemploymentInsurance(BigDecimal unemploymentInsurance) { - this.unemploymentInsurance = unemploymentInsurance; - } - - public BigDecimal getAccumulationFund() { - return accumulationFund; - } - - public void setAccumulationFund(BigDecimal accumulationFund) { - this.accumulationFund = accumulationFund; - } - - public BigDecimal getChildrenEducation() { - return childrenEducation; - } - - public void setChildrenEducation(BigDecimal childrenEducation) { - this.childrenEducation = childrenEducation; - } - - public BigDecimal getSupportTheOld() { - return supportTheOld; - } - - public void setSupportTheOld(BigDecimal supportTheOld) { - this.supportTheOld = supportTheOld; - } - - public BigDecimal getHousingLoans() { - return housingLoans; - } - - public void setHousingLoans(BigDecimal housingLoans) { - this.housingLoans = housingLoans; - } - - public BigDecimal getHousingRents() { - return housingRents; - } - - public void setHousingRents(BigDecimal housingRents) { - this.housingRents = housingRents; - } - - public BigDecimal getAdultEducation() { - return adultEducation; - } - - public void setAdultEducation(BigDecimal adultEducation) { - this.adultEducation = adultEducation; - } - - public BigDecimal getTreatmentForSeriousDisease() { - return treatmentForSeriousDisease; - } - - public void setTreatmentForSeriousDisease(BigDecimal treatmentForSeriousDisease) { - this.treatmentForSeriousDisease = treatmentForSeriousDisease; - } - - public BigDecimal getSpecialDeduction() { - return specialDeduction; - } - - public void setSpecialDeduction(BigDecimal specialDeduction) { - this.specialDeduction = specialDeduction; - } - - public BigDecimal getTotalWages() { - return totalWages; - } - - public void setTotalWages(BigDecimal totalWages) { - this.totalWages = totalWages; - } - public BigDecimal getAggregatePersonalIncomeTax() { - return aggregatePersonalIncomeTax; - } - - public void setAggregatePersonalIncomeTax(BigDecimal aggregatePersonalIncomeTax) { - this.aggregatePersonalIncomeTax = aggregatePersonalIncomeTax; - } - public String getRemarks() { - return remarks; - } - - public void setRemarks(String remarks) { - this.remarks = remarks; - } } diff --git a/evo-admin/src/main/java/com/evo/system/service/ISysStaffService.java b/evo-admin/src/main/java/com/evo/system/service/ISysStaffService.java index b0d8361..f4213d2 100644 --- a/evo-admin/src/main/java/com/evo/system/service/ISysStaffService.java +++ b/evo-admin/src/main/java/com/evo/system/service/ISysStaffService.java @@ -7,6 +7,7 @@ import com.evo.system.domain.SysStaff; import com.evo.system.domain.vo.SysStaffVo; import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; import java.util.List; /** @@ -100,4 +101,11 @@ public interface ISysStaffService extends IService SysStaff selectByDepId(Long deptId); AjaxResult importSalesCommissions(List attendanceList); + + /*** + * 数据导出 + * @param response + * @param sysStaff + */ + void exportInfo(HttpServletResponse response, SysStaff sysStaff); } diff --git a/evo-admin/src/main/java/com/evo/system/service/impl/SysStaffServiceImpl.java b/evo-admin/src/main/java/com/evo/system/service/impl/SysStaffServiceImpl.java index 210c619..b3f35a9 100644 --- a/evo-admin/src/main/java/com/evo/system/service/impl/SysStaffServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/system/service/impl/SysStaffServiceImpl.java @@ -11,8 +11,14 @@ import com.evo.common.core.domain.entity.RzUpload; import com.evo.common.core.domain.entity.SysDept; import com.evo.common.core.domain.entity.SysDictData; import com.evo.common.utils.*; +import com.evo.common.utils.Collections; import com.evo.common.utils.bean.BeanUtils; +import com.evo.common.utils.poi.ExcelUtil; +import com.evo.common.utils.poi.ExcelUtil1; import com.evo.equipment.service.IEqSnDetailService; +import com.evo.kingdeeUtils.KingdeeRequestUtils; +import com.evo.personnelMatters.domain.RzSubsidyInfo; +import com.evo.personnelMatters.mapper.RzSubsidyInfoMapper; import com.evo.restaurant.service.IRzRestaurantStatisticsService; import com.evo.system.domain.SysStaff; import com.evo.system.domain.SysStaffDetail; @@ -23,6 +29,7 @@ import com.evo.system.mapper.SysStaffDetailMapper; import com.evo.system.mapper.SysStaffMapper; import com.evo.system.service.ISysStaffService; import com.evo.system.service.RzUploadService; +import com.evo.system.utils.SubsidyCalculationUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; @@ -35,14 +42,11 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; -import java.io.IOException; -import java.io.InputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.*; import java.math.BigDecimal; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -69,6 +73,8 @@ public class SysStaffServiceImpl extends ServiceImpl i private RzUploadService rzUploadService;//文件上传 @Resource private IEqSnDetailService eqSnDetailService;//设备信息 + @Resource + private RzSubsidyInfoMapper rzSubsidyInfoMapper; /** * 查询员工管理 * @@ -152,6 +158,9 @@ public class SysStaffServiceImpl extends ServiceImpl i rzRestaurantStatisticsService.createRestaurantStatistics(sysStaff, DateUtils.getNowDate()); //处理考勤机相关信息 initCheckDevice(sysStaff); + //新增员工信息到金蝶 + KingdeeRequestUtils.employeeSave(Collections.asMap("FName", sysStaff.getName(), "FStaffNumber", sysStaff.getCode(), "FNumber", sysStaff.getJobCode().split("_")[0])); + return AjaxResult.success(); } @@ -223,6 +232,8 @@ public class SysStaffServiceImpl extends ServiceImpl i if(i < 1){ return AjaxResult.error(); } + //如果是离职, 推送金蝶禁用 + KingdeeRequestUtils.employeeDisabled(Collections.asMap("Numbers",sysStaff.getJobCode().split("_")[0])); return AjaxResult.success(); } } @@ -237,6 +248,10 @@ public class SysStaffServiceImpl extends ServiceImpl i } //根据员工ID查询原来的数据信息 SysStaff old_staff = getBaseMapper().selectSysStaffByUserId(sysStaff.getUserId()); + //检查是否修改岗位 + if(!old_staff.getJobCode().equals(sysStaff.getJobCode())) { + KingdeeRequestUtils.updateJobInfo(Collections.asMap("NeedUpDateFields","\"FDept\",\"FPosition\"", "FNumber", sysStaff.getCode(), "FDept_FNumber", sysStaff.getJobCode().split("_")[1], "FPosition_FNumber", sysStaff.getJobCode().split("_")[0])); + } //判断员工更换公司 if(!old_staff.getCompanyName().equals(sysStaff.getCompanyName())) { SysStaffDetail sysStaffDetail = sysStaffDetailMapper.selectSysStaffDetailByStaffId(sysStaff.getUserId()); @@ -480,8 +495,8 @@ public class SysStaffServiceImpl extends ServiceImpl i for (SysStaffVo Staffvo : staffList){ //判断必填项是否为空,为空执行下一条数据: 身份证号,姓名,部门,是否有加班费,入职日期,学历,打卡,合同,社保 if(StringUtils.isEmpty(Staffvo.getIdCard()) || StringUtils.isEmpty(Staffvo.getName()) || StringUtils.isEmpty(Staffvo.getDeptName()) - || StringUtils.isEmpty(Staffvo.getIsOvertimePay()) || Staffvo.getEmploymentDate() == null || StringUtils.isEmpty(Staffvo.getLevel()) - || StringUtils.isEmpty(Staffvo.getClockIn()) || StringUtils.isEmpty(Staffvo.getContractType()) || StringUtils.isEmpty(Staffvo.getSocialType()) + || Staffvo.getEmploymentDate() == null || StringUtils.isEmpty(Staffvo.getLevel()) + || StringUtils.isEmpty(Staffvo.getClockIn()) || StringUtils.isEmpty(Staffvo.getSocialType()) || StringUtils.isEmpty(Staffvo.getSocialSubsidy())){ continue; } @@ -526,12 +541,12 @@ public class SysStaffServiceImpl extends ServiceImpl i } } //合同年限 - for (SysDictData sysDictData : ht_list) { - if(sysDictData.getDictLabel().equals(Staffvo.getContractType())){ - sysStaff.setContractType(sysDictData.getDictValue()); - break; - } - } +// for (SysDictData sysDictData : ht_list) { +// if(sysDictData.getDictLabel().equals(Staffvo.getContractType())){ +// sysStaff.setContractType(sysDictData.getDictValue()); +// break; +// } +// } //计算性别和年龄 if(StringUtils.isNotEmpty(sysStaff.getIdCard())){ //根据身份证解析性别和年龄 @@ -707,5 +722,45 @@ public class SysStaffServiceImpl extends ServiceImpl i return AjaxResult.success(); } + @Override + public void exportInfo(HttpServletResponse response, SysStaff sysStaff) { + List res_list = new ArrayList(); + //查询员工信息 + List yg_list = getBaseMapper().selectSysStaffList(sysStaff); + List userIds = yg_list.stream().map(SysStaff::getUserId).collect(Collectors.toList()); + Map detailMap = sysStaffDetailMapper.selectList(new LambdaQueryWrapper().eq(SysStaffDetail::getDelFlag, Constants.DELETE_FLAG_0).in(SysStaffDetail::getStaffId,userIds)).stream().collect(Collectors.toMap(SysStaffDetail::getStaffId, v->v)); + List subsidyList = rzSubsidyInfoMapper.selectList(new LambdaQueryWrapper()); + Map subsidyMap = rzSubsidyInfoMapper.selectList(new LambdaQueryWrapper()).stream().collect(Collectors.toMap(RzSubsidyInfo::getId, RzSubsidyInfo::getName)); + + for (SysStaff staff : yg_list) { + SysStaffVo sysStaffVo = new SysStaffVo(); + BeanUtils.copyProperties(staff,sysStaffVo); + //根据员工信息查询详情信息 + SysStaffDetail sysStaffDetail = SubsidyCalculationUtils.subsidyCalculation(staff,detailMap.get(staff.getUserId()), subsidyList); + BeanUtils.copyProperties(sysStaffDetail,sysStaffVo); +// StringBuilder subsidyInfo = new StringBuilder(""); +// for (String key : sysStaffDetail.getExtendeds().keySet()){ +// subsidyInfo.append(key).append("-").append(sysStaffDetail.getExtendeds().get(key)).append("元,"); +// } +// sysStaffVo.setSubsidyInfo(subsidyInfo.toString()); + sysStaffVo.setSubsidyMap(sysStaffDetail.getExtendeds()); + res_list.add(sysStaffVo); + } + ExcelUtil1 util = new ExcelUtil1(SysStaffVo.class); + util.exportExcel(response, res_list, "员工信息"); + } + + + public static void main(String[] args) throws Exception { + + BufferedReader reader = new BufferedReader(new FileReader(new File("D:\\andy\\文档\\考勤\\岗位任职部门信息.txt"))); + String line = reader.readLine(); + while (line != null) { + String[] configData = line.split("_"); + System.out.println("update sys_dict_data set dict_value='"+line+"' where dict_value='"+configData[0]+"';\n"); + line = reader.readLine(); + } + } + } diff --git a/evo-admin/src/main/resources/lib/k3cloud-webapi-sdk-java11-v8.2.0.jar b/evo-admin/src/main/resources/lib/k3cloud-webapi-sdk-java11-v8.2.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..bad846c3187d305cc850b625c47d732479f4891b GIT binary patch literal 57197 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 literal 0 HcmV?d00001 diff --git a/evo-admin/src/main/resources/mapper/system/SysStaffMapper.xml b/evo-admin/src/main/resources/mapper/system/SysStaffMapper.xml index 587a5c2..7521f1f 100644 --- a/evo-admin/src/main/resources/mapper/system/SysStaffMapper.xml +++ b/evo-admin/src/main/resources/mapper/system/SysStaffMapper.xml @@ -52,7 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select user_id,company_name, dept_id, code, name, id_card,is_leader, sex, age, phone, address, level, major, school, bank_number,social_subsidy, bank, employment_date, experience, worker_term, regular_date, quit_date, contract_start, contract_end, contract_type, social_type, seniority, is_overtime_pay, zs_flag, secrecy, injury, insurance, introducer, clock_in, status, wages_ratio_date, remarks, del_flag, create_by, create_time, update_by, update_time, image_url,time_clock,subsidys from sys_staff + select user_id,company_name, dept_id, code, name, id_card,is_leader, sex, age, phone, address, level, major, school, bank_number,social_subsidy, bank, employment_date, experience, worker_term, regular_date, quit_date, contract_start, contract_end, contract_type, social_type, seniority, is_overtime_pay, zs_flag, secrecy, injury, insurance, introducer, clock_in, status, wages_ratio_date, remarks, del_flag, create_by, create_time, update_by, update_time, image_url,time_clock,subsidys, job_code from sys_staff