|
|
@@ -8,14 +8,10 @@ import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
-import lombok.extern.slf4j.Slf4j;
|
|
|
-import org.apache.poi.ss.usermodel.*;
|
|
|
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
import org.springframework.util.StringUtils;
|
|
|
-import org.springframework.web.multipart.MultipartFile;
|
|
|
import shop.alien.entity.result.R;
|
|
|
import shop.alien.entity.store.*;
|
|
|
import shop.alien.entity.store.dto.LifeDiscountCouponStoreFriendDto;
|
|
|
@@ -27,10 +23,8 @@ import shop.alien.store.service.LifeDiscountCouponStoreFriendService;
|
|
|
import shop.alien.util.common.UniqueRandomNumGenerator;
|
|
|
import shop.alien.util.common.constant.OrderStatusEnum;
|
|
|
|
|
|
-import java.io.InputStream;
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
-import java.text.SimpleDateFormat;
|
|
|
import java.time.*;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.time.format.TextStyle;
|
|
|
@@ -44,7 +38,6 @@ import java.util.stream.Collectors;
|
|
|
* @version 1.0
|
|
|
* @date 2024/12/23 15:08
|
|
|
*/
|
|
|
-@Slf4j
|
|
|
@Service
|
|
|
@RequiredArgsConstructor
|
|
|
public class LifeCouponServiceImpl extends ServiceImpl<LifeCouponMapper, LifeCoupon> implements LifeCouponService {
|
|
|
@@ -701,262 +694,4 @@ public class LifeCouponServiceImpl extends ServiceImpl<LifeCouponMapper, LifeCou
|
|
|
return lifeCouponMapper.getNewCouponDetail(id);
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public R<String> importHolidayFromExcel(MultipartFile file) {
|
|
|
- log.info("LifeCouponServiceImpl.importHolidayFromExcel fileName={}", file.getOriginalFilename());
|
|
|
-
|
|
|
- if (file == null || file.isEmpty()) {
|
|
|
- return R.fail("上传文件为空");
|
|
|
- }
|
|
|
-
|
|
|
- String fileName = file.getOriginalFilename();
|
|
|
- if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
|
|
|
- return R.fail("文件格式不正确,请上传Excel文件");
|
|
|
- }
|
|
|
-
|
|
|
- List<String> errorMessages = new ArrayList<>();
|
|
|
- int successCount = 0;
|
|
|
- int totalCount = 0;
|
|
|
-
|
|
|
- try (InputStream inputStream = file.getInputStream();
|
|
|
- XSSFWorkbook workbook = new XSSFWorkbook(inputStream)) {
|
|
|
- Sheet sheet = workbook.getSheetAt(0);
|
|
|
-
|
|
|
- // 获取表头(第6行,索引为5)
|
|
|
- Row headerRow = sheet.getRow(5);
|
|
|
- if (headerRow == null) {
|
|
|
- return R.fail("Excel文件格式不正确,缺少表头");
|
|
|
- }
|
|
|
-
|
|
|
- // 构建字段映射(表头名称 -> 列索引)
|
|
|
- Map<String, Integer> headerMap = new HashMap<>();
|
|
|
- for (int i = 0; i < headerRow.getLastCellNum(); i++) {
|
|
|
- Cell cell = headerRow.getCell(i);
|
|
|
- if (cell != null) {
|
|
|
- String headerName = getCellValueAsString(cell);
|
|
|
- if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(headerName)) {
|
|
|
- headerMap.put(headerName.trim(), i);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 验证表头
|
|
|
- if (!headerMap.containsKey("年份") || !headerMap.containsKey("节日名称")
|
|
|
- || !headerMap.containsKey("开始时间") || !headerMap.containsKey("结束时间")) {
|
|
|
- return R.fail("Excel文件格式不正确,缺少必要的表头字段(年份、节日名称、开始时间、结束时间)");
|
|
|
- }
|
|
|
-
|
|
|
- // 读取数据行(从第7行开始,索引为6)
|
|
|
- for (int rowIndex = 6; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
|
|
|
- Row row = sheet.getRow(rowIndex);
|
|
|
- if (row == null) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查是否为空行
|
|
|
- boolean isEmptyRow = true;
|
|
|
- for (int i = 0; i < row.getLastCellNum(); i++) {
|
|
|
- Cell cell = row.getCell(i);
|
|
|
- if (cell != null && cell.getCellType() != CellType.BLANK) {
|
|
|
- String cellValue = getCellValueAsString(cell);
|
|
|
- if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(cellValue)) {
|
|
|
- isEmptyRow = false;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (isEmptyRow) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- totalCount++;
|
|
|
- EssentialHolidayComparison holiday = new EssentialHolidayComparison();
|
|
|
-
|
|
|
- try {
|
|
|
- // 读取年份(必填)
|
|
|
- Integer yearColIndex = headerMap.get("年份");
|
|
|
- if (yearColIndex == null) {
|
|
|
- throw new RuntimeException("缺少年份字段");
|
|
|
- }
|
|
|
- Cell yearCell = row.getCell(yearColIndex);
|
|
|
- String yearValue = getCellValueAsString(yearCell);
|
|
|
- if (StringUtils.isEmpty(yearValue)) {
|
|
|
- throw new RuntimeException("年份不能为空");
|
|
|
- }
|
|
|
- // 处理年份可能是数字的情况
|
|
|
- if (yearCell != null && yearCell.getCellType() == CellType.NUMERIC) {
|
|
|
- double numericValue = yearCell.getNumericCellValue();
|
|
|
- yearValue = String.valueOf((long) numericValue);
|
|
|
- }
|
|
|
- holiday.setParticularYear(yearValue.trim());
|
|
|
-
|
|
|
- // 读取节日名称(必填)
|
|
|
- Integer nameColIndex = headerMap.get("节日名称");
|
|
|
- if (nameColIndex == null) {
|
|
|
- throw new RuntimeException("缺少节日名称字段");
|
|
|
- }
|
|
|
- Cell nameCell = row.getCell(nameColIndex);
|
|
|
- String nameValue = getCellValueAsString(nameCell);
|
|
|
- if (StringUtils.isEmpty(nameValue)) {
|
|
|
- throw new RuntimeException("节日名称不能为空");
|
|
|
- }
|
|
|
- holiday.setFestivalName(nameValue.trim());
|
|
|
-
|
|
|
- // 读取开始时间(必填,格式:2026-01-01)
|
|
|
- Integer startTimeColIndex = headerMap.get("开始时间");
|
|
|
- if (startTimeColIndex == null) {
|
|
|
- throw new RuntimeException("缺少开始时间字段");
|
|
|
- }
|
|
|
- Cell startTimeCell = row.getCell(startTimeColIndex);
|
|
|
- String startTimeValue = getCellValueAsString(startTimeCell);
|
|
|
- if (StringUtils.isEmpty(startTimeValue)) {
|
|
|
- throw new RuntimeException("开始时间不能为空");
|
|
|
- }
|
|
|
- Date startTime = parseDate(startTimeValue.trim(), rowIndex + 1);
|
|
|
- holiday.setStartTime(startTime);
|
|
|
-
|
|
|
- // 读取结束时间(必填,格式:2026-01-01)
|
|
|
- Integer endTimeColIndex = headerMap.get("结束时间");
|
|
|
- if (endTimeColIndex == null) {
|
|
|
- throw new RuntimeException("缺少结束时间字段");
|
|
|
- }
|
|
|
- Cell endTimeCell = row.getCell(endTimeColIndex);
|
|
|
- String endTimeValue = getCellValueAsString(endTimeCell);
|
|
|
- if (StringUtils.isEmpty(endTimeValue)) {
|
|
|
- throw new RuntimeException("结束时间不能为空");
|
|
|
- }
|
|
|
- Date endTime = parseDate(endTimeValue.trim(), rowIndex + 1);
|
|
|
- holiday.setEndTime(endTime);
|
|
|
-
|
|
|
- // 验证结束时间必须大于等于开始时间
|
|
|
- if (endTime.before(startTime)) {
|
|
|
- throw new RuntimeException("结束时间必须大于等于开始时间");
|
|
|
- }
|
|
|
-
|
|
|
- // 读取状态(可选,默认启用)
|
|
|
- Integer statusColIndex = headerMap.get("状态");
|
|
|
- int openFlag = 1; // 默认启用
|
|
|
- if (statusColIndex != null) {
|
|
|
- Cell statusCell = row.getCell(statusColIndex);
|
|
|
- String statusValue = getCellValueAsString(statusCell);
|
|
|
- if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(statusValue)) {
|
|
|
- String status = statusValue.trim();
|
|
|
- if ("启用".equals(status) || "1".equals(status)) {
|
|
|
- openFlag = 1;
|
|
|
- } else if ("禁用".equals(status) || "0".equals(status)) {
|
|
|
- openFlag = 0;
|
|
|
- } else {
|
|
|
- throw new RuntimeException("状态格式错误,请输入'启用'或'禁用'");
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- holiday.setOpenFlag(openFlag);
|
|
|
- holiday.setDelFlag(0);
|
|
|
-
|
|
|
- // 设置节日日期为开始时间
|
|
|
- LocalDate startLocalDate = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
|
|
- holiday.setFestivalDate(startLocalDate);
|
|
|
-
|
|
|
- // 保存数据
|
|
|
- essentialHolidayComparisonMapper.insert(holiday);
|
|
|
- successCount++;
|
|
|
- } catch (Exception e) {
|
|
|
- errorMessages.add(String.format("第%d行:%s", rowIndex + 1, e.getMessage()));
|
|
|
- log.error("导入第{}行数据失败", rowIndex + 1, e);
|
|
|
- }
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("导入Excel失败", e);
|
|
|
- return R.fail("导入失败:" + e.getMessage());
|
|
|
- }
|
|
|
-
|
|
|
- // 构建返回消息
|
|
|
- StringBuilder message = new StringBuilder();
|
|
|
- message.append(String.format("导入完成:成功%d条,失败%d条", successCount, totalCount - successCount));
|
|
|
- if (!errorMessages.isEmpty()) {
|
|
|
- message.append("\n失败详情:\n");
|
|
|
- for (int i = 0; i < Math.min(errorMessages.size(), 10); i++) {
|
|
|
- message.append(errorMessages.get(i)).append("\n");
|
|
|
- }
|
|
|
- if (errorMessages.size() > 10) {
|
|
|
- message.append("...还有").append(errorMessages.size() - 10).append("条错误信息");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return R.success(message.toString());
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 解析日期字符串
|
|
|
- */
|
|
|
- private Date parseDate(String dateStr, int rowNum) {
|
|
|
- try {
|
|
|
- // 尝试多种日期格式
|
|
|
- SimpleDateFormat[] formats = {
|
|
|
- new SimpleDateFormat("yyyy-MM-dd"),
|
|
|
- new SimpleDateFormat("yyyy/MM/dd"),
|
|
|
- new SimpleDateFormat("yyyy年MM月dd日")
|
|
|
- };
|
|
|
-
|
|
|
- for (SimpleDateFormat format : formats) {
|
|
|
- try {
|
|
|
- return format.parse(dateStr);
|
|
|
- } catch (Exception e) {
|
|
|
- // 继续尝试下一个格式
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 如果都失败,尝试解析数字日期(Excel日期格式)
|
|
|
- try {
|
|
|
- double numericValue = Double.parseDouble(dateStr);
|
|
|
- return org.apache.poi.ss.usermodel.DateUtil.getJavaDate(numericValue);
|
|
|
- } catch (Exception e) {
|
|
|
- // 忽略
|
|
|
- }
|
|
|
-
|
|
|
- throw new RuntimeException("日期格式错误,请使用格式:2026-01-01");
|
|
|
- } catch (Exception e) {
|
|
|
- throw new RuntimeException("日期格式错误,请使用格式:2026-01-01");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取单元格值(字符串格式)
|
|
|
- */
|
|
|
- private String getCellValueAsString(Cell cell) {
|
|
|
- if (cell == null) {
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- switch (cell.getCellType()) {
|
|
|
- case STRING:
|
|
|
- return cell.getStringCellValue();
|
|
|
- case NUMERIC:
|
|
|
- if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
|
|
|
- // 日期格式
|
|
|
- Date date = cell.getDateCellValue();
|
|
|
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
- return sdf.format(date);
|
|
|
- } else {
|
|
|
- // 处理数字,避免科学计数法
|
|
|
- double numericValue = cell.getNumericCellValue();
|
|
|
- if (numericValue == (long) numericValue) {
|
|
|
- return String.valueOf((long) numericValue);
|
|
|
- } else {
|
|
|
- return String.valueOf(numericValue);
|
|
|
- }
|
|
|
- }
|
|
|
- case BOOLEAN:
|
|
|
- return String.valueOf(cell.getBooleanCellValue());
|
|
|
- case FORMULA:
|
|
|
- try {
|
|
|
- return cell.getStringCellValue();
|
|
|
- } catch (Exception e) {
|
|
|
- return String.valueOf(cell.getNumericCellValue());
|
|
|
- }
|
|
|
- default:
|
|
|
- return null;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
}
|