✨ 小程序调度端运单列表、待处理与统计按组织收口
原先三个取数入口都不带组织条件,租户内两个组织的运单混在同一张表里。「小程序管理」 账号与运单业务组织不一致确实是事实,但那是账号挂在一个已软删部门上的脏数据症状, 不是「不该按组织过滤」的理由。 现在与后台运单列表同一条规则:普通用户只出自己所属组织,超级管理员不过滤, 小程序端不提供「全部组织」开关;详情与重新派单照旧不按组织收口。 组织条件由调用方算好、经 TripQueryVO.deptIds 落到运次读服务的运单行上, 列表、待处理与首页三档统计因此共用同一条可见范围;「待重新派单」另走库层分组查询, 单独带上,首页重派角标与待办 feed 随之一起收口。 运次读服务的分档统计走一份「去掉 Tab 条件」的副本,该副本必须照搬 deptIds, 否则统计会退回全租户、与列表的数对不上(已由用例钉住)。 存量 42 张 dept_id 为 -1 或 NULL 的运单不属于任何组织,收紧后普通用户再也看不到, 另订正到各自的创建组织,见 doc/sql/transport/blade_waybill_dept_backfill_20261018.sql。 新增 ManageWaybillOrgScopeTest(8 项),TripQueryServiceImplTest 补 3 项; blade-transport 全量 376 项用例通过。
This commit is contained in:
+1
-1
@@ -69,7 +69,7 @@ public class ManageWaybillController extends BladeController {
|
||||
|
||||
@GetMapping("/stats")
|
||||
@ApiOperationSupport(order = 1)
|
||||
@Operation(summary = "运单状态统计", description = "待接单=pending,运输中=running,已完成=completed;租户内不过滤组织(小程序调度账号组织常与运单不一致);在途异常=异常处置状态≠已完成")
|
||||
@Operation(summary = "运单状态统计", description = "待接单=pending,运输中=running,已完成=completed;只统计本组织的运单(超级管理员不过滤组织);在途异常=异常处置状态≠已完成")
|
||||
public R<AdminHomeStatsVO> stats() {
|
||||
return R.data(manageWaybillService.stats());
|
||||
}
|
||||
|
||||
+27
-6
@@ -59,6 +59,7 @@ import org.springblade.transport.service.IManageWaybillService;
|
||||
import org.springblade.transport.service.IRiskDisposalService;
|
||||
import org.springblade.transport.service.ITripQueryService;
|
||||
import org.springblade.transport.service.IWaybillService;
|
||||
import org.springblade.transport.support.TransportBusinessSupport;
|
||||
import org.springblade.transport.support.WaybillProcessSupport;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -140,7 +141,9 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
public AdminHomeStatsVO stats() {
|
||||
AdminHomeStatsVO vo = new AdminHomeStatsVO();
|
||||
// 三档状态按运次计:有配载单的一趟车算一个,与列表和司机端同一份聚合
|
||||
TripTabCountsVO tripCounts = tripQueryService.tabCounts(TripQueryVO.forAdmin());
|
||||
TripQueryVO query = TripQueryVO.forAdmin();
|
||||
query.setDeptIds(manageableDeptIds());
|
||||
TripTabCountsVO tripCounts = tripQueryService.tabCounts(query);
|
||||
vo.setPendingAccept(tripCounts.getPending());
|
||||
vo.setTransporting(tripCounts.getDoing());
|
||||
vo.setCompleted(tripCounts.getDone());
|
||||
@@ -177,6 +180,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
// 组织类型 / 异常 / 创建时间都是子单行级条件,与状态、关键字、分页一起交给运次读服务,
|
||||
// 一次取数取完整趟车:分组、分档、筛选、排序与分页都在它那边算完
|
||||
TripQueryVO query = TripQueryVO.forAdmin();
|
||||
query.setDeptIds(manageableDeptIds());
|
||||
query.setStatus(toTripStatus(status));
|
||||
query.setKeyword(keyword);
|
||||
query.setTransportOrgType(transportType);
|
||||
@@ -224,6 +228,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
|
||||
Set<Long> exceptionWaybillIds = loadIncompleteExceptionWaybillIds();
|
||||
TripQueryVO query = TripQueryVO.forAdmin();
|
||||
query.setDeptIds(manageableDeptIds());
|
||||
query.setKeyword(keyword);
|
||||
// 待处理只要待接单与进行中两档;「未拒单」也是交给运次读服务按子单行筛
|
||||
query.setStatuses(List.of(0, 1));
|
||||
@@ -686,6 +691,11 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
SQL_MAX_REJECT_TIME + " AS driver_reject_time", SQL_MAX_CREATE_TIME + " AS create_time");
|
||||
wrapper.eq("driver_accept_status", ACCEPT_REJECTED);
|
||||
wrapper.in("business_status", STATUS_PENDING, STATUS_RUNNING);
|
||||
// 这条查询不经运次读服务,组织收口得自己带上,否则待重派列表与首页重派角标会出别的组织的单
|
||||
List<Long> deptIds = manageableDeptIds();
|
||||
if (Func.isNotEmpty(deptIds)) {
|
||||
wrapper.in("dept_id", deptIds);
|
||||
}
|
||||
wrapper.groupBy(TripAggregation.SQL_TRIP_KEY);
|
||||
return wrapper;
|
||||
}
|
||||
@@ -895,11 +905,22 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序调度端不做组织过滤。
|
||||
* 「小程序管理」等账号 JWT/档案 dept 常与运单业务组织不一致,按 dept 过滤会导致统计全 0;
|
||||
* 与后台 allDept=1 一致,仅依赖租户隔离(MyBatis-Plus TenantLine)。
|
||||
* 调度端可见组织:普通用户(含各级角色)只出自己所属组织,超级管理员不过滤。
|
||||
* <p>
|
||||
* 与后台运单列表同一条规则({@link TransportBusinessSupport#resolveDeptFilterIds}),
|
||||
* 小程序端不提供「全部组织」开关,故两个入参固定传空;详情与重新派单不按组织收口。
|
||||
*/
|
||||
private LambdaQueryWrapper<Waybill> scopedWaybillQuery() {
|
||||
private List<Long> manageableDeptIds() {
|
||||
return TransportBusinessSupport.resolveDeptFilterIds(null, null, "运单管理");
|
||||
}
|
||||
|
||||
/**
|
||||
* 已拒子单的查询底:只有租户与逻辑删除(MyBatis-Plus 自动补),不带组织。
|
||||
* <p>
|
||||
* 它服务的是「这个运次里有没有被拒的子单」,可见范围由调用方先定好——列表传的运次已经收过组织,
|
||||
* 详情按主键进入不收组织。这里再按组织收一次,详情里别的组织的运次会丢掉重派标记。
|
||||
*/
|
||||
private LambdaQueryWrapper<Waybill> rejectedChildQuery() {
|
||||
return Wrappers.<Waybill>lambdaQuery();
|
||||
}
|
||||
|
||||
@@ -1039,7 +1060,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<Waybill> pendingReassignQuery() {
|
||||
return scopedWaybillQuery()
|
||||
return rejectedChildQuery()
|
||||
.eq(Waybill::getDriverAcceptStatus, ACCEPT_REJECTED)
|
||||
.in(Waybill::getBusinessStatus, STATUS_PENDING, STATUS_RUNNING);
|
||||
}
|
||||
|
||||
+15
@@ -236,6 +236,7 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
.and(visible -> visible.isNull(Waybill::getDriverAcceptStatus)
|
||||
.or().ne(Waybill::getDriverAcceptStatus, WaybillProcessSupport.ACCEPT_REJECTED));
|
||||
applyScope(wrapper, condition);
|
||||
applyDeptScope(wrapper, condition);
|
||||
applyOrgTypeFilter(wrapper, condition);
|
||||
applyKeyword(wrapper, condition.getKeyword());
|
||||
List<Waybill> rows = waybillService.list(wrapper);
|
||||
@@ -243,6 +244,19 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组织收口:条件里给了组织 ID 集合时只出这些组织的运单行,空集合表示不过滤。
|
||||
* <p>
|
||||
* 与司机手机号收口一样落在库层的运单行上:分档、分页、总数都由它缩过的行集合算出来。
|
||||
* 读服务不自己解析当前用户的组织——它同时服务司机端与管理端,可见范围由调用方算好再传。
|
||||
*/
|
||||
private void applyDeptScope(LambdaQueryWrapper<Waybill> wrapper, TripQueryVO condition) {
|
||||
if (Func.isEmpty(condition.getDeptIds())) {
|
||||
return;
|
||||
}
|
||||
wrapper.in(Waybill::getDeptId, condition.getDeptIds());
|
||||
}
|
||||
|
||||
/**
|
||||
* 运输组织类型按子单行筛:它在同一趟车里必然是同一个值(配载的每张子单带同一个配载单号,
|
||||
* 未配载的每张自成一趟车),所以这一层不会把一趟车拆开。
|
||||
@@ -709,6 +723,7 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
TripQueryVO copy = new TripQueryVO();
|
||||
copy.setDriverPhone(source.getDriverPhone());
|
||||
copy.setAllDrivers(source.isAllDrivers());
|
||||
copy.setDeptIds(source.getDeptIds());
|
||||
copy.setKeyword(source.getKeyword());
|
||||
copy.setTransportOrgType(source.getTransportOrgType());
|
||||
copy.setException(source.getException());
|
||||
|
||||
Reference in New Issue
Block a user