package com.doumee.service.business.impl; 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.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.Utils; import com.doumee.dao.business.PreselectOrderItemMapper; import com.doumee.dao.business.PreselectOrderMapper; import com.doumee.dao.business.PreselectOrderSeqMapper; import com.doumee.dao.business.model.PreselectOrder; import com.doumee.dao.business.model.PreselectOrderItem; import com.doumee.dao.business.model.PreselectOrderSeq; import com.doumee.dao.business.model.dto.PreselectOrderItemDTO; import com.doumee.dao.business.model.dto.SubmitPreselectOrderDTO; import com.doumee.service.business.PreselectOrderService; import org.apache.commons.lang3.StringUtils; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.shiro.SecurityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; @Service public class PreselectOrderServiceImpl implements PreselectOrderService { @Autowired private PreselectOrderMapper preselectOrderMapper; @Autowired private PreselectOrderItemMapper preselectOrderItemMapper; @Autowired private PreselectOrderSeqMapper preselectOrderSeqMapper; @Override @Transactional public synchronized String generateOrderNo() { String prefix = new SimpleDateFormat("yyyyMMddHHmm").format(new Date()); PreselectOrderSeq seq = preselectOrderSeqMapper.selectOne(new QueryWrapper().eq("SEQ_KEY", prefix)); int nextVal = 1; if (seq == null) { seq = new PreselectOrderSeq(); seq.setSeqKey(prefix); seq.setSeqVal(1); preselectOrderSeqMapper.insert(seq); } else { nextVal = seq.getSeqVal() + 1; seq.setSeqVal(nextVal); preselectOrderSeqMapper.updateById(seq); } return prefix + String.format("%03d", nextVal); } @Override @Transactional public void submit(SubmitPreselectOrderDTO dto) { LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal(); if (!user.getType().equals(Constants.UserType.ZHUBO.getKey())) { throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "非主播用户无法提交订单"); } if (StringUtils.isBlank(dto.getOrderNo())) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单编号不能为空"); } if (CollectionUtils.isEmpty(dto.getItems())) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请至少选择一个商品"); } long exists = preselectOrderMapper.selectCount(new QueryWrapper() .eq("ORDER_NO", dto.getOrderNo()).eq("ISDELETED", Constants.ZERO)); if (exists > 0) { throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "订单编号已存在,请刷新页面"); } Date now = new Date(); Date sessionCreate = dto.getSessionCreateTime() != null ? dto.getSessionCreateTime() : now; long durationSeconds = Math.max(0, (now.getTime() - sessionCreate.getTime()) / 1000); Set categorySet = new HashSet<>(); BigDecimal totalZd = BigDecimal.ZERO; BigDecimal totalPrice = BigDecimal.ZERO; int goodsCount = 0; List validItems = new ArrayList<>(); for (PreselectOrderItemDTO item : dto.getItems()) { if (item.getGoodsId() == null || StringUtils.isBlank(item.getGoodsName())) { continue; } validItems.add(item); goodsCount++; if (item.getCategoryId() != null) { categorySet.add(item.getCategoryId()); } if (item.getZdPrice() != null) { totalZd = totalZd.add(item.getZdPrice()); } if (item.getPrice() != null) { totalPrice = totalPrice.add(item.getPrice()); } } if (validItems.isEmpty()) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请至少选择一个有效商品"); } PreselectOrder order = new PreselectOrder(); order.setOrderNo(dto.getOrderNo()); order.setCompanyId(user.getCompanyId()); order.setAnchorUserId(user.getId()); order.setAnchorUsername(user.getUsername()); order.setUserBudget(dto.getUserBudget() != null ? dto.getUserBudget() : BigDecimal.ZERO); order.setCategoryCount(categorySet.size()); order.setGoodsCount(goodsCount); order.setTotalZdPrice(totalZd); order.setTotalPrice(totalPrice); order.setSessionCreateTime(sessionCreate); order.setCreateTime(sessionCreate); order.setSubmitTime(now); order.setDurationSeconds((int) durationSeconds); order.setCreator(user.getId()); order.setIsdeleted(Constants.ZERO); preselectOrderMapper.insert(order); int sort = 1; for (PreselectOrderItemDTO itemDto : validItems) { PreselectOrderItem item = new PreselectOrderItem(); item.setOrderId(order.getId()); item.setSortNum(sort++); item.setCategoryId(itemDto.getCategoryId()); item.setCategoryName(itemDto.getCategoryName()); item.setSubCategoryId(itemDto.getSubCategoryId()); item.setSubCategoryName(itemDto.getSubCategoryName()); item.setGoodsId(itemDto.getGoodsId()); item.setGoodsName(itemDto.getGoodsName()); item.setZdPrice(itemDto.getZdPrice()); item.setPrice(itemDto.getPrice()); item.setIsdeleted(Constants.ZERO); preselectOrderItemMapper.insert(item); } } @Override public PageData findPage(PageWrap pageWrap) { LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal(); IPage page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); QueryWrapper queryWrapper = new QueryWrapper<>(); Utils.MP.blankToNull(pageWrap.getModel()); queryWrapper.eq("ISDELETED", Constants.ZERO); queryWrapper.eq("COMPANY_ID", user.getCompanyId()); if (pageWrap.getModel() != null) { if (StringUtils.isNotBlank(pageWrap.getModel().getOrderNo())) { queryWrapper.like("ORDER_NO", pageWrap.getModel().getOrderNo()); } if (StringUtils.isNotBlank(pageWrap.getModel().getAnchorUsername())) { queryWrapper.like("ANCHOR_USERNAME", pageWrap.getModel().getAnchorUsername()); } if (pageWrap.getModel().getSubmitTimeStart() != null) { queryWrapper.ge("SUBMIT_TIME", pageWrap.getModel().getSubmitTimeStart()); } if (pageWrap.getModel().getSubmitTimeEnd() != null) { queryWrapper.le("SUBMIT_TIME", pageWrap.getModel().getSubmitTimeEnd()); } } queryWrapper.orderByDesc("SUBMIT_TIME"); IPage result = preselectOrderMapper.selectPage(page, queryWrapper); result.getRecords().forEach(o -> o.setDurationText(formatDuration(o.getDurationSeconds()))); return PageData.from(result); } @Override public PreselectOrder findDetail(Integer id) { LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal(); PreselectOrder order = preselectOrderMapper.selectById(id); if (order == null || !Objects.equals(order.getIsdeleted(), Constants.ZERO) || !user.getCompanyId().equals(order.getCompanyId())) { throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在"); } order.setDurationText(formatDuration(order.getDurationSeconds())); List items = preselectOrderItemMapper.selectList(new QueryWrapper() .eq("ORDER_ID", id).eq("ISDELETED", Constants.ZERO).orderByAsc("SORT_NUM")); order.setItems(items); return order; } @Override public void deleteById(Integer id) { PreselectOrder order = findDetail(id); order.setIsdeleted(Constants.ONE); preselectOrderMapper.updateById(order); } @Override public void exportDetail(Integer id, HttpServletResponse response) { PreselectOrder order = findDetail(id); try (Workbook workbook = new XSSFWorkbook()) { Sheet sheet = workbook.createSheet("订单明细"); sheet.setColumnWidth(0, 3000); sheet.setColumnWidth(1, 6000); sheet.setColumnWidth(2, 8000); sheet.setColumnWidth(3, 6000); sheet.setColumnWidth(4, 4000); CellStyle titleStyle = workbook.createCellStyle(); Font titleFont = workbook.createFont(); titleFont.setBold(true); titleFont.setFontHeightInPoints((short) 14); titleStyle.setFont(titleFont); titleStyle.setAlignment(HorizontalAlignment.CENTER); CellStyle headerStyle = workbook.createCellStyle(); Font headerFont = workbook.createFont(); headerFont.setBold(true); headerFont.setColor(IndexedColors.WHITE.getIndex()); headerStyle.setFont(headerFont); headerStyle.setFillForegroundColor(IndexedColors.DARK_TEAL.getIndex()); headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); headerStyle.setAlignment(HorizontalAlignment.CENTER); headerStyle.setBorderBottom(BorderStyle.THIN); headerStyle.setBorderTop(BorderStyle.THIN); headerStyle.setBorderLeft(BorderStyle.THIN); headerStyle.setBorderRight(BorderStyle.THIN); CellStyle dataStyle = workbook.createCellStyle(); dataStyle.setBorderBottom(BorderStyle.THIN); dataStyle.setBorderTop(BorderStyle.THIN); dataStyle.setBorderLeft(BorderStyle.THIN); dataStyle.setBorderRight(BorderStyle.THIN); dataStyle.setVerticalAlignment(VerticalAlignment.CENTER); CellStyle labelStyle = workbook.createCellStyle(); Font labelFont = workbook.createFont(); labelFont.setBold(true); labelStyle.setFont(labelFont); int rowIdx = 0; Row titleRow = sheet.createRow(rowIdx++); Cell titleCell = titleRow.createCell(0); titleCell.setCellValue("预选订单明细清单"); titleCell.setCellStyle(titleStyle); sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 4)); rowIdx++; String[][] summary = { {"订单编号", order.getOrderNo(), "客户预算", formatMoney(order.getUserBudget())}, {"品类数量", String.valueOf(order.getCategoryCount()), "商品数量", String.valueOf(order.getGoodsCount())}, {"旗舰价合计", formatMoney(order.getTotalZdPrice()), "指导价合计", formatMoney(order.getTotalPrice())}, {"主播账号", order.getAnchorUsername() != null ? order.getAnchorUsername() : "", "创建时长", order.getDurationText() != null ? order.getDurationText() : ""}, {"创建时间", formatDate(order.getSessionCreateTime() != null ? order.getSessionCreateTime() : order.getCreateTime()), "提交时间", formatDate(order.getSubmitTime())} }; for (String[] line : summary) { Row row = sheet.createRow(rowIdx++); for (int i = 0; i < line.length; i++) { Cell cell = row.createCell(i); cell.setCellValue(line[i]); cell.setCellStyle(i % 2 == 0 ? labelStyle : dataStyle); } } rowIdx++; Row headerRow = sheet.createRow(rowIdx++); String[] headers = {"序号", "品类名称", "产品型号", "旗舰价", "指导价"}; for (int i = 0; i < headers.length; i++) { Cell cell = headerRow.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(headerStyle); } List items = order.getItems() != null ? order.getItems() : Collections.emptyList(); for (PreselectOrderItem item : items) { Row row = sheet.createRow(rowIdx++); row.createCell(0).setCellValue(item.getSortNum() != null ? item.getSortNum() : 0); row.createCell(1).setCellValue(item.getCategoryName() != null ? item.getCategoryName() : ""); row.createCell(2).setCellValue(item.getGoodsName() != null ? item.getGoodsName() : ""); row.createCell(3).setCellValue(formatMoney(item.getZdPrice())); row.createCell(4).setCellValue(formatMoney(item.getPrice())); for (int i = 0; i < 5; i++) { row.getCell(i).setCellStyle(dataStyle); } } String fileName = "订单_" + order.getOrderNo() + ".xlsx"; String encodeFileName = URLEncoder.encode(fileName, "UTF-8"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment;filename=" + encodeFileName); response.setHeader("eva-opera-type", "download"); response.setHeader("eva-download-filename", encodeFileName); workbook.write(response.getOutputStream()); response.flushBuffer(); } catch (Exception e) { throw new BusinessException(ResponseStatus.EXPORT_EXCEL_ERROR.getCode(), "导出失败"); } } private String formatDate(Date date) { if (date == null) { return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); } private String formatMoney(BigDecimal val) { if (val == null) { return "¥0"; } return "¥" + val.stripTrailingZeros().toPlainString(); } private String formatDuration(Integer seconds) { if (seconds == null || seconds <= 0) { return "0秒"; } int h = seconds / 3600; int m = (seconds % 3600) / 60; int s = seconds % 60; StringBuilder sb = new StringBuilder(); if (h > 0) { sb.append(h).append("小时"); } if (m > 0) { sb.append(m).append("分"); } if (s > 0 || sb.length() == 0) { sb.append(s).append("秒"); } return sb.toString(); } }