|
|
@@ -1,12 +1,19 @@
|
|
|
package modules.order;
|
|
|
|
|
|
+import com.jfinal.kit.StrKit;
|
|
|
import com.jfinal.plugin.activerecord.Db;
|
|
|
+import com.jfinal.plugin.activerecord.Page;
|
|
|
import com.jfinal.plugin.activerecord.Record;
|
|
|
import common.model.Order;
|
|
|
import common.model.OrderLog;
|
|
|
import common.utils.http.MyRet;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
public class OrderService {
|
|
|
public MyRet create(long nfttId, long userId, int orderType) {
|
|
|
@@ -49,7 +56,7 @@ public class OrderService {
|
|
|
order.set("delivery_status", 0);
|
|
|
// ... nft铸造状态 ...
|
|
|
order.set("nft_mint_status", 0);
|
|
|
- // 其它
|
|
|
+ // 退款状态
|
|
|
order.set("refund_status", 0);
|
|
|
// 相关时间戳
|
|
|
order.set("create_time", System.currentTimeMillis());
|
|
|
@@ -63,7 +70,7 @@ public class OrderService {
|
|
|
// 3. 记录订单创建日志
|
|
|
OrderLog log = new OrderLog();
|
|
|
log.set("order_id", order.getId());
|
|
|
- log.set("from_status", 0); // 从无状态到待支付
|
|
|
+ log.set("from_status", OrderController.OrderStatus.INIT.code);
|
|
|
log.set("to_status", OrderController.OrderStatus.PENDING_PAY.code);
|
|
|
log.set("operator_id", userId); // 由用户创建
|
|
|
log.set("operator_type", 1);
|
|
|
@@ -81,7 +88,242 @@ public class OrderService {
|
|
|
return MyRet.fail(e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ public MyRet cancelByUser(long userId, long orderId) {
|
|
|
+ try {
|
|
|
+ Db.tx(() -> {
|
|
|
+ // 1. 获取order和nfttId
|
|
|
+ Order order = Order.dao.findById(orderId);
|
|
|
+ long nfttId = order.getNfttId();
|
|
|
+
|
|
|
+ // 2. 更新库存(在锁定的行上进行)
|
|
|
+ if (Db.update("UPDATE purchased_quantity SET purchased_quantity = purchased_quantity - 1 WHERE id = ?", nfttId) != 1) {
|
|
|
+ throw new RuntimeException("更新库存失败导致的取消失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 取消订单
|
|
|
+ order.set("order_status", OrderController.OrderStatus.CANCELED.code);
|
|
|
+ order.set("update_time", System.currentTimeMillis());
|
|
|
+
|
|
|
+ if (!order.update()) {
|
|
|
+ throw new RuntimeException("订单更新失败导致的取消失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 记录订单创建日志
|
|
|
+ OrderLog log = new OrderLog();
|
|
|
+ log.set("order_id", order.getId());
|
|
|
+ log.set("from_status", OrderController.OrderStatus.PENDING_PAY.code);
|
|
|
+ log.set("to_status", OrderController.OrderStatus.CANCELED.code);
|
|
|
+ log.set("operator_id", userId); // 由用户取消
|
|
|
+ log.set("operator_type", 1);
|
|
|
+ log.set("change_reason", "用户手动取消");
|
|
|
+ log.set("create_time", System.currentTimeMillis());
|
|
|
+ if (!log.save()) {
|
|
|
+ throw new RuntimeException("订单日志创建失败"); // 抛出异常触发回滚
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+
|
|
|
+ return MyRet.ok("取消成功");
|
|
|
+ } catch (Exception e) {
|
|
|
+ return MyRet.fail(e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据用户ID查询订单列表,并封装订单流转状态
|
|
|
+ * @param userId 用户ID
|
|
|
+ * @return 包含订单列表及状态流转信息的 MyRet 对象
|
|
|
+ */
|
|
|
+ public MyRet findOrderByUser(long userId) {
|
|
|
+ List<Order> orderList = Order.dao.find("SELECT * FROM t_order WHERE user_id = ? ORDER BY create_time DESC", userId);
|
|
|
+
|
|
|
+ if (orderList.isEmpty()) {
|
|
|
+ return MyRet.ok("查询成功").setData(new ArrayList<Map<String, Object>>());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调用重用方法封装日志
|
|
|
+ List<Map<String, Object>> resultList = encapsulateOrdersWithLogs(orderList);
|
|
|
+
|
|
|
+ return MyRet.ok("查询成功").setData(resultList);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 管理员查询订单列表(分页,按更新时间倒序,根据订单状态筛选)
|
|
|
+ * 按照用户提供的分页逻辑计算 total_row 和 total_page
|
|
|
+ * @param pageNumber 页码
|
|
|
+ * @param pageSize 页面大小
|
|
|
+ * @param orderStatus 订单状态码 (用于筛选,可选,如果为null或小于0则不筛选)
|
|
|
+ * @return 包含分页订单列表及状态流转信息的 MyRet 对象
|
|
|
+ */
|
|
|
+ public MyRet findForAdmin(int pageNumber, int pageSize, Integer orderStatus) { // 接收 Integer 类型的 orderStatus
|
|
|
+ // 构建用于查询当前页订单列表的 SQL
|
|
|
+ String columns = "id, order_sn, user_id, nftt_id, order_status, order_type, quantity, unit_price, total_price, payment_method, payment_sn, pay_time, delivery_status, delivery_time, cancel_time, closed_time, refund_status, refund_amount, refund_reason, create_time, update_time, is_deleted, memo";
|
|
|
+ String select = "SELECT " + columns;
|
|
|
+ String fromWhere = "FROM t_order"; // 基础 from 子句
|
|
|
+ String orderBy = "ORDER BY update_time DESC";
|
|
|
+
|
|
|
+ List<Object> paramsForList = new ArrayList<>(); // 用于 SELECT 列表查询的参数
|
|
|
+
|
|
|
+ // ✅ 根据 orderStatus 筛选
|
|
|
+ if (orderStatus != null && orderStatus >= 0) { // 确保 orderStatus 有效,0 通常表示“已取消”,也作为有效状态
|
|
|
+ fromWhere += " WHERE order_status = ?";
|
|
|
+ paramsForList.add(orderStatus);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算 LIMIT 的 offset (偏移量)
|
|
|
+ int offset = (pageNumber - 1) * pageSize;
|
|
|
+
|
|
|
+ // 构建查询当前页订单列表的最终 SQL (手动添加 LIMIT)
|
|
|
+ String listSql = select + " " + fromWhere + " " + orderBy + " LIMIT ?, ?";
|
|
|
+ paramsForList.add(offset);
|
|
|
+ paramsForList.add(pageSize);
|
|
|
|
|
|
+ // 获取当前页的订单列表
|
|
|
+ List<Order> orderList = Order.dao.find(listSql, paramsForList.toArray());
|
|
|
+
|
|
|
+ // 如果列表为空,直接返回
|
|
|
+ if (orderList.isEmpty()) {
|
|
|
+ Map<String, Object> response = new HashMap<>(); // 准备返回结构
|
|
|
+ response.put("list", new ArrayList<>());
|
|
|
+ response.put("total_row", 0);
|
|
|
+ response.put("total_page", 0);
|
|
|
+ response.put("page_size", pageSize);
|
|
|
+ response.put("page_number", pageNumber);
|
|
|
+ response.put("total_order_count", 0); // 与你的 total_user_count 对应
|
|
|
+ return MyRet.ok("查询成功").setData(response);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重用封装日志的逻辑
|
|
|
+ List<Map<String, Object>> encapsulatedOrderList = encapsulateOrdersWithLogs(orderList);
|
|
|
+
|
|
|
+ // 获取符合搜索条件的总行数 (total_row)
|
|
|
+ // 调用新的 countOrders 方法,传入 orderStatus 进行筛选计数
|
|
|
+ long totalRowLong = countOrders(orderStatus);
|
|
|
+
|
|
|
+ // 手动计算 total_page
|
|
|
+ int totalPage = (int) Math.ceil((double) totalRowLong / pageSize);
|
|
|
+ if (totalPage == 0 && totalRowLong > 0) { // 解决总行数大于0但总页数为0(pageSize大于totalRow)的问题
|
|
|
+ totalPage = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 封装最终响应
|
|
|
+ Map<String, Object> response = new HashMap<>();
|
|
|
+ response.put("list", encapsulatedOrderList);
|
|
|
+ response.put("total_row", totalRowLong); // 符合条件的订单总数
|
|
|
+ response.put("total_page", totalPage); // 手动计算的总页数
|
|
|
+ response.put("page_size", pageSize);
|
|
|
+ response.put("page_number", pageNumber);
|
|
|
+ response.put("total_order_count", totalRowLong); // 对应 total_user_count,这里是符合订单状态筛选的总数
|
|
|
+
|
|
|
+ return MyRet.ok("查询成功").setData(response);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 【重用方法】封装订单列表及其状态流转日志
|
|
|
+ * @param orderList 原始订单列表
|
|
|
+ * @return 封装了日志和描述信息的订单列表
|
|
|
+ */
|
|
|
+ private List<Map<String, Object>> encapsulateOrdersWithLogs(List<Order> orderList) {
|
|
|
+ if (orderList.isEmpty()) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 获取所有订单的ID,用于批量查询订单日志
|
|
|
+ List<Long> orderIds = orderList.stream()
|
|
|
+ .map(order -> order.getLong("id"))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ // 确保 orderIds 不为空,避免 SQL 错误
|
|
|
+ if (orderIds.isEmpty()) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 一次性查询所有订单相关的状态日志
|
|
|
+ StringBuilder inClause = new StringBuilder();
|
|
|
+ for (int i = 0; i < orderIds.size(); i++) {
|
|
|
+ inClause.append("?");
|
|
|
+ if (i < orderIds.size() - 1) {
|
|
|
+ inClause.append(",");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String sql = "SELECT * FROM t_order_log WHERE order_id IN (" + inClause.toString() + ") ORDER BY order_id, create_time ASC";
|
|
|
+ List<OrderLog> orderLogs = OrderLog.dao.find(sql, orderIds.toArray());
|
|
|
+
|
|
|
+ // 4. 将日志按 order_id 分组
|
|
|
+ Map<Long, List<Map<String, Object>>> orderLogsMap = new HashMap<>();
|
|
|
+ for (OrderLog log : orderLogs) {
|
|
|
+ long orderId = log.getLong("order_id");
|
|
|
+ orderLogsMap.computeIfAbsent(orderId, k -> new ArrayList<>())
|
|
|
+ .add(convertOrderLogToMap(log));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 遍历订单列表,封装日志和状态描述
|
|
|
+ List<Map<String, Object>> resultList = new ArrayList<>();
|
|
|
+ for (Order order : orderList) {
|
|
|
+ Map<String, Object> orderData = order.toMap();
|
|
|
+
|
|
|
+ orderData.put("order_status_desc", getStatusDescByCode(order.getInt("order_status")));
|
|
|
+
|
|
|
+ List<Map<String, Object>> currentOrderLogs = orderLogsMap.getOrDefault(order.getLong("id"), new ArrayList<>());
|
|
|
+ orderData.put("status_history", currentOrderLogs);
|
|
|
+
|
|
|
+ resultList.add(orderData);
|
|
|
+ }
|
|
|
+ return resultList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public long countOrders(Integer orderStatus) { // 接收 Integer 类型的 orderStatus
|
|
|
+ String sql = "SELECT COUNT(id) FROM t_order"; // COUNT(id) 更清晰
|
|
|
+ List<Object> params = new ArrayList<>();
|
|
|
+
|
|
|
+ // ✅ 根据 orderStatus 筛选
|
|
|
+ if (orderStatus != null && orderStatus >= 0) {
|
|
|
+ sql += " WHERE order_status = ?";
|
|
|
+ params.add(orderStatus);
|
|
|
+ }
|
|
|
+ return Db.queryLong(sql, params.toArray());
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean isOrderBelongToUser(long userId, long orderId) {
|
|
|
+ String sql = "SELECT COUNT(1) FROM t_order" +
|
|
|
+ " WHERE id=? and user_id=?";
|
|
|
+
|
|
|
+ return Db.queryInt(sql, orderId, userId) != 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 辅助方法:将 OrderLog Model 转换为 Map,并添加状态描述
|
|
|
+ * @param log OrderLog 对象
|
|
|
+ * @return 包含描述信息的 Map
|
|
|
+ */
|
|
|
+ private Map<String, Object> convertOrderLogToMap(OrderLog log) {
|
|
|
+ Map<String, Object> logMap = log.toMap(); // 获取原始日志属性
|
|
|
+
|
|
|
+ // 添加状态描述
|
|
|
+ logMap.put("from_status_desc", getStatusDescByCode(log.getInt("from_status")));
|
|
|
+ logMap.put("to_status_desc", getStatusDescByCode(log.getInt("to_status")));
|
|
|
+
|
|
|
+ return logMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据状态码获取状态描述
|
|
|
+ * 假设你已经定义了 OrderStatus 枚举
|
|
|
+ *
|
|
|
+ * @param statusCode 状态码
|
|
|
+ * @return 状态描述字符串
|
|
|
+ */
|
|
|
+ private String getStatusDescByCode(int statusCode) {
|
|
|
+ for (OrderController.OrderStatus status : OrderController.OrderStatus.values()) {
|
|
|
+ if (status.code == statusCode) {
|
|
|
+ return status.desc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "未知状态"; // 如果找不到对应的状态码
|
|
|
+ }
|
|
|
+
|
|
|
private String generateOrderSn() {
|
|
|
return System.currentTimeMillis() + "" + (int)(Math.random() * 10000);
|
|
|
}
|