This commit is contained in:
2026-08-03 13:16:19 +08:00
parent 481747d9dc
commit 9eb03d4bce
54 changed files with 1925 additions and 52 deletions
@@ -3,6 +3,7 @@ package com.baiyue.order.client;
import com.baiyue.common.core.api.ApiResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient(name="warehouse-service", contextId="warehousePartnerClient",
url="${baiyue.clients.warehouse.url:}", path="/internal/warehouse-partners")
@@ -10,5 +11,6 @@ public interface PartnerClient {
@GetMapping("/{tenantId}/{id}/active")
ApiResponse<Partner> active(@RequestHeader("X-Internal-Service-Token") String token,
@PathVariable("tenantId") long tenantId, @PathVariable("id") long id);
record Partner(Long id, Long tenantId, String partnerName, String status) { }
record Partner(Long id, Long tenantId, String partnerName, String status,
String partnerType, List<String> types) { }
}
@@ -6,6 +6,7 @@ import com.baiyue.common.core.api.PageResult;
import com.baiyue.common.security.AuthenticatedUser;
import com.baiyue.order.dto.OrderDetailResponse;
import com.baiyue.order.dto.OrderRequests;
import com.baiyue.order.dto.TenantOrderCountResponse;
import com.baiyue.order.entity.OrderEntity;
import com.baiyue.order.entity.OrderStatus;
import com.baiyue.order.service.OrderApplicationService;
@@ -27,6 +28,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PutMapping;
import java.util.List;
/**
* 平台端头程订单管理接口,在明确的目标租户范围内提供查询、审核和履约状态流转能力。
@@ -110,6 +112,20 @@ public class PlatformFirstLegOrderController {
return ApiResponse.success(service.page(OrderScopeGuard.platform(user, tenantId), query));
}
@GetMapping("/tenant-counts")
@PreAuthorize("hasAuthority('platform:order:list')")
@Operation(summary = "批量查询客户运单数", description = "按客户租户 ID 返回真实头程运单数量,最多 200 个客户。")
public ApiResponse<List<TenantOrderCountResponse>> tenantCounts(
@AuthenticationPrincipal AuthenticatedUser user,
@RequestParam List<Long> tenantIds) {
if (tenantIds.isEmpty() || tenantIds.size() > 200 || tenantIds.stream().anyMatch(id -> id == null || id <= 0)) {
throw new com.baiyue.common.core.exception.BizException(
com.baiyue.common.core.api.ResultCode.BAD_REQUEST, "1 to 200 valid tenant IDs are required / 需要 1 至 200 个有效租户 ID");
}
OrderScopeGuard.platform(user, tenantIds.get(0));
return ApiResponse.success(service.countByTenantIds(tenantIds));
}
@Operation(summary = "Tenant order detail / 租户订单详情", description = "Returns the complete order aggregate within the explicit target tenant. / 返回明确目标租户内的完整订单聚合。")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "Query succeeded / 查询成功"),
@@ -0,0 +1,6 @@
package com.baiyue.order.dto;
import io.swagger.v3.oas.annotations.media.Schema;
@Schema(name = "TenantOrderCountResponse", description = "平台客户的头程运单数量")
public record TenantOrderCountResponse(Long tenantId, Long orderCount) { }
@@ -5,11 +5,13 @@ import com.baiyue.order.dto.OrderRequests;
import com.baiyue.order.entity.*;
import com.baiyue.order.mapper.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Map;
/**
* 订单聚合仓储,组合订单主表、货物、参与方、备注、状态历史与 Outbox 的持久化操作,
@@ -86,6 +88,18 @@ public class OrderRepository {
return PageResult.from(orderMapper.selectPage(new Page<>(query.page(), query.size()), wrapper));
}
public Map<Long, Long> countByTenantIds(List<Long> tenantIds) {
if (tenantIds.isEmpty()) return Map.of();
var rows = orderMapper.selectMaps(new QueryWrapper<OrderEntity>()
.select("tenant_id", "COUNT(*) AS order_count")
.in("tenant_id", tenantIds)
.groupBy("tenant_id"));
return rows.stream().collect(java.util.stream.Collectors.toMap(
row -> ((Number) row.get("tenant_id")).longValue(),
row -> ((Number) row.get("order_count")).longValue()
));
}
public List<OrderCargoEntity> findCargo(long tenantId, long orderId) {
return cargoMapper.selectList(new LambdaQueryWrapper<OrderCargoEntity>()
.eq(OrderCargoEntity::getTenantId, tenantId).eq(OrderCargoEntity::getOrderId, orderId)
@@ -4,6 +4,7 @@ import com.baiyue.common.core.api.PageResult;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.order.dto.OrderDetailResponse;
import com.baiyue.order.dto.OrderRequests;
import com.baiyue.order.dto.TenantOrderCountResponse;
import com.baiyue.order.entity.*;
import com.baiyue.order.repository.OrderRepository;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
@@ -108,6 +109,13 @@ public class OrderApplicationService {
}
public PageResult<OrderEntity> page(long tenantId, OrderRequests.QueryRequest query) { return repository.page(tenantId, query); }
public List<TenantOrderCountResponse> countByTenantIds(List<Long> tenantIds) {
var counts = repository.countByTenantIds(tenantIds);
return tenantIds.stream().distinct()
.map(tenantId -> new TenantOrderCountResponse(tenantId, counts.getOrDefault(tenantId, 0L)))
.toList();
}
public OrderDetailResponse detail(long tenantId, long id) {
OrderEntity order = require(tenantId, id);
return new OrderDetailResponse(order, repository.findCargo(tenantId, id), repository.findParties(tenantId, id),
@@ -72,6 +72,8 @@ public class OrderMasterDataGuard {
throw new BizException(ResultCode.FORBIDDEN,"往来单位不属于当前企业");
if (!"ACTIVE".equals(value.status()))
throw new BizException(ResultCode.CONFLICT,"往来单位已停用");
if (value.types() == null || !value.types().contains("SHIPPER"))
throw new BizException(ResultCode.VALIDATION_FAILED,"所选往来单位不具备发货单位类型");
if (!StringUtils.hasText(value.partnerName())) throw unavailable("往来单位");
return value;
}
@@ -40,6 +40,18 @@ paths:
responses:
'200': {description: 成功或业务失败,按响应体 code 判断}
'403': {description: 需要 platform:order:create 权限}
/api/platform/v1/orders/first-leg/tenant-counts:
get:
summary: 批量查询客户运单数
description: 按客户租户 ID 返回真实头程运单数量,最多 200 个租户。
parameters:
- name: tenantIds
in: query
required: true
schema: {type: array, maxItems: 200, items: {type: integer, format: int64}}
responses:
'200': {description: 查询成功或业务失败,按响应体 code 判断}
'403': {description: 需要 platform:order:list 权限}
/api/platform/v1/orders/first-leg/{id}/submit:
post:
summary: 平台代客提交指定订单