package com.doumee.service.business.impl;
|
|
import com.alibaba.fastjson.JSON;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.doumee.biz.system.SystemDictDataBiz;
|
import com.doumee.core.annotation.excel.ExcelEmbeddedImageReader;
|
import com.doumee.core.annotation.excel.AsyncImportExcelSupport;
|
import com.doumee.core.annotation.excel.ExcelImporter;
|
import com.doumee.core.annotation.excel.RowEmbeddedImages;
|
import com.doumee.core.constants.ResponseStatus;
|
import com.doumee.core.exception.BusinessException;
|
import com.doumee.core.model.LoginUserInfo;
|
import com.doumee.core.model.PageData;
|
import com.doumee.core.model.PageWrap;
|
import com.doumee.core.utils.Constants;
|
import com.doumee.core.utils.PinYinUtil;
|
import com.doumee.core.utils.Utils;
|
import com.doumee.dao.business.*;
|
import com.doumee.dao.business.model.*;
|
import com.doumee.dao.business.model.dto.OssModel;
|
import com.doumee.service.CateParamSelectService;
|
import com.doumee.service.business.BaseDataService;
|
import com.doumee.service.business.GoodsImportTaskService;
|
import org.apache.commons.lang3.StringUtils;
|
import org.apache.poi.ss.usermodel.*;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.shiro.SecurityUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.context.annotation.Lazy;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.web.multipart.MultipartFile;
|
|
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletResponse;
|
import java.io.File;
|
import java.io.FileOutputStream;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.OutputStream;
|
import java.math.BigDecimal;
|
import java.net.URLEncoder;
|
import java.util.*;
|
|
@Service
|
public class GoodsImportTaskServiceImpl implements GoodsImportTaskService {
|
|
private static final String[] ASYNC_TEMPLATE_HEADERS = {
|
"商品文件夹名称", "商品名称", "商品类别", "商品品牌",
|
"指导价", "入手价", "产品参数", "商品二级类别", "商品主图", "商品多图"
|
};
|
|
/** 表头字体改为黑色的列:商品二级类别、商品主图、商品多图 */
|
private static final int[] BLACK_HEADER_COLS = {7, 8, 9};
|
|
/** 商品主图、商品多图列索引(与 GoodsImportAsync.index 一致) */
|
private static final int COL_MAIN_IMAGE = 8;
|
private static final int COL_MULTI_IMAGE = 9;
|
|
@Autowired
|
private GoodsImportTaskMapper goodsImportTaskMapper;
|
@Autowired
|
private GoodsMapper goodsMapper;
|
@Autowired
|
private CategoryMapper categoryMapper;
|
@Autowired
|
private BrandMapper brandMapper;
|
@Autowired
|
private CateParamMapper cateParamMapper;
|
@Autowired
|
private GoodsParamMapper goodsParamMapper;
|
@Autowired
|
private MultifileMapper multifileMapper;
|
@Autowired
|
private BaseDataService baseDataService;
|
@Autowired
|
private SystemDictDataBiz systemDictDataBiz;
|
@Autowired
|
private CateParamSelectService cateParamSelectService;
|
@Autowired
|
@Lazy
|
private GoodsImportTaskWorker goodsImportTaskWorker;
|
|
@Override
|
public void exportImportAsyncTemplate(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
|
String fileName = "产品异步导入表" + System.currentTimeMillis() + ".xlsx";
|
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("static/file/goodsExcelTemp.xlsx");
|
Workbook workbook = new XSSFWorkbook(inputStream);
|
Sheet sheet0 = workbook.getSheetAt(0);
|
Row headerRow = sheet0.getRow(0);
|
if (headerRow == null) {
|
headerRow = sheet0.createRow(0);
|
}
|
for (int i = 0; i < ASYNC_TEMPLATE_HEADERS.length; i++) {
|
Cell cell = headerRow.getCell(i);
|
if (cell == null) {
|
cell = headerRow.createCell(i);
|
}
|
cell.setCellValue(ASYNC_TEMPLATE_HEADERS[i]);
|
}
|
applyTemplateHeaderStyles(workbook, headerRow);
|
applyTemplateColumnWidths(sheet0);
|
CellStyle wrapStyle = workbook.createCellStyle();
|
wrapStyle.setWrapText(true);
|
fillTemplateExampleRow(sheet0, wrapStyle);
|
Sheet sheet = workbook.getSheetAt(1);
|
CellStyle cs = workbook.createCellStyle();
|
cs.setWrapText(true);
|
Row row = sheet.createRow(1);
|
List<Category> categoryList = categoryMapper.selectList(
|
new QueryWrapper<Category>().eq("ISDELETED", 0).eq("COMPANY_ID", loginUserInfo.getCompanyId()));
|
categoryList.forEach(i -> i.setParamList(
|
cateParamMapper.selectList(new QueryWrapper<CateParam>().eq("ISDELETED", 0).eq("CATEGORY_ID", i.getId()))));
|
if (categoryList != null) {
|
for (int i = 0; i < categoryList.size(); i++) {
|
Category category = categoryList.get(i);
|
row = sheet.createRow(i + 1);
|
row.createCell(0).setCellValue(category.getName());
|
List<CateParam> paramList = category.getParamList();
|
StringBuilder param = new StringBuilder();
|
if (paramList != null) {
|
for (int j = 0; j < paramList.size(); j++) {
|
if (j > 0) {
|
param.append("\r\n");
|
}
|
param.append(paramList.get(j).getName()).append(":");
|
}
|
}
|
Cell cell = row.createCell(1);
|
cell.setCellStyle(cs);
|
cell.setCellValue(param.toString());
|
}
|
}
|
setResponseHeader(response, fileName);
|
OutputStream os = response.getOutputStream();
|
workbook.write(os);
|
os.flush();
|
os.close();
|
workbook.close();
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Integer submitTask(MultipartFile file) {
|
LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
|
if (hasUnfinishedTask(user.getCompanyId())) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "当前存在未完成的导入任务,请等待完成后再提交");
|
}
|
if (file == null || file.isEmpty()) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "导入文件不能为空");
|
}
|
String originalName = sanitizeImportFileName(StringUtils.defaultString(file.getOriginalFilename(), "import.xlsx"));
|
String saveDir = buildImportDir(user.getCompanyId());
|
File dir = new File(saveDir);
|
if (!dir.exists() && !dir.mkdirs()) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), "创建导入目录失败");
|
}
|
String saveName = System.currentTimeMillis() + "_" + originalName;
|
File saved = new File(dir, saveName);
|
try {
|
saveImportFile(file, saved);
|
} catch (Exception e) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), "保存导入文件失败:" + e.getMessage());
|
}
|
GoodsImportTask task = new GoodsImportTask();
|
task.setCompanyId(user.getCompanyId());
|
task.setCreator(user.getId());
|
task.setCreateDate(new Date());
|
task.setEditDate(new Date());
|
task.setIsdeleted(Constants.ZERO);
|
task.setFileName(originalName);
|
task.setFilePath(saved.getAbsolutePath());
|
task.setStatus(GoodsImportTask.STATUS_PENDING);
|
task.setTotalRows(0);
|
task.setSuccessRows(0);
|
task.setFailedRows(0);
|
task.setProgress(0);
|
goodsImportTaskMapper.insert(task);
|
goodsImportTaskWorker.runTask(task.getId());
|
return task.getId();
|
}
|
|
@Override
|
public void processTask(Integer taskId) {
|
GoodsImportTask task = goodsImportTaskMapper.selectById(taskId);
|
if (task == null || !Constants.equalsInteger(Constants.ZERO, task.getIsdeleted())) {
|
return;
|
}
|
task.setStatus(GoodsImportTask.STATUS_PROCESSING);
|
task.setEditDate(new Date());
|
goodsImportTaskMapper.updateById(task);
|
List<String> errorLines = new ArrayList<>();
|
int success = 0;
|
int failed = 0;
|
int rowNum = 1;
|
try {
|
ExcelImporter ie = new ExcelImporter(new File(task.getFilePath()), 0, 0);
|
List<GoodsImportAsync> dataList = ie.getDataList(GoodsImportAsync.class, null);
|
if (dataList == null || dataList.isEmpty()) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "录入数据为空");
|
}
|
AsyncImportExcelSupport.ColumnMapping columnMapping =
|
AsyncImportExcelSupport.readAndApplyTextFields(task.getFilePath(), 0, 0, dataList);
|
task.setTotalRows(dataList.size());
|
goodsImportTaskMapper.updateById(task);
|
|
Map<Integer, RowEmbeddedImages> rowImageMap = ExcelEmbeddedImageReader.read(
|
task.getFilePath(), 0, 0, columnMapping.getMainImageCol(), columnMapping.getMultiImageCol());
|
|
LoginUserInfo user = new LoginUserInfo();
|
user.setId(task.getCreator());
|
user.setCompanyId(task.getCompanyId());
|
|
List<Brand> brandList = brandMapper.selectList(new LambdaQueryWrapper<Brand>().eq(Brand::getIsdeleted, Constants.ZERO)
|
.and(w -> w.eq(Brand::getCompanyId, task.getCompanyId()).or().eq(Brand::getType, Constants.ONE)));
|
List<Goods> goodsList = goodsMapper.selectList(new LambdaQueryWrapper<Goods>().eq(Goods::getIsdeleted, Constants.ZERO)
|
.eq(Goods::getCompanyId, task.getCompanyId()));
|
List<Category> categoryList = categoryMapper.selectList(new LambdaQueryWrapper<Category>().eq(Category::getIsdeleted, Constants.ZERO)
|
.eq(Category::getCompanyId, task.getCompanyId()));
|
Map<Integer, List<Category>> subCategoryMap = buildSubCategoryMap(task.getCompanyId());
|
List<CateParam> allParamsList = cateParamMapper.selectList(new LambdaQueryWrapper<CateParam>().eq(CateParam::getIsdeleted, Constants.ZERO));
|
OssModel ossModel = baseDataService.initOssModel();
|
|
int processed = 0;
|
int dataStartRow = 1;
|
for (int i = 0; i < dataList.size(); i++) {
|
GoodsImportAsync row = dataList.get(i);
|
int excelRowIndex = dataStartRow + i;
|
rowNum = excelRowIndex + 1;
|
if (isBlankRow(row)) {
|
processed++;
|
updateProgress(task, processed, success, failed);
|
continue;
|
}
|
RowEmbeddedImages rowImages = rowImageMap.getOrDefault(excelRowIndex, RowEmbeddedImages.empty());
|
try {
|
importOneRow(row, rowNum, user, rowImages, brandList, goodsList, categoryList,
|
subCategoryMap, allParamsList, ossModel);
|
success++;
|
} catch (BusinessException e) {
|
failed++;
|
errorLines.add("第【" + rowNum + "】行:" + e.getMessage());
|
} catch (Exception e) {
|
failed++;
|
errorLines.add("第【" + rowNum + "】行:导入异常");
|
}
|
processed++;
|
updateProgress(task, processed, success, failed);
|
}
|
task.setStatus(GoodsImportTask.STATUS_SUCCESS);
|
task.setSuccessRows(success);
|
task.setFailedRows(failed);
|
task.setProgress(100);
|
if (!errorLines.isEmpty()) {
|
task.setErrorMessage("部分行导入失败,共 " + failed + " 行");
|
task.setErrorDetail(JSON.toJSONString(errorLines));
|
if (success == 0) {
|
task.setStatus(GoodsImportTask.STATUS_FAILED);
|
task.setErrorMessage("全部导入失败");
|
}
|
}
|
cateParamSelectService.dealCateParamSelect();
|
} catch (BusinessException e) {
|
task.setStatus(GoodsImportTask.STATUS_FAILED);
|
task.setErrorMessage(e.getMessage());
|
task.setFailedRows(Math.max(failed, 1));
|
} catch (Exception e) {
|
task.setStatus(GoodsImportTask.STATUS_FAILED);
|
task.setErrorMessage("导入任务执行异常,请稍后重试");
|
if (!errorLines.isEmpty()) {
|
task.setErrorDetail(JSON.toJSONString(errorLines));
|
}
|
} finally {
|
task.setEditDate(new Date());
|
goodsImportTaskMapper.updateById(task);
|
}
|
}
|
|
private void importOneRow(GoodsImportAsync m, int num, LoginUserInfo user, RowEmbeddedImages rowImages,
|
List<Brand> brandList, List<Goods> goodsList, List<Category> categoryList,
|
Map<Integer, List<Category>> subCategoryMap, List<CateParam> allParamsList,
|
OssModel ossModel) {
|
if (StringUtils.isBlank(m.getName()) || StringUtils.isBlank(m.getCategory())
|
|| StringUtils.isBlank(m.getBrand()) || StringUtils.isBlank(m.getZdPrice())
|
|| StringUtils.isBlank(m.getPrice())) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "数据无效,请检查名称/类别/品牌/价格");
|
}
|
if (StringUtils.isNotBlank(m.getId())) {
|
Goods existsFolder = new Goods();
|
existsFolder.setRemark(m.getId());
|
existsFolder.setCompanyId(user.getCompanyId());
|
existsFolder.setIsdeleted(Constants.ZERO);
|
existsFolder = goodsMapper.selectOne(new QueryWrapper<>(existsFolder).last(" limit 1"));
|
if (existsFolder != null) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "商品图片文件夹名称重复");
|
}
|
}
|
Category cate = getTopCategoryByName(m.getCategory(), categoryList);
|
if (cate == null) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "商品类别无效");
|
}
|
Category subCate = null;
|
String subCategoryName = normalizeCategoryName(m.getSubCategory());
|
if (StringUtils.isNotBlank(subCategoryName)) {
|
subCate = matchSubCategoryUnderParent(cate, subCategoryName, subCategoryMap, user.getCompanyId());
|
if (subCate == null) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),
|
"商品二级类别【" + subCategoryName + "】在一级类别【"
|
+ normalizeCategoryName(cate.getName()) + "】的子类别中不存在");
|
}
|
}
|
Brand brand = getBrandByName(m.getBrand(), brandList);
|
if (brand == null) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "商品品牌无效");
|
}
|
if (findGoodsByName(m.getName(), goodsList) != null) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "产品名称【" + m.getName() + "】已存在");
|
}
|
|
Goods newModel = new Goods();
|
if (StringUtils.isNotBlank(m.getId())) {
|
newModel.setRemark(m.getId());
|
}
|
newModel.setCategoryId(cate.getId());
|
if (subCate != null) {
|
newModel.setSubCategoryId(subCate.getId());
|
}
|
newModel.setBrandId(brand.getId());
|
newModel.setIsdeleted(Constants.ZERO);
|
newModel.setCreator(user.getId());
|
newModel.setCompanyId(user.getCompanyId());
|
newModel.setCreateDate(new Date());
|
newModel.setName(m.getName().trim());
|
newModel.setStatus(Constants.ZERO);
|
try {
|
newModel.setZdPrice(BigDecimal.valueOf(Double.parseDouble(m.getZdPrice().trim())));
|
newModel.setPrice(BigDecimal.valueOf(Double.parseDouble(m.getPrice().trim())));
|
} catch (Exception e) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "指导价或入手价无效");
|
}
|
newModel.setPinyin(PinYinUtil.getFullSpell(newModel.getName()));
|
newModel.setShortPinyin(PinYinUtil.getFirstSpell(newModel.getName()));
|
|
String goodsFolder = ossModel.getGoodsFolder();
|
String mainImg = null;
|
if (rowImages.getMainImage() != null) {
|
mainImg = uploadEmbeddedImage(ossModel, goodsFolder, rowImages.getMainImage());
|
}
|
|
List<String> multiUrls = new ArrayList<>();
|
if (rowImages.getMultiImages() != null) {
|
for (RowEmbeddedImages.EmbeddedImageItem item : rowImages.getMultiImages()) {
|
String url = uploadEmbeddedImage(ossModel, goodsFolder, item);
|
if (StringUtils.isNotBlank(url)) {
|
multiUrls.add(url);
|
}
|
}
|
}
|
|
if (StringUtils.isNotBlank(mainImg)) {
|
newModel.setImgurl(mainImg);
|
}
|
|
goodsMapper.insert(newModel);
|
goodsList.add(newModel);
|
dealGoodsParam(cate, newModel, m.getParamStr(), allParamsList, num);
|
dealMultifiles(multiUrls, newModel);
|
}
|
|
@Override
|
public PageData<GoodsImportTask> findPage(PageWrap<GoodsImportTask> pageWrap) {
|
LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
|
IPage<GoodsImportTask> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
|
QueryWrapper<GoodsImportTask> wrapper = new QueryWrapper<>();
|
wrapper.eq("COMPANY_ID", user.getCompanyId());
|
wrapper.eq("ISDELETED", Constants.ZERO);
|
GoodsImportTask model = pageWrap.getModel();
|
if (model != null) {
|
if (model.getStatus() != null) {
|
wrapper.eq("STATUS", model.getStatus());
|
}
|
if (model.getCreateDateStart() != null) {
|
wrapper.ge("CREATE_DATE", model.getCreateDateStart());
|
}
|
if (model.getCreateDateEnd() != null) {
|
wrapper.le("CREATE_DATE", model.getCreateDateEnd());
|
}
|
}
|
wrapper.orderByDesc("ID");
|
IPage<GoodsImportTask> result = goodsImportTaskMapper.selectPage(page, wrapper);
|
if (result.getRecords() != null) {
|
result.getRecords().forEach(this::fillStatusText);
|
}
|
return PageData.from(result);
|
}
|
|
@Override
|
public GoodsImportTask findById(Integer id) {
|
LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
|
GoodsImportTask task = goodsImportTaskMapper.selectById(id);
|
if (task == null || !Constants.equalsInteger(Constants.ZERO, task.getIsdeleted())
|
|| !user.getCompanyId().equals(task.getCompanyId())) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "任务不存在");
|
}
|
fillStatusText(task);
|
return task;
|
}
|
|
@Override
|
public boolean hasUnfinishedTask(Integer companyId) {
|
Long count = goodsImportTaskMapper.selectCount(new LambdaQueryWrapper<GoodsImportTask>()
|
.eq(GoodsImportTask::getCompanyId, companyId)
|
.eq(GoodsImportTask::getIsdeleted, Constants.ZERO)
|
.in(GoodsImportTask::getStatus, GoodsImportTask.STATUS_PENDING, GoodsImportTask.STATUS_PROCESSING));
|
return count != null && count > 0;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteById(Integer id) {
|
LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
|
GoodsImportTask task = goodsImportTaskMapper.selectById(id);
|
if (task == null || !Constants.equalsInteger(Constants.ZERO, task.getIsdeleted())
|
|| !user.getCompanyId().equals(task.getCompanyId())) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "任务不存在");
|
}
|
if (Constants.equalsInteger(GoodsImportTask.STATUS_PENDING, task.getStatus())
|
|| Constants.equalsInteger(GoodsImportTask.STATUS_PROCESSING, task.getStatus())) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "待处理或处理中的任务无法删除");
|
}
|
task.setIsdeleted(Constants.ONE);
|
task.setEditor(user.getId());
|
task.setEditDate(new Date());
|
goodsImportTaskMapper.updateById(task);
|
removeTaskFile(task.getFilePath());
|
}
|
|
private void removeTaskFile(String filePath) {
|
if (StringUtils.isBlank(filePath)) {
|
return;
|
}
|
try {
|
File file = new File(filePath);
|
if (file.isFile()) {
|
file.delete();
|
}
|
} catch (Exception ignored) {
|
}
|
}
|
|
private void updateProgress(GoodsImportTask task, int processed, int success, int failed) {
|
int total = Math.max(task.getTotalRows(), 1);
|
task.setProgress(Math.min(100, (int) (processed * 100.0 / total)));
|
task.setSuccessRows(success);
|
task.setFailedRows(failed);
|
task.setEditDate(new Date());
|
goodsImportTaskMapper.updateById(task);
|
}
|
|
private void fillStatusText(GoodsImportTask task) {
|
if (task == null || task.getStatus() == null) {
|
return;
|
}
|
switch (task.getStatus()) {
|
case GoodsImportTask.STATUS_PENDING:
|
task.setStatusText("待处理");
|
break;
|
case GoodsImportTask.STATUS_PROCESSING:
|
task.setStatusText("处理中");
|
break;
|
case GoodsImportTask.STATUS_SUCCESS:
|
task.setStatusText("成功");
|
break;
|
case GoodsImportTask.STATUS_FAILED:
|
task.setStatusText("失败");
|
break;
|
default:
|
task.setStatusText("未知");
|
}
|
}
|
|
private boolean isBlankRow(GoodsImportAsync row) {
|
return StringUtils.isBlank(row.getName()) && StringUtils.isBlank(row.getCategory())
|
&& StringUtils.isBlank(row.getBrand()) && StringUtils.isBlank(row.getZdPrice())
|
&& StringUtils.isBlank(row.getPrice()) && StringUtils.isBlank(row.getId());
|
}
|
|
private String buildImportDir(Integer companyId) {
|
String goodsDir = buildImportDirByBase(companyId, Constants.GOODS_IMG_DIR);
|
if (canCreateDir(goodsDir)) {
|
return goodsDir;
|
}
|
String fileDir = buildImportDirByBase(companyId, Constants.FILE_DIR);
|
if (canCreateDir(fileDir)) {
|
return fileDir;
|
}
|
String tmpDir = normalizeDirPath(System.getProperty("java.io.tmpdir"))
|
+ "preselect" + File.separator + "import_tasks" + File.separator + companyId;
|
if (!canCreateDir(tmpDir)) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), "创建导入目录失败");
|
}
|
return tmpDir;
|
}
|
|
private String buildImportDirByBase(Integer companyId, String baseKey) {
|
String base = getDictCode(baseKey);
|
if (StringUtils.isBlank(base)) {
|
return "";
|
}
|
String proDir = getDictCode(Constants.PROJECTS);
|
return normalizeDirPath(base) + normalizeDirPath(proDir) + companyId + File.separator + "import_tasks";
|
}
|
|
private String getDictCode(String label) {
|
try {
|
com.doumee.dao.system.model.SystemDictData data = systemDictDataBiz.queryByCode(Constants.SYSTEM, label);
|
return data == null ? "" : StringUtils.defaultString(data.getCode(), "");
|
} catch (Exception e) {
|
return "";
|
}
|
}
|
|
private String normalizeDirPath(String path) {
|
if (StringUtils.isBlank(path)) {
|
return "";
|
}
|
String normalized = path.replace('/', File.separatorChar).replace('\\', File.separatorChar);
|
if (!normalized.endsWith(File.separator)) {
|
normalized += File.separator;
|
}
|
return normalized;
|
}
|
|
private boolean canCreateDir(String dirPath) {
|
if (StringUtils.isBlank(dirPath)) {
|
return false;
|
}
|
File dir = new File(dirPath);
|
return dir.exists() || dir.mkdirs();
|
}
|
|
private String sanitizeImportFileName(String fileName) {
|
String name = fileName.replace("\\", "_").replace("/", "_").replace(":", "_");
|
if (!name.toLowerCase(Locale.ROOT).endsWith(".xlsx") && !name.toLowerCase(Locale.ROOT).endsWith(".xls")) {
|
name = name + ".xlsx";
|
}
|
return name;
|
}
|
|
private void saveImportFile(MultipartFile file, File dest) throws IOException {
|
File target = dest.getAbsoluteFile();
|
File parent = target.getParentFile();
|
if (parent != null && !parent.exists() && !parent.mkdirs()) {
|
throw new IOException("无法创建目录: " + parent.getAbsolutePath());
|
}
|
if (target.exists() && !target.delete()) {
|
throw new IOException("无法覆盖已存在文件: " + target.getAbsolutePath());
|
}
|
try (InputStream in = file.getInputStream(); FileOutputStream out = new FileOutputStream(target)) {
|
byte[] buffer = new byte[8192];
|
int len;
|
while ((len = in.read(buffer)) != -1) {
|
out.write(buffer, 0, len);
|
}
|
out.flush();
|
}
|
}
|
|
private String uploadEmbeddedImage(OssModel ossModel, String folder, RowEmbeddedImages.EmbeddedImageItem item) {
|
if (item == null || item.getData() == null || item.getData().length == 0) {
|
return null;
|
}
|
String ext = StringUtils.defaultIfBlank(item.getExtension(), ".jpg");
|
File temp = null;
|
try {
|
temp = File.createTempFile("goods_import_img_", ext);
|
try (FileOutputStream out = new FileOutputStream(temp)) {
|
out.write(item.getData());
|
}
|
return baseDataService.getOssImgurl(ossModel, folder, temp);
|
} catch (Exception e) {
|
return null;
|
} finally {
|
if (temp != null && temp.exists() && !temp.delete()) {
|
temp.deleteOnExit();
|
}
|
}
|
}
|
|
private void dealMultifiles(List<String> urls, Goods goods) {
|
if (urls == null || urls.isEmpty()) {
|
return;
|
}
|
List<Multifile> list = new ArrayList<>();
|
for (int i = 0; i < urls.size(); i++) {
|
Multifile f = new Multifile();
|
f.setObjType(Constants.ZERO);
|
f.setName(urls.get(i));
|
f.setType(Constants.ZERO);
|
f.setObjId(goods.getId());
|
f.setCreateDate(goods.getCreateDate());
|
f.setCreator(goods.getCreator());
|
f.setIsdeleted(Constants.ZERO);
|
f.setSortnum(i + Constants.ONE);
|
f.setCompanyId(goods.getCompanyId());
|
f.setFileurl(urls.get(i));
|
list.add(f);
|
}
|
multifileMapper.insertBatch(list);
|
}
|
|
private void dealGoodsParam(Category cate, Goods goods, String paramStr, List<CateParam> allParamsList, int num) {
|
List<GoodsParam> paramList = new ArrayList<>();
|
String[] params = StringUtils.defaultString(paramStr, "").split("\n");
|
List<CateParam> cateParams = getCateParamByCateId(cate.getId(), allParamsList);
|
for (String s : params) {
|
if (StringUtils.isBlank(s)) {
|
continue;
|
}
|
s = s.replace(":", ":");
|
String[] ts = s.split(":");
|
if (ts.length == 0) {
|
continue;
|
}
|
CateParam ta = getCateParamByName(ts[0], cateParams);
|
if (ta == null) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "产品参数中【" + s + "】无效");
|
}
|
GoodsParam gp = new GoodsParam();
|
gp.setIsdeleted(Constants.ZERO);
|
gp.setCreator(goods.getCreator());
|
gp.setCreateDate(goods.getCreateDate());
|
gp.setGoodsId(goods.getId());
|
gp.setName(ta.getName());
|
gp.setPramaId(ta.getId());
|
gp.setStatus(Constants.ZERO);
|
gp.setVal(ts.length > 1 ? ts[1] : null);
|
gp.setSortnum(ta.getSortnum());
|
paramList.add(gp);
|
}
|
if (!paramList.isEmpty()) {
|
goodsParamMapper.insertBatch(paramList);
|
}
|
}
|
|
private String normalizeCategoryName(String name) {
|
if (name == null) {
|
return "";
|
}
|
return name.trim().replace('\u00A0', ' ').replaceAll("\\s+", " ");
|
}
|
|
private boolean isTopLevelCategory(Category category) {
|
return category != null
|
&& (category.getParentId() == null || Constants.equalsInteger(category.getParentId(), Constants.ZERO));
|
}
|
|
private Category getTopCategoryByName(String name, List<Category> list) {
|
if (list == null) {
|
return null;
|
}
|
String normalized = normalizeCategoryName(name);
|
if (StringUtils.isBlank(normalized)) {
|
return null;
|
}
|
for (Category c : list) {
|
if (isTopLevelCategory(c) && StringUtils.equals(normalized, normalizeCategoryName(c.getName()))) {
|
return c;
|
}
|
}
|
return null;
|
}
|
|
/** 按企业加载一级类别 -> 子类别列表 */
|
private Map<Integer, List<Category>> buildSubCategoryMap(Integer companyId) {
|
List<Category> subCategories = categoryMapper.selectList(new LambdaQueryWrapper<Category>()
|
.eq(Category::getCompanyId, companyId)
|
.eq(Category::getIsdeleted, Constants.ZERO)
|
.isNotNull(Category::getParentId)
|
.orderByAsc(Category::getSortnum));
|
Map<Integer, List<Category>> map = new HashMap<>();
|
for (Category sub : subCategories) {
|
if (sub.getParentId() == null || Constants.equalsInteger(sub.getParentId(), Constants.ZERO)) {
|
continue;
|
}
|
map.computeIfAbsent(sub.getParentId(), k -> new ArrayList<>()).add(sub);
|
}
|
return map;
|
}
|
|
/**
|
* 根据本行已匹配的一级【商品类别】,在其子类别中查找与【商品二级类别】名称一致的记录。
|
*/
|
private Category matchSubCategoryUnderParent(Category topCategory, String subCategoryName,
|
Map<Integer, List<Category>> subCategoryMap, Integer companyId) {
|
if (topCategory == null || topCategory.getId() == null) {
|
return null;
|
}
|
String normalized = normalizeCategoryName(subCategoryName);
|
if (StringUtils.isBlank(normalized)) {
|
return null;
|
}
|
List<Category> children = subCategoryMap.get(topCategory.getId());
|
if (children == null || children.isEmpty()) {
|
Integer cid = topCategory.getCompanyId() != null ? topCategory.getCompanyId() : companyId;
|
children = categoryMapper.selectList(new LambdaQueryWrapper<Category>()
|
.eq(Category::getParentId, topCategory.getId())
|
.eq(Category::getCompanyId, cid)
|
.eq(Category::getIsdeleted, Constants.ZERO)
|
.orderByAsc(Category::getSortnum));
|
}
|
for (Category child : children) {
|
if (StringUtils.equals(normalized, normalizeCategoryName(child.getName()))) {
|
return child;
|
}
|
}
|
return null;
|
}
|
|
private Brand getBrandByName(String name, List<Brand> list) {
|
if (list == null) {
|
return null;
|
}
|
for (Brand b : list) {
|
if (StringUtils.equals(name.trim(), b.getName())) {
|
return b;
|
}
|
}
|
return null;
|
}
|
|
private Goods findGoodsByName(String name, List<Goods> list) {
|
if (list == null) {
|
return null;
|
}
|
for (Goods g : list) {
|
if (StringUtils.equals(name.trim(), g.getName())) {
|
return g;
|
}
|
}
|
return null;
|
}
|
|
private List<CateParam> getCateParamByCateId(Integer cateId, List<CateParam> all) {
|
List<CateParam> list = new ArrayList<>();
|
if (all == null) {
|
return list;
|
}
|
for (CateParam p : all) {
|
if (Constants.equalsInteger(cateId, p.getCategoryId())) {
|
list.add(p);
|
}
|
}
|
return list;
|
}
|
|
private CateParam getCateParamByName(String name, List<CateParam> params) {
|
if (params == null) {
|
return null;
|
}
|
for (CateParam p : params) {
|
if (StringUtils.equals(name.trim(), p.getName())) {
|
return p;
|
}
|
}
|
return null;
|
}
|
|
/** 原模板「产品参数」列宽(字符宽),用于新版 G 列放大 */
|
private static final double TEMPLATE_PARAM_COL_WIDTH = 16.33203125D;
|
|
private void applyTemplateHeaderStyles(Workbook workbook, Row headerRow) {
|
CellStyle evenStyle = null;
|
CellStyle oddStyle = null;
|
for (int i = 0; i < 6; i++) {
|
Cell cell = headerRow.getCell(i);
|
if (cell == null) {
|
continue;
|
}
|
if (i % 2 == 0) {
|
evenStyle = cell.getCellStyle();
|
} else {
|
oddStyle = cell.getCellStyle();
|
}
|
}
|
if (evenStyle == null && headerRow.getCell(0) != null) {
|
evenStyle = headerRow.getCell(0).getCellStyle();
|
}
|
if (oddStyle == null) {
|
oddStyle = evenStyle;
|
}
|
for (int i = 0; i < ASYNC_TEMPLATE_HEADERS.length; i++) {
|
Cell cell = headerRow.getCell(i);
|
if (cell == null) {
|
cell = headerRow.createCell(i);
|
}
|
CellStyle style = (i % 2 == 0) ? evenStyle : oddStyle;
|
if (style != null) {
|
cell.setCellStyle(style);
|
}
|
}
|
for (int col : BLACK_HEADER_COLS) {
|
Cell cell = headerRow.getCell(col);
|
if (cell == null) {
|
continue;
|
}
|
CellStyle baseStyle = cell.getCellStyle();
|
CellStyle blackStyle = workbook.createCellStyle();
|
if (baseStyle != null) {
|
blackStyle.cloneStyleFrom(baseStyle);
|
}
|
Font baseFont = baseStyle != null ? workbook.getFontAt(baseStyle.getFontIndexAsInt()) : null;
|
Font blackFont = workbook.createFont();
|
if (baseFont != null) {
|
blackFont.setBold(baseFont.getBold());
|
blackFont.setFontHeight(baseFont.getFontHeight());
|
blackFont.setFontName(baseFont.getFontName());
|
}
|
blackFont.setColor(IndexedColors.BLACK.getIndex());
|
blackStyle.setFont(blackFont);
|
cell.setCellStyle(blackStyle);
|
}
|
}
|
|
private void applyTemplateColumnWidths(Sheet sheet) {
|
int paramColIndex = 6;
|
int doubledWidth = (int) Math.round(TEMPLATE_PARAM_COL_WIDTH * 256 * 2);
|
sheet.setColumnWidth(paramColIndex, doubledWidth);
|
}
|
|
private void fillTemplateExampleRow(Sheet sheet0, CellStyle wrapStyle) {
|
Row exampleRow = sheet0.getRow(1);
|
if (exampleRow == null) {
|
exampleRow = sheet0.createRow(1);
|
}
|
exampleRow.createCell(0).setCellValue("125");
|
exampleRow.createCell(1).setCellValue("美的电烤箱");
|
exampleRow.createCell(2).setCellValue("电烤箱");
|
exampleRow.createCell(3).setCellValue("美的");
|
exampleRow.createCell(4).setCellValue("2888");
|
exampleRow.createCell(5).setCellValue("2300");
|
Cell paramCell = exampleRow.createCell(6);
|
paramCell.setCellStyle(wrapStyle);
|
paramCell.setCellValue("容量:99升\r\n重量:88KG\r\n型号:77");
|
exampleRow.createCell(7).setCellValue("");
|
exampleRow.createCell(8).setCellValue("");
|
exampleRow.createCell(9).setCellValue("");
|
}
|
|
private void setResponseHeader(HttpServletResponse response, String fileName) throws Exception {
|
String encodeFileName = URLEncoder.encode(fileName, "UTF-8");
|
response.setContentType("application/octet-stream");
|
response.setHeader("Content-Disposition", "attachment;filename=" + encodeFileName);
|
response.setHeader("eva-opera-type", "download");
|
response.setHeader("eva-download-filename", encodeFileName);
|
}
|
}
|