package cn.lk.ehs.module.equipment.service.impl;
import cn.lk.ehs.framework.common.pojo.CommonResult;
import cn.lk.ehs.framework.mongodb.base.service.impl.LKServiceImpl;
import cn.lk.ehs.module.equipment.entity.Record;
import cn.lk.ehs.module.equipment.entity.*;
import cn.lk.ehs.module.equipment.mapper.FixMapper;
import cn.lk.ehs.module.equipment.service.*;
import cn.lk.ehs.module.equipment.utils.TaxUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.Units;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static cn.lk.ehs.framework.common.pojo.CommonResult.error;
import static cn.lk.ehs.framework.common.pojo.CommonResult.success;
@Slf4j
@Service
public class FixDetailServiceImpl extends LKServiceImpl<FixMapper, FixDetail, String>
implements FixDetailService {
@Autowired
private EquipmentService equipmentService;
@Autowired
private EntityService entityService;
@Autowired
private ConstructService constructService;
@Autowired
private ShareService shareService;
@Autowired
private cn.lk.ehs.module.equipment.service.LedgerService ledgerService;
@Autowired
private RecordService recordService;
@Autowired
private PartService partService;
@Value("${file.upload.base-path}")
private String basePath;
private static final int BATCH_SIZE = 100; // 分批处理大小
private static final int PAGE_SIZE_LIMIT = 4; // 每页最大行数
private static final int MAX_IMAGE_SIZE_KB = 100; // 目标图片大小
@Override
public CommonResult addFixDetail(FixDetail itemData) {
//验证项目是否可以转固
Query query = Query.query(Criteria.where("itemNum").is(itemData.getItemNum()));
query.addCriteria(Criteria.where("deleted").is(0));
List<EquipmentData> equipmentData = equipmentService.list(query);
if (!equipmentData.isEmpty()) {
if (!"1".equals(equipmentData.get(0).getIsAccept())) {
return error(1, "项目未完成验收无法转固!");
}
//查数据补入台账表
List<EntityItem> entityItems = entityService.getlist(query, itemData.getItemNum());
List<Construct> constructs = constructService.list(query);
//做一个台账对象插入数据库 更改项目表状态
List<Ledger> ledgers = packageLedger(entityItems, equipmentData, constructs);
ledgerService.saveBatch(ledgers);
EquipmentData e = equipmentData.get(0);
e.setFixedDate(itemData.getDate());
e.setIsFixed("1");
e.setStatus(6);
e.setItemType("5");
equipmentService.updateById(e);
List<Record> records = packageRecords(itemData, e);
recordService.saveBatch(records);
save(itemData);
} else {
return error(1, "未查询到合同信息!");
}
return success(itemData);
}
/**
* 拼装档案数据
*
* @param itemData
* @param e
* @return
*/
private List<Record> packageRecords(FixDetail itemData, EquipmentData e) {
List<Record> records = new ArrayList<>();
for (int i = 0; i < 5; i++) {
Record record = new Record();
record.setItemNum(itemData.getItemNum());
record.setItemName(e.getItemName());
record.setContractNum(e.getContractNum());
record.setSupplierName(e.getSupplierName());
record.setSupplierCode(e.getSupplierCode());
switch (i) {
case 0:
record.setType("5");
record.setFileUri(itemData.getCheckFixUri());
if (!itemData.getCheckFixUri().isEmpty()) {
records.add(record);
}
break;
case 1:
record.setType("6");
record.setFileUri(itemData.getVerifyUri());
if (!itemData.getVerifyUri().isEmpty()) {
records.add(record);
}
break;
case 2:
record.setType("7");
record.setFileUri(itemData.getPromiseUri());
if (!itemData.getPromiseUri().isEmpty()) {
records.add(record);
}
break;
case 3:
record.setType("9");
record.setFileUri(itemData.getEntityUri());
if (!itemData.getEntityUri().isEmpty()) {
records.add(record);
}
break;
case 4:
record.setType("10");
record.setFileUri(itemData.getDrawingUri());
if (!itemData.getDrawingUri().isEmpty()) {
records.add(record);
}
break;
default:
break;
}
}
List<FileRecords> otherUris = itemData.getOtherUri();
if (!otherUris.isEmpty()) {
//先查询是否有同项目编号 项目名 合同号的数据
Query entityQuery = Query.query(Criteria.where("itemNum").is(itemData.getItemNum()));
entityQuery.addCriteria(Criteria.where("itemName").is(e.getItemName()));
entityQuery.addCriteria(Criteria.where("contractNum").is(e.getContractNum()));
entityQuery.addCriteria(Criteria.where("type").is(0));
List<Record> existRecord = recordService.list(entityQuery);
if (!existRecord.isEmpty()) {
List<FileRecords> urls = existRecord.get(0).getFileUri();
urls.addAll(otherUris);
records.get(0).setFileUri(urls);
recordService.updateById(records.get(0));
} else {
Record record = new Record();
record.setItemNum(itemData.getItemNum());
record.setItemName(e.getItemName());
record.setContractNum(e.getContractNum());
record.setType("0");
record.setFileUri(otherUris);
record.setSupplierName(e.getSupplierName());
record.setSupplierCode(e.getSupplierCode());
recordService.save(record);
}
}
return records;
}
private List<Ledger> packageLedger(List<EntityItem> entityItems, List<EquipmentData> equipmentData, List<Construct> constructs) {
List<Ledger> ledgers = new ArrayList<>();
EquipmentData itemData = equipmentData.get(0);
for (EntityItem entityItem : entityItems) {
//查询toolNumber在台账表内是否存在 如果已经存在把比例改为百分之百
Query ledQuery = Query.query(Criteria.where("toolNumber").is(entityItem.getToolNumber()));
ledQuery.addCriteria(Criteria.where("deleted").is(0));
List<Ledger> ledgerList = ledgerService.list(ledQuery);
if (null != ledgerList && !ledgerList.isEmpty()) {
Ledger ledger = ledgerList.get(0);
ledger.setFinishRatio("100%");
ledgerService.updateById(ledger);
continue;
}
Ledger ledger = new Ledger();
//,模具部分
ledger.setToolNumber(entityItem.getToolNumber());
ledger.setToolName(entityItem.getToolName());
ledger.setNameplateUri(getNameplate(entityItem.getItemNum(), entityItem.getToolNumber()));
ledger.setToolUri(getToolUri(entityItem.getItemNum(), entityItem.getToolNumber()));
ledger.setProductUri(getProductUri(entityItem.getItemNum(), entityItem.getToolNumber()));
ledger.setNum(entityItem.getNum());
ledger.setCarModule(entityItem.getCarModule().stream().collect(Collectors.joining("/")));
ledger.setAssetType(entityItem.getAssetType());
ledger.setNewOrOld(entityItem.getNewOrOld());
ledger.setCavitiesNum(entityItem.getCavitiesNum());
ledger.setMaterial(entityItem.getMaterial());
ledger.setSize(entityItem.getSize());
ledger.setWeight(entityItem.getWeight());
ledger.setSapCode(entityItem.getSapCode());
//新增字段
//项目部分
ledger.setItemNum(itemData.getItemNum());
ledger.setItemName(itemData.getItemName());
ledger.setContractNum(itemData.getContractNum());
ledger.setSupplierCode(itemData.getSupplierCode());
ledger.setSupplierName(itemData.getSupplierName());
//零件部分。
Query query = Query.query(Criteria.where("itemNum").is(itemData.getItemNum()));
query.addCriteria(Criteria.where("deleted").is(0));
query.addCriteria(Criteria.where("toolNumber").is(entityItem.getToolNumber())); //新增BUG,按单个资产查询零件。
List<PartItem> partItems = partService.list(query);
//将零件编号和零件名称组合写入台账
String partCodes = partItems.stream().map(PartItem::getPartCode).collect(Collectors.joining("/"));
String partNames = partItems.stream().map(PartItem::getPartName).collect(Collectors.joining("/"));
ledger.setParCodes(partCodes);
ledger.setParNames(partNames);
ledger.setConstructList(constructs);
ledger.setIsShare("0");
//判断是否包含分摊。如果包含分摊 归拢出当前模具对总价值的占比
if (null != itemData.getProjectType() && "在建".equals(itemData.getProjectType()) && null != itemData.getLinkContract() && !itemData.getLinkContract().isEmpty()) {
ledger.setIsShare("1");
// ledger.setShareTax(itemData.getFixedRatio());
ledger.setFixedRatio(itemData.getFixedRatio());
ledger.setFinishRatio(TaxUtil.calculatePartyBOwnership(itemData.getFixedRatio()));
}
if (null != itemData.getProjectType() && "分摊".equals(itemData.getProjectType())) {
ledger.setIsShare("1");
// ledger.setShareTax(itemData.getFixedRatio());
ledger.setFixedRatio(itemData.getFixedRatio());
ledger.setFinishRatio(itemData.getFixedRatio() + "%");
}
ledger.setSecondary("0"); //资产
ledger.setAssetsSubord(entityItem.getSapCode() + "0"); //资产加次级
ledger.setEntityDesc(entityItem.getToolName()); //资产描述
ledger.setCapitalizationDate("");
ledger.setPurchasePrice(entityItem.getTaxMoney());
ledger.setImpairmentAmount("");
ledger.setBookValue("");
ledger.setCurrency("");
ledger.setCostCenter("");
ledger.setAssetClass("");
ledger.setSubject("");
ledger.setStockCode(entityItem.getToolNumber()); //存货号
ledger.setStatus("1"); //资产状态
ledger.setCategory(parseCatgory(entityItem.getNewOrOld())); //资产类别
if (itemData.getSupplierName().equals(entityItem.getLocation())) {
ledger.setPrimaryLocation(itemData.getSupplierName()); //一级存放地点
ledger.setSecondaryLocation(""); //二级存放地点
} else {
ledger.setPrimaryLocation(itemData.getSupplierName()); //一级存放地点
ledger.setSecondaryLocation(entityItem.getLocation()); //二级存放地点
}
ledger.setLife(entityItem.getModelLife()); //设计寿命
ledgers.add(ledger);
}
return ledgers;
}
private String parseCatgory(Object cellValue) {
//对象属性转CellData
if (cellValue == null) {
return "";
}
if (cellValue.equals("新制")) {
return "1";
} else if (cellValue.equals("改制")) {
return "2";
}
return "1";
}
private List<String> getToolUri(String ItemNum, String toolNumber) {
Query entityQuery = Query.query(Criteria.where("itemNum").is(ItemNum));
entityQuery.addCriteria(Criteria.where("deleted").is(0));
entityQuery.addCriteria(Criteria.where("toolNumber").is(toolNumber));
List<EntityItem> entityItems = entityService.list(entityQuery);
for (EntityItem fixTool : entityItems) {
if (toolNumber.equals(fixTool.getToolNumber())) {
List<FileRecords> files = fixTool.getPropertyUri();
if (files.size() > 0) {
return files.stream().map(FileRecords::getFileUri).collect(Collectors.toList());
}
}
}
return new ArrayList<String>();
}
private List<String> getProductUri(String ItemNum, String toolNumber) {
Query entityQuery = Query.query(Criteria.where("itemNum").is(ItemNum));
entityQuery.addCriteria(Criteria.where("deleted").is(0));
entityQuery.addCriteria(Criteria.where("toolNumber").is(toolNumber));
List<EntityItem> entityItems = entityService.list(entityQuery);
for (EntityItem fixTool : entityItems) {
if (toolNumber.equals(fixTool.getToolNumber())) {
List<FileRecords> files = fixTool.getProductUri();
if (files.size() > 0) {
return files.stream().map(FileRecords::getFileUri).collect(Collectors.toList());
}
}
}
return new ArrayList<String>();
}
private String getNameplate(String ItemNum, String toolNumber) {
Query entityQuery = Query.query(Criteria.where("itemNum").is(ItemNum));
entityQuery.addCriteria(Criteria.where("deleted").is(0));
entityQuery.addCriteria(Criteria.where("toolNumber").is(toolNumber));
List<EntityItem> entityItems = entityService.list(entityQuery);
for (EntityItem fixTool : entityItems) {
if (toolNumber.equals(fixTool.getToolNumber())) {
List<FileRecords> files = fixTool.getNameplateUri();
if (files.size() > 0) {
return files.get(0).getFileUri();
}
}
}
return "";
}
/**
* 获取当前模具下零件的付款总额
*
* @return
*/
private String getPartTax(List<PartItem> partItems, EquipmentData itemData, List<Construct> constructs) {
partItems = packagePart(partItems);
BigDecimal total = new BigDecimal("0.00");
for (PartItem item : partItems) {
if (item.getAlreadyNum().isBlank() || item.getPrice().isBlank()) {
continue;
}
BigDecimal alreadyNum = new BigDecimal(item.getAlreadyNum().trim());
BigDecimal price = new BigDecimal(item.getPrice().trim());
BigDecimal partSum = alreadyNum.multiply(price);
total = total.add(partSum);
}
Query query = Query.query(Criteria.where("itemNum").is(itemData.getItemNum()));
query.addCriteria(Criteria.where("deleted").is(0));
BigDecimal constructTotal = new BigDecimal("0.00");
for (Construct item : constructs) {
BigDecimal part = new BigDecimal(item.getPayNum().trim());
constructTotal = constructTotal.add(part);
}
BigDecimal amount = new BigDecimal(itemData.getAmount());
// 格式化为两位小数
DecimalFormat df = new DecimalFormat("0.00");
return TaxUtil.calculatePercentage(amount.subtract(constructTotal).toString(), df.format(total));
}
/**
* 拼装已收货数量为了后边算总价做准备
*
* @param partItems
* @return
*/
private List<PartItem> packagePart(List<PartItem> partItems) {
if (partItems.isEmpty()) {
return partItems;
}
for (PartItem partItem : partItems) {
//循环零件表数据 去到货表内拿子数据
Query query = Query.query(Criteria.where("partId").is(partItem.getId()));
query.addCriteria(Criteria.where("deleted").is(0));
query.addCriteria(Criteria.where("partCode").is(partItem.getPartCode()));
List<ShareItem> list = shareService.list(query);
int sum = list.stream()
.filter(Objects::nonNull) // 过滤 null 值
.mapToInt(ShareItem::getNum)
.sum();
partItem.setAlreadyNum(String.valueOf(sum));
}
return partItems;
}
@Override
public CommonResult uptFixDetail(FixDetail itemData) {
//验证项目是否可以转固
Query query = Query.query(Criteria.where("itemNum").is(itemData.getItemNum()));
query.addCriteria(Criteria.where("deleted").is(0));
query.addCriteria(Criteria.where("status").is(5));
List<EquipmentData> finance = equipmentService.list(query);
if (!finance.isEmpty()) {
itemData.setFinanceStatus(0);
updateById(itemData);
} else {
return error(1, "项目未处于待转固状态!");
}
return success(itemData);
}
@Override
public ByteArrayOutputStream exportToWord(List<EntityItem> entityItems) throws Exception {
return exportToWordStream(entityItems);
}
public ByteArrayOutputStream exportToWordStream(List<EntityItem> records) throws Exception {
// 创建临时文件作为缓冲区
File tempFile = File.createTempFile("word_export", ".docx");
try (FileOutputStream fos = new FileOutputStream(tempFile);
XWPFDocument doc = new XWPFDocument()) {
// 设置页面布局
setupPageLayout(doc);
// 初始化表格和计数器
XWPFTable currentTable = createNewTable(doc);
int currentPageRowCount = 1;
int num = 0;
// 处理所有记录
for (int i = 0; i < records.size(); i++) {
EntityItem record = records.get(i);
// 分批处理:定期写入磁盘释放内存
if (i > 0 && i % BATCH_SIZE == 0) {
doc.write(fos);
fos.flush();
doc.removeBodyElement(doc.getPosOfTable(currentTable));
currentTable = createNewTable(doc);
}
// 计算图片行数
int maxImageRows = calculateMaxImageRows(
record.getPropertyUri(),
record.getNameplateUri(),
record.getProductUri()
);
// 分页检查
if (currentPageRowCount + maxImageRows > PAGE_SIZE_LIMIT) {
doc.createParagraph().setPageBreak(true);
currentTable = createNewTable(doc);
currentPageRowCount = 1;
}
// 创建数据行
XWPFTableRow row = currentTable.createRow();
row.setCantSplitRow(true);
// 文本列
createFixedWidthTextCell(row, 0, String.valueOf(++num), 800);
createFixedWidthTextCell(row, 1, record.getToolNumber(), 1000);
createFixedWidthTextCell(row, 2, record.getToolName(), 1000);
// 图片列(使用流式处理)
addImagesToCellWithStream(row.getCell(3), record.getPropertyUri(), 6800, 2, 1);
addImagesToCellWithStream(row.getCell(4), record.getNameplateUri(), 3000, 1, 2);
addImagesToCellWithStream(row.getCell(5), record.getProductUri(), 3000, 2, 3);
currentPageRowCount += maxImageRows;
}
// 添加页码并写入最终内容
addPageNumbers(doc);
doc.write(fos);
// 从临时文件读取到字节流
return readTempFileToOutputStream(tempFile);
} finally {
// 确保删除临时文件
if (tempFile.exists()) {
tempFile.delete();
}
}
}
// 读取临时文件到字节流
private ByteArrayOutputStream readTempFileToOutputStream(File tempFile) throws IOException {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(tempFile)) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
outputStream.write(buffer, 0, len);
}
return outputStream;
}
}
// 统一表格创建方法
private XWPFTable createNewTable(XWPFDocument doc) {
XWPFTable table = doc.createTable();
setupTable(table);
createTableHeader(table);
return table;
}
// 优化图片行数计算
private int calculateMaxImageRows(List<FileRecords>... imageLists) {
int maxRows = 0;
for (List<FileRecords> list : imageLists) {
if (list != null && !list.isEmpty()) {
int itemCount = list.size();
int cols = (list == imageLists[2]) ? 4 : 2; // 产品图4列,其它2列
int rows = (int) Math.ceil((double) itemCount / cols);
maxRows = Math.max(maxRows, rows);
}
}
return maxRows > 0 ? maxRows : 1; // 至少1行
}
// 页面设置
private static void setupPageLayout(XWPFDocument doc) {
CTSectPr sectPr = doc.getDocument().getBody().addNewSectPr();
CTPageSz pageSize = sectPr.addNewPgSz();
pageSize.setOrient(STPageOrientation.LANDSCAPE);
pageSize.setW(BigInteger.valueOf(16840));
pageSize.setH(BigInteger.valueOf(11900));
CTPageMar pageMar = sectPr.addNewPgMar();
pageMar.setLeft(BigInteger.valueOf(390));
pageMar.setRight(BigInteger.valueOf(390));
pageMar.setTop(BigInteger.valueOf(900));
pageMar.setBottom(BigInteger.valueOf(900));
pageMar.setFooter(BigInteger.valueOf(900));
}
// 表格设置
private static void setupTable(XWPFTable table) {
table.setWidth("100%");
int[] columnWidths = {500, 500, 500, 5000, 2000, 5000};
CTTbl cttbl = table.getCTTbl();
CTTblGrid tblGrid = cttbl.getTblGrid() != null ?
cttbl.getTblGrid() :
cttbl.addNewTblGrid();
// 清空现有网格列
if (tblGrid.sizeOfGridColArray() > 0) {
tblGrid.removeGridCol(0);
}
// 添加新网格列
for (int width : columnWidths) {
CTTblGridCol gridCol = tblGrid.addNewGridCol();
gridCol.setW(BigInteger.valueOf(width));
}
}
// 创建表头
private static void createTableHeader(XWPFTable table) {
XWPFTableRow headerRow = table.getRow(0);
for (int i = 0; i < 6; i++) {
XWPFTableCell cell = headerRow.getCell(i) != null ?
headerRow.getCell(i) : headerRow.createCell();
// 清除现有内容
for (int j = cell.getParagraphs().size() - 1; j >= 0; j--) {
cell.removeParagraph(j);
}
// 添加新内容
XWPFParagraph para = cell.addParagraph();
para.setAlignment(ParagraphAlignment.CENTER);
XWPFRun run = para.createRun();
run.setBold(true);
run.setFontSize(12);
run.setText(getHeaderText(i));
}
}
// 固定宽度文本单元格
private void createFixedWidthTextCell(XWPFTableRow row, int pos, String text, int width) {
XWPFTableCell cell = row.getCell(pos) != null ? row.getCell(pos) : row.createCell();
// 清除现有内容
for (int i = cell.getParagraphs().size() - 1; i >= 0; i--) {
cell.removeParagraph(i);
}
// 设置固定宽度
CTTcPr tcPr = cell.getCTTc().getTcPr();
if (tcPr == null) tcPr = cell.getCTTc().addNewTcPr();
tcPr.addNewTcW().setW(BigInteger.valueOf(width));
// 添加内容
XWPFParagraph para = cell.addParagraph();
para.setAlignment(ParagraphAlignment.CENTER);
para.setWordWrap(true);
XWPFRun run = para.createRun();
run.setText(text);
}
// 图片流获取方法
private InputStream getImageStream(String uri) throws IOException {
URL url = new URL(uri);
URLConnection conn = url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
return conn.getInputStream();
}
// 图片尺寸计算
private int[] calculateImageDimensions(int flags) {
switch (flags) {
case 1:
return new int[]{135, 120}; // 属性图
case 2:
return new int[]{245, 120}; // 铭牌
case 3:
return new int[]{60, 60}; // 产品图
default:
return new int[]{120, 120};// 默认
}
}
// 表头文本
private static String getHeaderText(int colIndex) {
String[] headers = {"序号", "工装编号", "资产名称", "关联图片", "铭牌", "产品图片"};
return colIndex < headers.length ? headers[colIndex] : "";
}
// 添加页码
private static void addPageNumbers(XWPFDocument doc) {
XWPFFooter footer = doc.createFooter(HeaderFooterType.DEFAULT);
XWPFParagraph para = footer.createParagraph();
para.setAlignment(ParagraphAlignment.CENTER);
XWPFRun run = para.createRun();
run.getCTR().addNewFldChar().setFldCharType(STFldCharType.BEGIN);
run.getCTR().addNewInstrText().setStringValue("PAGE");
run.getCTR().addNewFldChar().setFldCharType(STFldCharType.END);
run.setText(" / ");
run.getCTR().addNewFldChar().setFldCharType(STFldCharType.BEGIN);
run.getCTR().addNewInstrText().setStringValue("NUMPAGES");
run.getCTR().addNewFldChar().setFldCharType(STFldCharType.END);
}
// 图片类型检测
private int determineImageType(String fileName) {
if (fileName == null || fileName.lastIndexOf(".") == -1) {
return XWPFDocument.PICTURE_TYPE_PNG; // 默认PNG
}
String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
switch (ext) {
case "png":
return XWPFDocument.PICTURE_TYPE_PNG;
case "jpg":
case "jpeg":
return XWPFDocument.PICTURE_TYPE_JPEG;
case "gif":
return XWPFDocument.PICTURE_TYPE_GIF;
case "bmp":
return XWPFDocument.PICTURE_TYPE_BMP;
default:
return XWPFDocument.PICTURE_TYPE_PNG;
}
}
// 修改图片处理方法
private void addImagesToCellWithStream(XWPFTableCell cell,
List<FileRecords> imagePaths,
int cellWidth,
int colsPerRow,
int flags) {
if (cell == null || imagePaths == null || imagePaths.isEmpty()) return;
// 清除单元格现有内容
for (int i = cell.getParagraphs().size() - 1; i >= 0; i--) {
cell.removeParagraph(i);
}
// 设置单元格宽度
CTTcPr tcPr = cell.getCTTc().getTcPr();
if (tcPr == null) tcPr = cell.getCTTc().addNewTcPr();
tcPr.addNewTcW().setW(BigInteger.valueOf(cellWidth));
XWPFParagraph currentPara = cell.addParagraph();
currentPara.setAlignment(ParagraphAlignment.LEFT);
XWPFRun currentRun = currentPara.createRun();
for (int i = 0; i < imagePaths.size(); i++) {
FileRecords imagePath = imagePaths.get(i);
try {
// 获取优化后的图片流
try (InputStream is = getOptimizedImageStream(imagePath.getFileUri(), flags)) {
if (is != null) {
int imageType = determineImageType(imagePath.getFileUri());
int[] dimensions = calculateImageDimensions(flags);
// 添加压缩后的图片
currentRun.addPicture(
is,
imageType,
imagePath.getFileUri(),
Units.toEMU(dimensions[0]),
Units.toEMU(dimensions[1])
);
}
}
// 换行控制
if ((i + 1) % colsPerRow == 0 && (i + 1) < imagePaths.size()) {
currentPara = cell.addParagraph();
currentPara.setAlignment(ParagraphAlignment.LEFT);
currentRun = currentPara.createRun();
}
} catch (Exception e) {
currentRun.setText("[图片处理失败: " + e.getMessage() + "]");
}
}
}
// 图片优化处理
private InputStream getOptimizedImageStream(String uri, int flags) throws IOException {
URL url = new URL(uri);
URLConnection conn = url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
try (InputStream originalStream = conn.getInputStream()) {
// 获取原始图片
BufferedImage originalImage = ImageIO.read(originalStream);
if (originalImage == null) return null;
// 计算目标尺寸并缩放
int[] targetDimensions = calculateTargetDimensions(originalImage, flags);
BufferedImage scaledImage = scaleImage(originalImage, targetDimensions[0], targetDimensions[1]);
// 压缩并转换格式
return compressImage(scaledImage, MAX_IMAGE_SIZE_KB * 1024);
}
}
// 计算优化后的尺寸
private int[] calculateTargetDimensions(BufferedImage image, int flags) {
int[] displayDims = calculateImageDimensions(flags);
int displayWidth = displayDims[0];
int displayHeight = displayDims[1];
// 保持原始宽高比
double aspectRatio = (double) image.getWidth() / image.getHeight();
int targetWidth = displayWidth;
int targetHeight = (int) (targetWidth / aspectRatio);
// 确保不小于显示尺寸
if (targetHeight < displayHeight) {
targetHeight = displayHeight;
targetWidth = (int) (targetHeight * aspectRatio);
}
// 限制最大尺寸(避免过大)
int maxDimension = 1500; // 最大像素尺寸
if (targetWidth > maxDimension || targetHeight > maxDimension) {
if (targetWidth > targetHeight) {
targetWidth = maxDimension;
targetHeight = (int) (maxDimension / aspectRatio);
} else {
targetHeight = maxDimension;
targetWidth = (int) (maxDimension * aspectRatio);
}
}
return new int[]{targetWidth, targetHeight};
}
// 图片缩放
private BufferedImage scaleImage(BufferedImage original, int width, int height) {
BufferedImage scaled = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = scaled.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(original, 0, 0, width, height, null);
g.dispose();
return scaled;
}
// 图片压缩
private InputStream compressImage(BufferedImage image, long maxSize) throws IOException {
float quality = 0.8f; // 初始质量
ByteArrayOutputStream output = new ByteArrayOutputStream();
// 迭代压缩直到满足大小
do {
output.reset();
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
// 设置压缩参数
if (param.canWriteCompressed()) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
}
try (ImageOutputStream ios = ImageIO.createImageOutputStream(output)) {
writer.setOutput(ios);
writer.write(null, new IIOImage(image, null, null), param);
}
writer.dispose();
quality -= 0.1f; // 降低质量
} while (output.size() > maxSize && quality > 0.3f);
// 转换为JPEG格式(更好的压缩率)
return new ByteArrayInputStream(output.toByteArray());
}
}帮忙整理下代码注释 间隔等等给一份完整代码