金蝶资产卡片

This commit is contained in:
tzy 2025-09-14 11:11:38 +08:00
parent 512f5fa908
commit 3318f3e988
31 changed files with 2166 additions and 368 deletions

View File

@ -20,7 +20,6 @@ import org.springframework.cache.annotation.EnableCaching;
@MapperScan("com.ruoyi.**.mapper")
@EnableCaching
public class RuoYiApplication {
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication application = new SpringApplication(RuoYiApplication.class);

View File

@ -49,7 +49,8 @@ spring:
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://localhost:3306/item_retrieval-evo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
#url: jdbc:mysql://localhost:3306/item_retrieval-evo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
url: jdbc:mysql://192.168.5.121:3306/item_retrieval-evo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# 从库数据源
@ -57,7 +58,8 @@ spring:
lazy: true
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/item_retrieval_salve?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
#url: jdbc:mysql://localhost:3306/item_retrieval_salve?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
url: jdbc:mysql://192.168.5.121:3306/item_retrieval_salve?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# oracle:

View File

@ -52,7 +52,8 @@ spring:
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://localhost:3306/item_retrieval-evo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
#url: jdbc:mysql://localhost:3306/item_retrieval-evo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
url: jdbc:mysql://192.168.5.121:3306/item_retrieval-evo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# 从库数据源
@ -60,7 +61,8 @@ spring:
lazy: true
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/item_retrieval_salve?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
# url: jdbc:mysql://localhost:3306/item_retrieval_salve?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
url: jdbc:mysql://192.168.5.121:3306/item_retrieval_salve?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# oracle:

View File

@ -30,7 +30,6 @@ server:
servlet:
# 应用的访问路径
context-path: /
# undertow 配置
undertow:
# HTTP post内容的最大大小。当值为-1时默认值为大小是无限的
max-http-post-size: -1
@ -144,6 +143,12 @@ security:
- /index/JDList
- /jmreport/**
- /system/procedure/**
- /system/dict/data/type/**
- /system/proPlan/expiryProjects
- /system/proPlan/overdue
- /system/proPlan/list2
- /system/mrp/**
- /system/orderPro/**
# MyBatisPlus配置
# https://baomidou.com/config/

View File

@ -0,0 +1,21 @@
package com.ruoyi;
import com.ruoyi.common.utils.FtpUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@SpringBootTest(classes=RuoYiApplication.class)
public class RuoYiTestApplication {
@Test
public void asfsrfsf() throws FileNotFoundException {
FtpUtil.uploadFile("192.168.5.18", 8022, "admin", "hbyt2025", "", "test11/111111111/222222", "33333.dwg", new FileInputStream(new File("D:\\dwg\\111111111111111.dwg")));
}
}

View File

@ -84,4 +84,4 @@ public class ExcelSummaryTest {
throw new RuntimeException("写入汇总 Excel 文件时出错", e);
}
}
}
}

View File

@ -173,6 +173,11 @@
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<!-- 离线IP地址定位库 -->
<dependency>
<groupId>org.lionsoul</groupId>

View File

@ -0,0 +1,106 @@
package com.ruoyi.common.convert;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ReadConverterContext;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.RichTextString;
public class KeepSpaceStringConverter implements Converter<String> {
private static boolean printedFields = false;
@Override
public Class<?> supportJavaTypeKey() {
return String.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public String convertToJavaData(ReadConverterContext<?> context) {
// 打印所有可用字段仅第一次
if (!printedFields) {
System.out.println("KeepSpaceStringConverter - ReadConverterContext字段:");
java.lang.reflect.Field[] fields = context.getClass().getDeclaredFields();
for (java.lang.reflect.Field field : fields) {
System.out.println(" - " + field.getName() + " (" + field.getType().getSimpleName() + ")");
}
printedFields = true;
}
// 尝试通过readCellData字段获取底层的POI Cell
try {
java.lang.reflect.Field readCellDataField = context.getClass().getDeclaredField("readCellData");
readCellDataField.setAccessible(true);
ReadCellData<?> readCellData = (ReadCellData<?>) readCellDataField.get(context);
if (readCellData != null) {
// 打印ReadCellData的字段
System.out.println("KeepSpaceStringConverter - ReadCellData字段:");
java.lang.reflect.Field[] cellDataFields = readCellData.getClass().getDeclaredFields();
for (java.lang.reflect.Field field : cellDataFields) {
System.out.println(" - " + field.getName() + " (" + field.getType().getSimpleName() + ")");
}
// 尝试不同的字段名获取POI Cell
String[] possibleFieldNames = {"cell", "poiCell", "xssfCell", "xssfCellData"};
for (String fieldName : possibleFieldNames) {
try {
java.lang.reflect.Field cellField = readCellData.getClass().getDeclaredField(fieldName);
cellField.setAccessible(true);
Object cellObj = cellField.get(readCellData);
if (cellObj instanceof Cell) {
Cell poiCell = (Cell) cellObj;
if (poiCell.getCellType() == CellType.STRING) {
// 直接从POI Cell获取原始数据
RichTextString richTextString = poiCell.getRichStringCellValue();
String rawValue = richTextString.getString();
System.out.println("KeepSpaceStringConverter - POI原始数据: '" + rawValue + "'");
System.out.println("KeepSpaceStringConverter - POI数据长度: " + rawValue.length());
// 检查是否包含前后空格
if (!rawValue.equals(rawValue.trim())) {
System.out.println("KeepSpaceStringConverter - POI检测到前后空格");
} else {
System.out.println("KeepSpaceStringConverter - POI没有检测到前后空格");
}
return rawValue;
}
}
} catch (NoSuchFieldException e) {
// 继续尝试下一个字段名
continue;
}
}
}
} catch (Exception e) {
System.out.println("KeepSpaceStringConverter - 反射获取ReadCellData失败: " + e.getMessage());
}
// 如果反射失败使用EasyExcel的方法
ReadCellData<?> cellData = context.getReadCellData();
String easyExcelValue = cellData.getStringValue();
System.out.println("KeepSpaceStringConverter - EasyExcel数据: '" + easyExcelValue + "'");
System.out.println("KeepSpaceStringConverter - EasyExcel数据长度: " + easyExcelValue.length());
return easyExcelValue;
}
@Override
public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {
return new WriteCellData<>(context.getValue());
}
}

View File

@ -0,0 +1,61 @@
package com.ruoyi.common.poi;
import lombok.Data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* @Description 存放需要导出的动态数据
* @Author susu
* @Date 2024/2/19
*/
@Data
public class DynamicDataMapping {
private String dataId;
private List<Map<String, Object>> dataList;
/**
* @description: 组装只有一个list类型的动态数据
* @param dataId
* @param dataList
* @return java.util.List<com.liu.susu.excel.template.poi.common.DynamicDataMapping>
* @author susu
* @date 2024/2/20
*/
public static List<DynamicDataMapping> createOneDataList(String dataId, List<Map<String, Object>> dataList) {
if (dataList == null)
return null;
return Collections.singletonList(getDynamicDataMapping(dataId,dataList));
}
/**
* @description: 组装只有多个list类型的动态数据
* @param transMap
* @return java.util.List<com.liu.susu.excel.template.poi.common.DynamicDataMapping>
* @author susu
* @date 2024/2/20
*/
public static List<DynamicDataMapping> createMorDataList(Map<String,List<Map<String, Object>>> transMap) {
if (transMap == null)
return null;
List<DynamicDataMapping> list = new ArrayList<>();
transMap.forEach((dataId,dataList)->{
list.add(getDynamicDataMapping(dataId,dataList));
});
return list;
}
public static DynamicDataMapping getDynamicDataMapping(String dataId, List<Map<String, Object>> dataList){
DynamicDataMapping dynamicData = new DynamicDataMapping();
dynamicData.dataId = dataId;
dynamicData.dataList = dataList;
return dynamicData;
}
}

View File

@ -0,0 +1,455 @@
package com.ruoyi.common.poi;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellCopyPolicy;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.ResourceUtils;
import java.io.*;
import java.util.List;
import java.util.Map;
/**
* @Description 根据模版导出Excel程序
* @Author susu
* @Date 2024/2/19
*/
public class ExcelTemplateProc {
/**
* @param templateFileName
* @param exportFilePathAndName
* @param staticDataMap
* @param dynamicDataMappingList
* @return void
* @description: 根据模版导出Excel入口
* @author susu
* @date 2024/2/20
*/
public static void doExportExcelByTemplateProc(String templateFileName, String exportFilePathAndName,
Map<String, Object> staticDataMap,
List<DynamicDataMapping> dynamicDataMappingList) throws IOException {
/**
* 1. 从resources下加载模板并替换
* 使用 ResourceUtils 加载文件
*/
File file = ResourceUtils.getFile("classpath:"+templateFileName);
InputStream inputStream = new FileInputStream(file);
Workbook workbook = dealAllSheetsByTemplate(inputStream, staticDataMap, dynamicDataMappingList);
// 2. 保存到本地
saveExportFile(workbook, exportFilePathAndName);
}
/**
* @param workbook
* @param excelFilePath
* @return void
* @description: 保存导出的Excel文件到服务器
* @author susu
* @date 2024/2/20
*/
public static void saveExportFile(Workbook workbook, String excelFilePath) throws IOException {
FileOutputStream outputStream = new FileOutputStream(excelFilePath);
executeWorkBookWrite(workbook, outputStream);
}
/**
* @param workbook
* @param outputStream
* @return void
* @description: 数据输出
* @author susu
* @date 2024/2/20
*/
public static void executeWorkBookWrite(Workbook workbook, OutputStream outputStream) throws IOException {
workbook.write(outputStream);
outputStream.flush();
outputStream.close();
workbook.close();
}
/**
* @param inputStream
* @param staticDataMap
* @param dynamicDataMappingList
* @return org.apache.poi.ss.usermodel.Workbook
* @description: 处理所有sheet页的模版
* @author susu
* @date 2024/2/20
*/
public static Workbook dealAllSheetsByTemplate(InputStream inputStream,
Map<String, Object> staticDataMap,
List<DynamicDataMapping> dynamicDataMappingList) throws IOException {
XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
// 处理所有sheet页
for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
XSSFSheet sheet = workbook.getSheetAt(sheetIndex);
// 按模板处理sheet页
dealSheetDataByTemplate(sheet, staticDataMap, dynamicDataMappingList);
}
return workbook;
}
/**
* @param inputStream
* @param staticDataMap
* @param dynamicDataMappingList
* @return org.apache.poi.ss.usermodel.Workbook
* @description: 处理只有一个sheet页的模版
* @author susu
* @date 2024/2/20
*/
public static Workbook dealFirstSheetByTemplate(InputStream inputStream,
Map<String, Object> staticDataMap,
List<DynamicDataMapping> dynamicDataMappingList) throws IOException {
XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
XSSFSheet sheet = workbook.getSheetAt(0);
// 按模板处理sheet页
dealSheetDataByTemplate(sheet, staticDataMap, dynamicDataMappingList);
return workbook;
}
/**
* @param sheet
* @param staticDataMap
* @param dynamicDataMappingList
* @return void
* @description: 按模板处理sheet页里的数据
* @author susu
* @date 2024/2/19
*/
private static void dealSheetDataByTemplate(XSSFSheet sheet, Map<String, Object> staticDataMap, List<DynamicDataMapping> dynamicDataMappingList) {
// 循环sheet里每一行
for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
XSSFRow row = sheet.getRow(i);
if (row == null) {
continue; // 跳过空行
}
// 添加调试信息检查每一行是否有静态数据占位符
if (row.getFirstCellNum() != -1 && row.getLastCellNum() != -1) {
for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
XSSFCell cell = row.getCell(j);
if (cell != null) {
String cellValue = cell.getStringCellValue();
if (cellValue != null && cellValue.contains("{{") && !cellValue.contains(".")) {
System.out.println("发现静态数据占位符: 行" + i + ", 列" + j + ", 内容: " + cellValue);
}
}
}
}
// 先处理静态数据再处理动态数据
dealTemplateDataRow(row, null, staticDataMap);
DynamicDataMapping dynamicDataMapping = getDynamicRowDataByMatch(row, dynamicDataMappingList);
if (dynamicDataMapping != null) {
i = getTemplateLastRowIndexAfterDealTemplate(sheet, i, dynamicDataMapping);
} else {
// 检查是否有动态数据占位符但没有匹配的数据映射
if (hasDynamicPlaceholders(row) && !hasMatchingDataMapping(row, dynamicDataMappingList)) {
// 清理没有数据映射的占位符
clearDynamicPlaceholders(row);
}
}
}
}
/**
* @param row
* @param dataMap
* @param dataPrefix
* @return void
* @description: 循环处理模版中每行的数据
* @author susu
* @date 2024/2/20
*/
private static void dealTemplateDataRow(XSSFRow row, String dataPrefix, Map<String, Object> dataMap) {
if (dataMap == null || row == null) {
return;
}
int firstCellNum = row.getFirstCellNum();
int lastCellNum = row.getLastCellNum();
// 检查是否有有效的单元格范围
if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) {
return;
}
// 添加调试信息显示静态数据处理
if (dataPrefix == null || dataPrefix.isEmpty()) {
System.out.println("开始处理静态数据行: " + row.getRowNum() + ", dataMap=" + dataMap.toString());
}
for (int i = firstCellNum; i < lastCellNum; i++) {
XSSFCell cell = row.getCell(i);
if (cell != null) {
// 添加调试信息检查静态数据处理
if (dataPrefix == null || dataPrefix.isEmpty()) {
String cellValue = cell.getStringCellValue();
if (cellValue != null && cellValue.contains("{{")) {
System.out.println("处理静态数据行,单元格" + i + ": " + cellValue);
}
}
fillInTemplateCellDataValue(cell, dataPrefix, dataMap);
}
}
}
/**
* @param cell
* @param dataPrefix
* @param dataMap
* @return void
* @description: 填充模版里单元格的值
* @author susu
* @date 2024/2/20
*/
private static void fillInTemplateCellDataValue(XSSFCell cell, String dataPrefix, Map<String, Object> dataMap) {
if (cell == null) {
return;
}
String cellValue = cell.getStringCellValue();//获取模版里设置的数据
if (StringUtils.isEmpty(cellValue)) {
return;
}
boolean flag = false;
dataPrefix = StringUtils.isEmpty(dataPrefix) ? "" : (dataPrefix + ".");
for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
// 循环所有因为可能一行有多个占位符
String cellTemplateStr = "{{" + dataPrefix + entry.getKey() + "}}";
if (cellValue.contains(cellTemplateStr)) {
// 替换模版中单元格的数据
String replacementValue = entry.getValue() == null ? "" : entry.getValue().toString();
cellValue = cellValue.replace(cellTemplateStr, replacementValue);
flag = true;
// 添加静态数据替换的调试信息
if (dataPrefix == null || dataPrefix.isEmpty()) {
System.out.println("静态数据替换: " + cellTemplateStr + " -> " + replacementValue);
System.out.println("替换后内容: " + cellValue);
}
}
}
if (flag) {
cell.setCellValue(cellValue);
// 添加调试信息确认值被设置
if (dataPrefix == null || dataPrefix.isEmpty()) {
System.out.println("设置单元格值: " + cellValue);
}
}
}
/**
* @param row
* @param dynamicDataMappingList
* @return com.liu.susu.excel.template.poi.common.DynamicDataMapping
* @description: 通过模版sheet中的行数据 动态数据匹配,获取此行需要填充的动态数据
* @author susu
* @date 2024/2/21
*/
private static DynamicDataMapping getDynamicRowDataByMatch(XSSFRow row, List<DynamicDataMapping> dynamicDataMappingList) {
if (dynamicDataMappingList == null || dynamicDataMappingList.size() < 1) {
return null;
}
// 检查行是否为空
if (row == null) {
return null;
}
int firstCellNum = row.getFirstCellNum();
int lastCellNum = row.getLastCellNum();
// 检查是否有有效的单元格范围
if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) {
return null;
}
for (int j = firstCellNum; j < lastCellNum; j++) {
XSSFCell cell = row.getCell(j);
if (cell == null) {
continue;
}
String value = cell.getStringCellValue();
if (value != null) {
for (DynamicDataMapping dynamicData : dynamicDataMappingList) {
if (value.startsWith("{{" + dynamicData.getDataId() + ".")) {
return dynamicData;
}
}
}
}
return null;
}
/**
* @param sheet
* @param rowIndex
* @param dynamicDataMapping
* @return int
* @description: 根据动态数据的条数动态复制模版行每处理一个类型的list返回最后的行数进而处理下一个类型的list
* @author susu
* @date 2024/2/20
*/
private static int getTemplateLastRowIndexAfterDealTemplate(XSSFSheet sheet, int rowIndex, DynamicDataMapping dynamicDataMapping) {
if (dynamicDataMapping == null) {
return rowIndex;
}
int dataRows = dynamicDataMapping.getDataList().size();
// 需要拷贝的行数因为模板行本身占1行所以-1
int copyRows = dataRows - 1;
if (copyRows > 0) {
/**
* shiftRows: 从动态数据模版行(rowIndex)到最后一行这些全部行都向下移copyRows行
* 相当于模版行上面插入n行空行n=copyRows
*/
sheet.shiftRows(rowIndex, sheet.getLastRowNum(), copyRows, true, false);
// 拷贝策略
CellCopyPolicy cellCopyPolicy = makeCellCopyPolicy();
// 因为从模版行开始向下平移了copyRows行所以这里 模板行=rowIndex + copyRows,
int templateDataRow = rowIndex + copyRows;
// 因为模版行上新增了空行所以要把模板所在行的模版 拷贝到上面新增的空行
for (int i = 0; i < copyRows; i++) {
//templateDataRow-模版行数据 rowIndex + i循环的当前空行
sheet.copyRows(templateDataRow, templateDataRow, rowIndex + i, cellCopyPolicy);
}
}
// 循环模版行动态替换模版行将模版行里的模版替换成动态数据
for (int j = rowIndex; j < rowIndex + dataRows; j++) {
Map<String, Object> dataMap = dynamicDataMapping.getDataList().get(j - rowIndex);
dealTemplateDataRow(sheet.getRow(j), dynamicDataMapping.getDataId(), dataMap);
}
return rowIndex + copyRows;
}
/**
* @param
* @return org.apache.poi.ss.usermodel.CellCopyPolicy
* @description: 拷贝策略
* @author susu
* @date 2024/2/20
*/
public static CellCopyPolicy makeCellCopyPolicy() {
CellCopyPolicy cellCopyPolicy = new CellCopyPolicy();
cellCopyPolicy.setCopyCellValue(true);
cellCopyPolicy.setCopyCellStyle(true);
return cellCopyPolicy;
}
/**
* 检查行中是否有动态数据占位符
*/
private static boolean hasDynamicPlaceholders(XSSFRow row) {
if (row == null) {
return false;
}
int firstCellNum = row.getFirstCellNum();
int lastCellNum = row.getLastCellNum();
if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) {
return false;
}
for (int j = firstCellNum; j < lastCellNum; j++) {
XSSFCell cell = row.getCell(j);
if (cell == null) {
continue;
}
String value = cell.getStringCellValue();
if (value != null && value.contains("{{") && value.contains("}}")) {
return true;
}
}
return false;
}
/**
* 检查行中是否有匹配的数据映射
*/
private static boolean hasMatchingDataMapping(XSSFRow row, List<DynamicDataMapping> dynamicDataMappingList) {
if (dynamicDataMappingList == null || dynamicDataMappingList.size() < 1) {
return false;
}
if (row == null) {
return false;
}
int firstCellNum = row.getFirstCellNum();
int lastCellNum = row.getLastCellNum();
if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) {
return false;
}
for (int j = firstCellNum; j < lastCellNum; j++) {
XSSFCell cell = row.getCell(j);
if (cell == null) {
continue;
}
String value = cell.getStringCellValue();
if (value != null) {
for (DynamicDataMapping dynamicData : dynamicDataMappingList) {
if (value.startsWith("{{" + dynamicData.getDataId() + ".")) {
return true;
}
}
}
}
return false;
}
/**
* 清理行中的动态数据占位符
*/
private static void clearDynamicPlaceholders(XSSFRow row) {
if (row == null) {
return;
}
int firstCellNum = row.getFirstCellNum();
int lastCellNum = row.getLastCellNum();
if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) {
return;
}
for (int j = firstCellNum; j < lastCellNum; j++) {
XSSFCell cell = row.getCell(j);
if (cell == null) {
continue;
}
String value = cell.getStringCellValue();
if (value != null && value.contains("{{") && value.contains("}}")) {
// 清理动态数据占位符保留静态内容
String cleanedValue = value.replaceAll("\\{\\{[^}]+\\}\\}", "");
cell.setCellValue(cleanedValue);
}
}
}
}

View File

@ -0,0 +1,65 @@
package com.ruoyi.common.poi;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Description 根据模版导出Excel工具类
* @Author susu
* @Date 2024/2/19
*/
public class ExportExcelByTemplateUtils {
/**
* @description: 根据模版导出Excel入口单个list数据
* @param templateFileName
* @param exportFilePathAndName
* @param staticDataMap
* @param dataId
* @param originDataList
* @return void
* @author susu
* @date 2024/2/21
*/
public static void doExportExcelOneListByTemplate(String templateFileName, String exportFilePathAndName,
Map<String, Object> staticDataMap,
String dataId,
List<?> originDataList) throws Exception{
List<Map<String, Object>> exportDataList = MapObjectUtil.objListToMapList(originDataList);
// 只有一个list数据
List<DynamicDataMapping> dynamicDataMappingList = DynamicDataMapping.createOneDataList(dataId, exportDataList);
// 导出
ExcelTemplateProc.doExportExcelByTemplateProc(templateFileName,exportFilePathAndName,staticDataMap,dynamicDataMappingList);
}
/**
* @description: 根据模版导出Excel入口多个list数据
* @param templateFileName
* @param exportFilePathAndName
* @param staticSource
* @param originDataMapList
* @return void
* @author susu
* @date 2024/2/20
*/
public static void doExportExcelMoreListByTemplate(String templateFileName,
String exportFilePathAndName,
Map<String, Object> staticSource,
Map<String, List<?>> originDataMapList) throws Exception{
Map<String,List<Map<String, Object>>> transMap = new HashMap<>();
originDataMapList.forEach((dataId,originDataList)->{
List<Map<String, Object>> transDataList = MapObjectUtil.objListToMapList(originDataList);
transMap.put(dataId,transDataList);
});
// 多个list类型数据
List<DynamicDataMapping> dynamicDataMappingList = DynamicDataMapping.createMorDataList(transMap);
// 导出
ExcelTemplateProc.doExportExcelByTemplateProc(templateFileName,exportFilePathAndName,staticSource,dynamicDataMappingList);
}
}

View File

@ -0,0 +1,89 @@
package com.ruoyi.common.poi;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.beanutils.BeanMap;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Description
* @Author susu
* @Date 2024/2/19
*/
public class MapObjectUtil {
/**
* @description: 将object的list数据 转换成 map的listList<Map<String, Object>>
* @param objDataList
* @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
* @author susu
*/
public static List<Map<String, Object>> objListToMapList(List<?> objDataList){
List<Map<String, Object>> dataList = new ArrayList<>();
if (objDataList==null || objDataList.size()<1){
return null;
}
objDataList.forEach(obj->{
try {
Map<String, Object> map = MapObjectUtil.objectToMap(obj);
dataList.add(map);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
return dataList;
}
/**
* @description: 将object数据转换成map数据
* @param obj
* @return java.util.Map<java.lang.String,java.lang.Object>
* @author susu
*/
public static Map<String, Object> objectToMap(Object obj) throws IllegalAccessException {
Map<String, Object> map = new HashMap();
Class<?> cla = obj.getClass();
Field[] fields = cla.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String keyName = field.getName();
Object value = field.get(obj);
if (value == null)
value = "";
map.put(keyName, value);
}
return map;
}
/**
* @description: 使用 JSONObject 将object转换成map
* @param obj
* @return java.util.Map<?,?>
* @author susu
*/
public static Map<?, ?> objectToMap2(Object obj) {
if (obj == null)
return null;
return JSONObject.parseObject(JSONObject.toJSONString(obj),Map.class);
}
/**
* @description: 使用BeanMap将object转换成map
* @param obj
* @return java.util.Map<?,?>
* @author susu
*/
public static Map<?, ?> objectToMap3(Object obj) {
if (obj == null)
return null;
return new BeanMap(obj);
}
}

View File

@ -91,22 +91,28 @@ public class SmbUtil {
return;
}
// 指定要下载的文件名
String targetFileName = targetFolder+"汇总表.xlsx";
// 定义要下载的文件列表
String[] fileNames = {
targetFolder + "汇总表.xlsx",
"RawDataTable.xlsx"
};
// 构造远程文件路径
SmbFile remoteFile = new SmbFile(remoteDir, targetFileName);
// 循环下载每个文件
for (String fileName : fileNames) {
// 构造远程文件路径
SmbFile remoteFile = new SmbFile(remoteDir, fileName);
if (!remoteFile.exists() || !remoteFile.isFile()) {
System.err.println("目标文件不存在: " + remoteFile.getCanonicalPath());
return;
if (!remoteFile.exists() || !remoteFile.isFile()) {
System.err.println("目标文件不存在: " + remoteFile.getCanonicalPath());
continue; // 继续下载其他文件
}
// 本地保存路径
File localFile = new File(localDir, fileName);
transferFile(remoteFile, localFile);
}
// 本地保存路径D:/file/项目生产数据表.xlsx
File localFile = new File(localDir, targetFileName);
transferFile(remoteFile, localFile);
} catch (Exception e) {
System.err.println("操作失败: " + e.getMessage());
e.printStackTrace();

View File

@ -68,7 +68,8 @@ public class ExcelUtil {
}
public static <T> ExcelResult<T> importExcelSheet6(InputStream is, Class<T> clazz, boolean isValidate) {
DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate);
EasyExcel.read(is, clazz, listener).sheet(6).doRead();
EasyExcel.read(is, clazz, listener).sheet(6)
.headRowNumber(2).doRead();
return listener.getExcelResult();
}
public static <T> ExcelResult<T> importExcelSheet1(InputStream is, Class<T> clazz, boolean isValidate) {
@ -76,6 +77,11 @@ public class ExcelUtil {
EasyExcel.read(is, clazz, listener).sheet(0).doRead();
return listener.getExcelResult();
}
public static <T> ExcelResult<T> importExcelSheet2(InputStream is, Class<T> clazz, boolean isValidate) {
DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate);
EasyExcel.read(is, clazz, listener).sheet(2).doRead();
return listener.getExcelResult();
}
/**
* 使用自定义监听器 异步导入 自定义返回

View File

@ -16,8 +16,10 @@ import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.utils.JdUtils;
import com.ruoyi.system.domain.EleMaterials;
import com.ruoyi.system.domain.ImMaterial;
import com.ruoyi.system.domain.dto.*;
import com.ruoyi.system.domain.vo.ExcelVo;
import com.ruoyi.system.mapper.ImMaterialMapper;
import com.ruoyi.system.runner.JdUtil;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
@ -54,6 +56,7 @@ import org.springframework.web.multipart.MultipartFile;
public class EleMaterialsController extends BaseController {
private final IEleMaterialsService iEleMaterialsService;
private final ImMaterialMapper materialMapper;
private static final Logger log = LoggerFactory.getLogger(EleMaterialsController.class);
/**
@ -482,4 +485,47 @@ public class EleMaterialsController extends BaseController {
return R.ok("更新成功");
}
@Log(title = "更新VMI仓位", businessType = BusinessType.IMPORT)
@SaCheckPermission("system:route:updaDateCangwei")
@PostMapping(value = "/updaDateCangwei12", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<Void> updaDateCangwei1(@RequestParam("file") MultipartFile file) throws Exception {
String originalFilename = file.getOriginalFilename();
log.info("读取文件名: " + originalFilename);
ExcelResult<JdVMIVo> result = ExcelUtil.importExcelSheet1(file.getInputStream(), JdVMIVo.class, true);
List<JdVMIVo> list = result.getList();
ExecutorService executor = Executors.newFixedThreadPool(10);
list.forEach(vmi -> executor.submit(() -> {
log.info("===============>开始查询物料编码: " + vmi.getMaterialCode() + "的entryID");
List<JdEntryVmi> entryID = JdUtil.getEntryID2(vmi.getMaterialCode());
entryID.forEach(jdEntryVmi -> {
int fmaterialid = jdEntryVmi.getFMATERIALID();
int fEntryId1 = jdEntryVmi.getFEntryId1();
int fEntryId3 = jdEntryVmi.getFEntryId3();
try {
log.info("=====================>开始更新 " + vmi.getMaterialCode() + " 的VMI仓位");
JdUtil.updateVMI(fmaterialid, fEntryId1, fEntryId3, vmi.getFStockId(), vmi.getFStockPlaceId());
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}));
// 关闭线程池并等待所有任务完成
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.MINUTES)) {
executor.shutdownNow(); // 超时后强制关闭
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt(); // 保留中断状态
}
return R.ok("更新成功");
}
}

View File

@ -356,7 +356,7 @@ public class ImMaterialController extends BaseController {
//请求参数要求为json字符串
JsonObject json = new JsonObject();
json.addProperty("FormId", "BD_MATERIAL");
json.addProperty("FieldKeys", "FMATERIALID,FNumber,FName,FCategoryID.FNumber,F_HBYT_DZ,F_SVRI_Assistant.FNumber,FErpClsID,FBaseUnitId.FName,FModifyDate,FForbidStatus");
json.addProperty("FieldKeys", "FMATERIALID,FNumber,FName,FCategoryID.FNumber,F_HBYT_DZ,F_SVRI_Assistant.FNumber,FErpClsID,FBaseUnitId.FName,FModifyDate,FForbidStatus,FIsVmiBusiness");
JsonArray filterString = new JsonArray();
log.debug("构建查询条件...");

View File

@ -379,7 +379,7 @@ public class ProcessRouteController extends BaseController {
ExcelResult<ProcessRouteVo> result = ExcelUtil.importExcelSheet6(file.getInputStream(), ProcessRouteVo.class, true);
List<ProcessRouteVo> list1 = result.getList();
// 读取总装部分sheet
ExcelResult<ProductionOrderVo> result1 = ExcelUtil.importExcelSheet1(file.getInputStream(), ProductionOrderVo.class, true);
ExcelResult<ProductionOrderVo> result1 = ExcelUtil.importExcelSheet2(file.getInputStream(), ProductionOrderVo.class, true);
List<ProductionOrderVo> list = result1.getList();
String productionOrderNo = list1.get(0).getRouteDescription();
List<BomDetails> bomDetails = iBomDetailsService.selectByProjectNumber(list1.get(0).getRouteDescription());

View File

@ -59,6 +59,7 @@ public class ImMaterial extends BaseEntity {
/*
所属名称:danwei
*/
@JsonProperty("FIsVmiBusiness")
private String classificationName;
/*
所属编号

View File

@ -0,0 +1,55 @@
package com.ruoyi.system.domain.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* 基础BOM明细
* @author 田志阳
* @date 2025-09-04
*/
@Data
public class BomDataVO {
/** 序号 */
@ExcelProperty(value = "序号")
private String index;
/** 图号 */
@ExcelProperty(value = "图号")
private String drawingNo;
/** 名称 */
@ExcelProperty(value = "名称")
private String name;
/** 数量 */
@ExcelProperty(value = "数量")
private String quantity;
/** 材料 */
@ExcelProperty(value = "材料")
private String material;
/** 单重 */
@ExcelProperty(value = "单重")
private String unitWeight;
/** 总重 */
@ExcelProperty(value = "总重")
private String totalWeight;
/** 备注 */
@ExcelProperty(value = "备注")
private String remark;
/** 部件 */
@ExcelProperty(value = "部件")
private String component;
/** 部件图号 */
@ExcelProperty(value = "部件图号")
private String componentDrawingNo;
}

View File

@ -0,0 +1,42 @@
package com.ruoyi.system.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
/**
* 伊特产品明细
* @author 田志阳
* @date 2025-09-04
*/
@Data
public class EVOProductsDataVO
{
/** 序号 */
private Integer index;
/** 图号 */
private String drawingNo;
/** 名称 */
private String name;
/** 数量 */
private Integer quantity;
/** 材料 */
private String material;
/** 单重 */
private BigDecimal unitWeight;
/** 总重 */
private BigDecimal totalWeight;
/** 备注 */
private String remark;
/** 批次数量 */
private Integer batchQuantity;
}

View File

@ -0,0 +1,41 @@
package com.ruoyi.system.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
/**
* 机电外购明细
*
* @author 田志阳
* @date 2025-09-04
*/
@Data
public class ElecOutDataVO {
/** 序号 */
private Integer index;
/** 图号 */
private String drawingNo;
/** 名称 */
private String name;
/** 数量 */
private Integer quantity;
/** 材料 */
private String material;
/** 单重 */
private BigDecimal unitWeight;
/** 总重 */
private BigDecimal totalWeight;
/** 备注 */
private String remark;
/** 批次数量 */
private Integer batchQuantity;
}

View File

@ -7,7 +7,11 @@ import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 金蝶资产卡片
* @author 田志阳
* @date 2025-09-04
*/
@Data
@ExcelIgnoreUnannotated
public class JdKingdeeAssetCardVo {

View File

@ -2,12 +2,9 @@ package com.ruoyi.system.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
import com.ruoyi.common.convert.KeepSpaceStringConverter;
import lombok.Data;
import java.math.BigDecimal;
/**
* 生产订单视图对象 production_order
@ -19,18 +16,17 @@ import java.math.BigDecimal;
@ExcelIgnoreUnannotated
public class ProductionOrderVo {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelProperty(value = "序号")
private Long id;
/**
* 生产令号
*/
@ExcelProperty(value = "生产令号")
private String productionOrderNo;
/**
@ -50,16 +46,13 @@ public class ProductionOrderVo {
*/
@ExcelProperty(value = "数量")
private Double quantity;
@ExcelProperty(value = "批次数量")
private String batchQuantity;
/**
* 生产材料
*/
@ExcelProperty(value = "材料")
private String material;
/**
* 单重kg
*/
@ -78,6 +71,9 @@ public class ProductionOrderVo {
@ExcelProperty(value = "备注")
private String remark;
@ExcelProperty(value = "批次数量")
private String batchQuantity;
/**
* 部件名称
*/

View File

@ -0,0 +1,40 @@
package com.ruoyi.system.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
/**
* 甲供件明细
* @author 田志阳
* @date 2025-09-04
*/
@Data
public class SupProvidDataVO {
/** 序号 */
private Integer index;
/** 图号 */
private String drawingNo;
/** 名称 */
private String name;
/** 数量 */
private Integer quantity;
/** 材料 */
private String material;
/** 单重 */
private BigDecimal unitWeight;
/** 总重 */
private BigDecimal totalWeight;
/** 备注 */
private String remark;
/** 批次数量 */
private Integer batchQuantity;
}

View File

@ -0,0 +1,41 @@
package com.ruoyi.system.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
/**
* VMI明细
*
* @author 田志阳
* @date 2025-09-04
*/
@Data
public class VMIDataVO {
/** 序号 */
private Integer index;
/** 图号 */
private String drawingNo;
/** 名称 */
private String name;
/** 数量 */
private Integer quantity;
/** 材料 */
private String material;
/** 单重 */
private BigDecimal unitWeight;
/** 总重 */
private BigDecimal totalWeight;
/** 备注 */
private String remark;
/** 批次数量 */
private Integer batchQuantity;
}

View File

@ -48,4 +48,6 @@ public interface ISafetyStockService {
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
List<SafetyStock> selectByType(String type1);
Boolean isSafeCode(String materialCode);
}

View File

@ -532,7 +532,8 @@ public class ImMaterialServiceImpl implements IImMaterialService {
@Override
public ImMaterial selectByCodeAndName(String materialCode, String materialName) {
LambdaQueryWrapper<ImMaterial> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ImMaterial::getMaterialCode, materialCode).eq(ImMaterial::getMaterialName, materialName);
queryWrapper.eq(ImMaterial::getMaterialCode, materialCode)
.eq(ImMaterial::getMaterialName, materialName);
return baseMapper.selectOne(queryWrapper);
}

View File

@ -148,6 +148,21 @@ public class SafetyStockServiceImpl implements ISafetyStockService {
return Collections.emptyList();
}
/**
* 查询此物料是否是安全库存
*
* @param materialCode
* @return
*/
@Override
public Boolean isSafeCode(String materialCode) {
LambdaQueryWrapper<SafetyStock> safetyStockLambdaQueryWrapper = new LambdaQueryWrapper<>();
safetyStockLambdaQueryWrapper.eq(SafetyStock::getMaterialCode,materialCode);
SafetyStock safetyStock = baseMapper.selectOne(safetyStockLambdaQueryWrapper);
return safetyStock != null;
}
/**
* 物料批量查询
*/