package com.tcm.training.admin.member.service; import cn.idev.excel.FastExcel; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.tcm.training.admin.common.DateTimes; import com.tcm.training.admin.common.PageResponse; import com.tcm.training.admin.common.PhoneMasker; import com.tcm.training.admin.member.entity.MemberPurchaseOrder; import com.tcm.training.admin.member.excel.MemberPurchaseOrderExcelRow; import com.tcm.training.admin.member.mapper.MemberPurchaseOrderMapper; import com.tcm.training.admin.member.row.MemberPurchaseOrderRow; import com.tcm.training.admin.member.vo.MemberPurchaseOrderListItemVO; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.math.BigDecimal; import java.net.URLEncoder; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @Service public class MemberPurchaseOrderAppService { private static final String STATUS_WAITING_PAYMENT = "WAITING_PAYMENT"; private static final String STATUS_PAID = "PAID"; private static final String STATUS_REFUNDED = "REFUNDED"; private static final String STATUS_CANCELLED = "CANCELLED"; private static final String MEMBER_TYPE_MONTH_CARD = "MONTH_CARD"; private static final String MEMBER_TYPE_QUARTER_CARD = "QUARTER_CARD"; private static final String PAYMENT_METHOD_WECHAT = "WECHAT"; private static final String PAYMENT_METHOD_ALIPAY = "ALIPAY"; private final MemberPurchaseOrderMapper memberPurchaseOrderMapper; public MemberPurchaseOrderAppService(MemberPurchaseOrderMapper memberPurchaseOrderMapper) { this.memberPurchaseOrderMapper = memberPurchaseOrderMapper; } public PageResponse page(int page, int pageSize, String orderNo, String userPhone, String memberType, String paymentMethod, String status, LocalDateTime createdFrom, LocalDateTime createdTo) { IPage result = memberPurchaseOrderMapper.selectOrderPage( new Page(page, pageSize), trimToNull(orderNo), trimToNull(userPhone), trimToNull(memberType), trimToNull(paymentMethod), normalizeStatus(status), createdFrom, createdTo ); return PageResponse.of(toList(result.getRecords()), result.getTotal(), result.getCurrent(), result.getSize()); } public void export(String orderNo, String userPhone, String memberType, String paymentMethod, String status, LocalDateTime createdFrom, LocalDateTime createdTo, HttpServletResponse response) throws IOException { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); String filename = URLEncoder.encode("会员购买订单", "UTF-8").replace("+", "%20"); response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + filename + ".xlsx"); List rows = memberPurchaseOrderMapper.selectOrderList( trimToNull(orderNo), trimToNull(userPhone), trimToNull(memberType), trimToNull(paymentMethod), normalizeStatus(status), createdFrom, createdTo ); List exports = new ArrayList(); for (MemberPurchaseOrderRow row : rows) { MemberPurchaseOrderExcelRow export = new MemberPurchaseOrderExcelRow(); export.setOrderNo(row.getOrderNo()); export.setUserNickname(defaultText(row.getUserNickname())); export.setUserPhone(PhoneMasker.mask(row.getUserPhone())); export.setMemberType(memberTypeText(row.getMemberType())); export.setMemberDaysText(memberDaysText(row.getMemberDays())); export.setOrderAmount(row.getOrderAmount()); export.setPaymentMethod(paymentMethodText(row.getPaymentMethod())); export.setStatus(statusText(row.getStatus())); export.setRefundAmount(resolveRefundAmount(row.getStatus(), row.getOrderAmount(), row.getRefundAmount())); export.setRefundRemark(defaultText(row.getRefundRemark())); export.setCreatedAt(DateTimes.format(row.getCreatedAt())); exports.add(export); } FastExcel.write(response.getOutputStream(), MemberPurchaseOrderExcelRow.class) .sheet("会员购买订单") .doWrite(exports); } public void refund(Long id) { MemberPurchaseOrder order = requireOrder(id); if (!STATUS_PAID.equals(order.getStatus())) { throw new IllegalArgumentException("仅已支付订单允许退款"); } // TODO: 支付方案确认后,在这里接入真实退款流程并在退款成功后更新订单状态与退款时间。 throw new IllegalArgumentException("退款功能待支付方案确认后接入"); } @Transactional public void delete(Long id) { MemberPurchaseOrder order = requireOrder(id); if (!STATUS_REFUNDED.equals(order.getStatus())) { throw new IllegalArgumentException("仅已退款订单允许删除"); } memberPurchaseOrderMapper.deleteById(id); } private MemberPurchaseOrder requireOrder(Long id) { MemberPurchaseOrder order = memberPurchaseOrderMapper.selectOne(new LambdaQueryWrapper() .eq(MemberPurchaseOrder::getId, id) .eq(MemberPurchaseOrder::getDeleted, 0) .last("limit 1")); if (order == null) { throw new IllegalArgumentException("会员购买订单不存在"); } return order; } private List toList(List rows) { List list = new ArrayList(); for (MemberPurchaseOrderRow row : rows) { MemberPurchaseOrderListItemVO item = new MemberPurchaseOrderListItemVO(); item.setId(row.getId()); item.setOrderNo(row.getOrderNo()); item.setUserNickname(row.getUserNickname()); item.setUserPhone(PhoneMasker.mask(row.getUserPhone())); item.setMemberType(row.getMemberType()); item.setMemberDays(row.getMemberDays()); item.setOrderAmount(row.getOrderAmount()); item.setPaymentMethod(row.getPaymentMethod()); item.setRefundAmount(resolveRefundAmount(row.getStatus(), row.getOrderAmount(), row.getRefundAmount())); item.setRefundRemark(row.getRefundRemark()); item.setStatus(row.getStatus()); item.setPaidAt(row.getPaidAt()); item.setRefundedAt(row.getRefundedAt()); item.setCreatedAt(row.getCreatedAt()); list.add(item); } return list; } private BigDecimal resolveRefundAmount(String status, BigDecimal orderAmount, BigDecimal refundAmount) { if (!STATUS_REFUNDED.equals(status)) { return null; } return refundAmount == null ? orderAmount : refundAmount; } private String normalizeStatus(String status) { String normalized = trimToNull(status); if (normalized == null) { return null; } if (STATUS_PAID.equals(normalized) || STATUS_REFUNDED.equals(normalized)) { return normalized; } return null; } private String trimToNull(String value) { if (value == null) { return null; } String trimmed = value.trim(); return trimmed.isEmpty() ? null : trimmed; } private String defaultText(String value) { return value == null || value.trim().isEmpty() ? "-" : value.trim(); } private String memberDaysText(Integer memberDays) { return memberDays == null ? "-" : memberDays + "天"; } private String memberTypeText(String memberType) { if (MEMBER_TYPE_MONTH_CARD.equals(memberType)) { return "月卡"; } if (MEMBER_TYPE_QUARTER_CARD.equals(memberType)) { return "季卡"; } return "-"; } private String paymentMethodText(String paymentMethod) { if (PAYMENT_METHOD_WECHAT.equals(paymentMethod)) { return "微信支付"; } if (PAYMENT_METHOD_ALIPAY.equals(paymentMethod)) { return "支付宝支付"; } return "-"; } private String statusText(String status) { if (STATUS_WAITING_PAYMENT.equals(status)) { return "待支付"; } if (STATUS_PAID.equals(status)) { return "已支付"; } if (STATUS_REFUNDED.equals(status)) { return "已退款"; } if (STATUS_CANCELLED.equals(status)) { return "已取消"; } return "-"; } }