Browse Source

执法端-计划

dev-V1.0.1
庄锐波 5 months ago
parent
commit
41ff2bd6c6
  1. 4
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpPlanService.java
  2. 218
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java
  3. 58
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpReserveServiceImpl.java
  4. 1
      zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpPlanMapper.xml
  5. 60
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_mine.vue
  6. 4
      zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/cp/AppEnfCpAutoReserveTest.java

4
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpPlanService.java

@ -9,6 +9,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.zdxt.enforcementcode.domain.EfcodeCpReserve; import com.zdxt.enforcementcode.domain.EfcodeCpReserve;
import org.springframework.transaction.annotation.Transactional;
/** /**
* 行政执法检查计划-计划Service接口 * 行政执法检查计划-计划Service接口
@ -89,6 +90,9 @@ public interface IEfcodeCpPlanService {
*/ */
Map<String, List<EfcodeCpReserve>> autoMatchReserve(boolean forceMatch, boolean updatePlan, boolean insertReserve); Map<String, List<EfcodeCpReserve>> autoMatchReserve(boolean forceMatch, boolean updatePlan, boolean insertReserve);
@Transactional(rollbackFor = Exception.class)
Map<String, List<EfcodeCpReserve>> autoMatchReserveV3(boolean forceMatch, boolean updatePlan, boolean insertReserve);
/** /**
* 计划自动匹配预约V2(定时任务调用) * 计划自动匹配预约V2(定时任务调用)
* <p>扫描待预约状态的计划,按自然周分组匹配,超出最大联合数量时拆分多组</p> * <p>扫描待预约状态的计划,按自然周分组匹配,超出最大联合数量时拆分多组</p>

218
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java

@ -293,7 +293,15 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService {
lqw.eq(bo.getIsPublic() != null, EfcodeCpPlan::getIsPublic, bo.getIsPublic()); lqw.eq(bo.getIsPublic() != null, EfcodeCpPlan::getIsPublic, bo.getIsPublic());
lqw.eq(bo.getIsUnion() != null, EfcodeCpPlan::getIsUnion, bo.getIsUnion()); lqw.eq(bo.getIsUnion() != null, EfcodeCpPlan::getIsUnion, bo.getIsUnion());
lqw.eq(StringUtils.isNotBlank(bo.getUnionBureauDeptNames()), EfcodeCpPlan::getUnionBureauDeptNames, bo.getUnionBureauDeptNames()); lqw.eq(StringUtils.isNotBlank(bo.getUnionBureauDeptNames()), EfcodeCpPlan::getUnionBureauDeptNames, bo.getUnionBureauDeptNames());
lqw.eq(bo.getReserveStatus() != null, EfcodeCpPlan::getReserveStatus, bo.getReserveStatus()); // 支持多值状态过滤(逗号分隔)
String reserveStatusList = params != null ? (String) params.get("reserveStatusList") : null;
if (StringUtils.isNotBlank(reserveStatusList)) {
List<Long> statusList = java.util.Arrays.stream(reserveStatusList.split(","))
.map(String::trim).map(Long::valueOf).collect(Collectors.toList());
lqw.in(EfcodeCpPlan::getReserveStatus, statusList);
} else {
lqw.eq(bo.getReserveStatus() != null, EfcodeCpPlan::getReserveStatus, bo.getReserveStatus());
}
lqw.eq(bo.getSystemReserved() != null, EfcodeCpPlan::getSystemReserved, bo.getSystemReserved()); lqw.eq(bo.getSystemReserved() != null, EfcodeCpPlan::getSystemReserved, bo.getSystemReserved());
lqw.eq(bo.getManualReserved() != null, EfcodeCpPlan::getManualReserved, bo.getManualReserved()); lqw.eq(bo.getManualReserved() != null, EfcodeCpPlan::getManualReserved, bo.getManualReserved());
lqw.eq(StringUtils.isNotBlank(bo.getBureauDeptId()), EfcodeCpPlan::getBureauDeptId, bo.getBureauDeptId()); lqw.eq(StringUtils.isNotBlank(bo.getBureauDeptId()), EfcodeCpPlan::getBureauDeptId, bo.getBureauDeptId());
@ -732,6 +740,182 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService {
return resultMap; return resultMap;
} }
@Transactional(rollbackFor = Exception.class)
@Override
public Map<String, List<EfcodeCpReserve>> autoMatchReserveV3(boolean forceMatch, boolean updatePlan, boolean insertReserve) {
log.info("[CpPlan-V2] 开始执行计划自动匹配预约, forceMatch={}, updatePlan={}, insertReserve={}", forceMatch, updatePlan, insertReserve);
Map<String, List<EfcodeCpReserve>> resultMap = new HashMap<>();
// 1. 日期校验:如果不是强制匹配,则判断当前天数是否等于 CP_SETTING_AUTO_MATCH_START
if (!forceMatch) {
int autoMatchStart = cpSettingService.getAutoMatchStart();
int today = LocalDate.now().getDayOfMonth();
if (today != autoMatchStart) {
log.info("[CpPlan-V2] 当前日期{}号,不等于设定的自动匹配日期{}号,跳过执行", today, autoMatchStart);
return resultMap;
}
}
// 2. 获取最大联合单位数量
int maxUnionUnit = cpSettingService.getMaxUnionUnit();
// 2.1 获取系统匹配预约周数范围
int systemMatchWeeks = cpSettingService.getSystemMatchWeeks();
log.info("[CpPlan-V2] 系统匹配周数范围={}", systemMatchWeeks);
// 3. 查询待匹配的计划:plan_date > 当前时间 且 system_reserved=0, manual_reserved=0, reserve_status=1, is_public=1, is_union=1
Date now = new Date();
LambdaQueryWrapper<EfcodeCpPlan> lqw = Wrappers.lambdaQuery();
lqw.gt(EfcodeCpPlan::getPlanDate, now);
lqw.eq(EfcodeCpPlan::getSystemReserved, 0L);
lqw.eq(EfcodeCpPlan::getManualReserved, 0L);
lqw.eq(EfcodeCpPlan::getReserveStatus, 1L);
lqw.eq(EfcodeCpPlan::getIsPublic, 1L);
lqw.eq(EfcodeCpPlan::getIsUnion, 1L);
lqw.eq(EfcodeCpPlan::getIsDelete, 0L);
lqw.isNotNull(EfcodeCpPlan::getCreateBy);
lqw.orderByAsc(EfcodeCpPlan::getPlanDate);
List<EfcodeCpPlan> pendingPlans = baseMapper.selectList(lqw);
if (pendingPlans.isEmpty()) {
log.info("[CpPlan-V2] 没有找到待匹配的计划记录,执行结束");
return resultMap;
}
log.info("[CpPlan-V2] 共查询到{}条待匹配计划", pendingPlans.size());
// 存储将要保存的联合记录列表
List<EfcodeCpReserve> unionReserveList = new ArrayList<>();
// 记录已被处理(system_reserved标记为1)的计划ID,避免重复处理
Set<String> processedPlanIds = new HashSet<>();
int matchedCount = 0;
for (EfcodeCpPlan plan : pendingPlans) {
// 已被处理过的计划跳过
if (processedPlanIds.contains(plan.getId())) {
continue;
}
log.info("[CpPlan-V2] 开始处理计划记录,计划ID={}", plan.getId());
String enterpriseNumber = plan.getEnterpriseNumber();
if (StringUtils.isBlank(enterpriseNumber)) {
continue;
}
// 5. 计算计划所在的时间范围:以计划所在自然周的周一为起始,向后扩展 systemMatchWeeks 周
LocalDate planLocalDate = plan.getPlanDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate weekStartDate = planLocalDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
LocalDate weekEndDate = weekStartDate.plusWeeks(systemMatchWeeks).minusDays(1); // 扩展N周后的周日
log.info("[CpPlan-V2] 计划ID={}的时间范围是:{} ~ {}", plan.getId(), weekStartDate, weekEndDate);
// 6. 从待匹配计划中筛选:同企业 + 时间范围内 + 不是当前计划创建者发布的 + 未被处理过
List<EfcodeCpPlan> matchedPlans = pendingPlans.stream()
.filter(p -> {
// 排除自身
if (p.getId().equals(plan.getId())) {
return false;
}
// 排除已处理过的
if (processedPlanIds.contains(p.getId())) {
return false;
}
// 同企业
if (!enterpriseNumber.equals(p.getEnterpriseNumber())) {
return false;
}
// 不是当前计划创建者发布的(不是我的计划)
if (plan.getCreateBy() != null && plan.getCreateBy().equals(p.getCreateBy())) {
return false;
}
// 在时间范围内
LocalDate pDate = p.getPlanDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
return !pDate.isBefore(weekStartDate) && !pDate.isAfter(weekEndDate);
})
.collect(Collectors.toList());
log.info("[CpPlan-V2] 计划ID={}, 在时间范围内找到{}条非本人发布的同企业计划", plan.getId(), matchedPlans.size());
// 7. 从matchedPlans中取出不超过 maxUnionUnit-1 条记录(当前计划本身占1个名额)
int limit = maxUnionUnit - 1;
List<EfcodeCpPlan> selectedPlans = matchedPlans.stream()
.limit(limit)
.collect(Collectors.toList());
log.info("[CpPlan-V2] 计划ID={}, 最终选取{}条计划参与联合(最大允许{}条)", plan.getId(), selectedPlans.size(), limit);
// 8. 如果没有可联合的计划,跳过
if (selectedPlans.isEmpty()) {
log.debug("[CpPlan-V2] 计划ID={} 没有找到可联合的计划,跳过", plan.getId());
continue;
}
// 9. 将当前plan和selectedPlans作为一组,生成预约记录
String planGroupId = "Temp" + "_" + UUID.randomUUID().toString().replace("-", "");
Date reserveTime = new Date();
List<EfcodeCpReserve> groupReserves = new ArrayList<>();
// 组内所有计划(当前计划 + 选中的计划)
List<EfcodeCpPlan> groupPlans = new ArrayList<>();
groupPlans.add(plan);
groupPlans.addAll(selectedPlans);
// 拼接参与单位名称
String unitNames = groupPlans.stream()
.map(EfcodeCpPlan::getBureauDeptName)
.filter(StringUtils::isNotBlank)
.collect(Collectors.joining(","));
String opMessage = "由于计划执法时间安排较近,系统推荐进行联合,参与单位为:" + unitNames + ".请确认.";
for (EfcodeCpPlan matchedPlan : groupPlans) {
EfcodeCpReserve reserve = new EfcodeCpReserve();
reserve.setPlanId(matchedPlan.getId());
reserve.setPlanGroupId(planGroupId);
reserve.setReserveTime(reserveTime);
reserve.setOpStatus(3L); // 待确认
reserve.setOpOrder(0L); // 系统匹配默认为0
reserve.setOpMessage(opMessage);
reserve.setOpSetDate(matchedPlan.getPlanDate());
reserve.setOpSetTime(matchedPlan.getPlanTime());
reserve.setResFrom(1L); // 系统匹配
reserve.setSenderId("from_system");
reserve.setReceiverId(String.valueOf(matchedPlan.getCreateBy()));
if (insertReserve) {
efcodeCpReserveMapper.insert(reserve);
}
groupReserves.add(reserve);
}
// 加入总的待处理列表
unionReserveList.addAll(groupReserves);
resultMap.put(planGroupId, groupReserves);
// 10. 将组内所有计划标记为 system_reserved=1,并更新 reserve_status=2(预约中)
if (updatePlan) {
for (EfcodeCpPlan gp : groupPlans) {
EfcodeCpPlan planUpdate = new EfcodeCpPlan();
planUpdate.setId(gp.getId());
planUpdate.setSystemReserved(1L);
planUpdate.setReserveStatus(2L);
baseMapper.updateById(planUpdate);
}
}
// 将组内所有计划ID加入已处理集合,防止重复匹配
for (EfcodeCpPlan gp : groupPlans) {
processedPlanIds.add(gp.getId());
}
matchedCount++;
log.info("[CpPlan-V2] 计划ID={} 匹配成功,联合{}个单位,planGroupId={}",
plan.getId(), groupPlans.size(), planGroupId);
}
log.info("[CpPlan-V2] 计划自动匹配预约执行完毕,共匹配{}组联合预约,共生成{}条预约记录", matchedCount, unionReserveList.size());
return resultMap;
}
/** /**
* 计划自动匹配预约V2(定时任务调用) * 计划自动匹配预约V2(定时任务调用)
* <p>扫描待预约状态的计划,按自然周分组匹配,超出最大联合数量时拆分多组</p> * <p>扫描待预约状态的计划,按自然周分组匹配,超出最大联合数量时拆分多组</p>
@ -822,7 +1006,7 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService {
weekLqw.orderByAsc(EfcodeCpPlan::getPlanDate); weekLqw.orderByAsc(EfcodeCpPlan::getPlanDate);
List<EfcodeCpPlan> samePlans = baseMapper.selectList(weekLqw); List<EfcodeCpPlan> samePlans = baseMapper.selectList(weekLqw);
// 7. 按不同执法单位去重,取每个 bureau_dept_id 的第一条计划作为代表 // 7. 按 bureau_dept_id 去重,每个单位取一条代表计划
List<EfcodeCpPlan> distinctUnitPlans = new ArrayList<>(); List<EfcodeCpPlan> distinctUnitPlans = new ArrayList<>();
Set<String> seenBureauDeptIds = new HashSet<>(); Set<String> seenBureauDeptIds = new HashSet<>();
for (EfcodeCpPlan sp : samePlans) { for (EfcodeCpPlan sp : samePlans) {
@ -833,18 +1017,17 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService {
} }
} }
// 8. 如果只有一个单位的计划,说明没有可联合的,跳过 // 8. 只有1个单位的计划,无法联合,跳过
if (distinctUnitPlans.size() <= 1) { if (distinctUnitPlans.size() <= 1) {
log.debug("[CpPlan-V2] 企业[{}] 周[{}~{}]内只有1个单位的计划,跳过", enterpriseNumber, weekStartDate, weekEndDate); log.debug("[CpPlan-V2] 企业[{}] 周[{}~{}]内只有1个单位的计划,跳过", enterpriseNumber, weekStartDate, weekEndDate);
continue; continue;
} }
// 9. 按最大联合单位数量分组:如果不同单位数 > maxUnionUnit,则拆分成多组 // 9. 按最大联合单位数量分组
List<List<EfcodeCpPlan>> groups = new ArrayList<>(); List<List<EfcodeCpPlan>> groups = new ArrayList<>();
for (int i = 0; i < distinctUnitPlans.size(); i += maxUnionUnit) { for (int i = 0; i < distinctUnitPlans.size(); i += maxUnionUnit) {
int end = Math.min(i + maxUnionUnit, distinctUnitPlans.size()); int end = Math.min(i + maxUnionUnit, distinctUnitPlans.size());
List<EfcodeCpPlan> group = distinctUnitPlans.subList(i, end); List<EfcodeCpPlan> group = distinctUnitPlans.subList(i, end);
// 每组至少需要2个不同单位才有联合意义
if (group.size() >= 2) { if (group.size() >= 2) {
groups.add(new ArrayList<>(group)); groups.add(new ArrayList<>(group));
} }
@ -855,12 +1038,12 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService {
} }
// 10. 为每组生成预约记录 // 10. 为每组生成预约记录
Set<String> matchedPlanIds = new HashSet<>();
for (List<EfcodeCpPlan> group : groups) { for (List<EfcodeCpPlan> group : groups) {
String planGroupId = "Temp" + "_" + UUID.randomUUID().toString().replace("-", ""); String planGroupId = "Temp" + "_" + UUID.randomUUID().toString().replace("-", "");
Date reserveTime = new Date(); Date reserveTime = new Date();
List<EfcodeCpReserve> groupReserves = new ArrayList<>(); List<EfcodeCpReserve> groupReserves = new ArrayList<>();
// 拼接参与单位名称,用于 opMessage
String unitNames = group.stream() String unitNames = group.stream()
.map(EfcodeCpPlan::getBureauDeptName) .map(EfcodeCpPlan::getBureauDeptName)
.filter(StringUtils::isNotBlank) .filter(StringUtils::isNotBlank)
@ -887,7 +1070,7 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService {
groupReserves.add(reserve); groupReserves.add(reserve);
} }
// 更新被选中参与联合的计划: reserve_status=2(预约中) // 更新被选中参与联合的计划: reserve_status=2(预约中), system_reserved=1
if (updatePlan) { if (updatePlan) {
for (EfcodeCpPlan dp : group) { for (EfcodeCpPlan dp : group) {
EfcodeCpPlan planUpdate = new EfcodeCpPlan(); EfcodeCpPlan planUpdate = new EfcodeCpPlan();
@ -895,27 +1078,28 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService {
planUpdate.setReserveStatus(2L); planUpdate.setReserveStatus(2L);
planUpdate.setSystemReserved(1L); planUpdate.setSystemReserved(1L);
baseMapper.updateById(planUpdate); baseMapper.updateById(planUpdate);
matchedPlanIds.add(dp.getId());
} }
} }
resultMap.put(planGroupId, groupReserves); resultMap.put(planGroupId, groupReserves);
matchedCount++; matchedCount++;
log.info("[CpPlan-V2] 企业[{}] 周[{}~{}] 分组匹配成功,联合{}个单位,planGroupId={}", log.info("[CpPlan-V2] 企业[{}] 周[{}~{}] 匹配成功,联合{}个单位,planGroupId={}",
enterpriseNumber, weekStartDate, weekEndDate, group.size(), planGroupId); enterpriseNumber, weekStartDate, weekEndDate, group.size(), planGroupId);
} }
// 11. 将该企业该周所有待匹配计划的 system_reserved 标记为1,防止重复匹配 // 11. 将已成功匹配的单位在该企业该周内的所有计划标记为 system_reserved=1,防止重复匹配
if (updatePlan) { if (updatePlan && !groups.isEmpty()) {
for (EfcodeCpPlan sp : samePlans) { for (EfcodeCpPlan sp : samePlans) {
// 已在上面group循环中更新过的(reserve_status=2)跳过,避免覆盖 if (matchedPlanIds.contains(sp.getId())) {
if (seenBureauDeptIds.contains(sp.getBureauDeptId())) {
// 该计划对应的单位已经参与联合,在group循环中已处理
continue; continue;
} }
EfcodeCpPlan planUpdate = new EfcodeCpPlan(); if (seenBureauDeptIds.contains(sp.getBureauDeptId())) {
planUpdate.setId(sp.getId()); EfcodeCpPlan planUpdate = new EfcodeCpPlan();
planUpdate.setSystemReserved(1L); planUpdate.setId(sp.getId());
baseMapper.updateById(planUpdate); planUpdate.setSystemReserved(1L);
baseMapper.updateById(planUpdate);
}
} }
} }
} }

58
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpReserveServiceImpl.java

@ -767,6 +767,9 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService {
return 0; return 0;
} }
// 收集受影响的分组ID(系统匹配用)
Set<String> affectedGroupIds = new HashSet<>();
Date now = new Date(); Date now = new Date();
for (EfcodeCpReserve reserve : overdueList) { for (EfcodeCpReserve reserve : overdueList) {
// 更新预约记录状态为超期取消(4) // 更新预约记录状态为超期取消(4)
@ -783,9 +786,64 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService {
planUpdate.setReserveStatus(4L); planUpdate.setReserveStatus(4L);
cpPlanMapper.updateById(planUpdate); cpPlanMapper.updateById(planUpdate);
} }
// 系统匹配记录收集分组ID
if (Long.valueOf(1L).equals(resFrom) && StringUtils.isNotBlank(reserve.getPlanGroupId())) {
affectedGroupIds.add(reserve.getPlanGroupId());
}
} }
log.info("[超期取消] resFrom={} ignoreTime={} 共取消{}条记录", resFrom, ignoreTime, overdueList.size()); log.info("[超期取消] resFrom={} ignoreTime={} 共取消{}条记录", resFrom, ignoreTime, overdueList.size());
// 系统匹配:取消后检查受影响的分组,若有已同意的记录则触发任务生成
if (Long.valueOf(1L).equals(resFrom) && !affectedGroupIds.isEmpty()) {
for (String groupId : affectedGroupIds) {
afterCancelGroupCheck(groupId);
}
}
return overdueList.size(); return overdueList.size();
} }
/**
* 超期取消后分组检查:若同组中有已同意的记录,且全部处理完成,则生成任务
*/
private void afterCancelGroupCheck(String planGroupId) {
// 查询同组全部记录
List<EfcodeCpReserve> allGroupReserves = baseMapper.selectList(
Wrappers.<EfcodeCpReserve>lambdaQuery()
.eq(EfcodeCpReserve::getPlanGroupId, planGroupId)
);
// 检查是否全部处理完成(无待确认记录)
boolean allProcessed = allGroupReserves.stream()
.noneMatch(r -> Long.valueOf(3L).equals(r.getOpStatus()));
if (!allProcessed) {
return;
}
// 筛选同意的记录
List<EfcodeCpReserve> approvedReserves = allGroupReserves.stream()
.filter(r -> Long.valueOf(1L).equals(r.getOpStatus()))
.collect(java.util.stream.Collectors.toList());
if (approvedReserves.isEmpty()) {
log.info("[超期取消后置] planGroupId={} 无已同意记录,不生成任务", planGroupId);
return;
}
// 至少一家同意:生成1条任务,只关联同意的计划
String sharedTaskId = null;
for (EfcodeCpReserve r : approvedReserves) {
EfcodeCpPlan plan = cpPlanMapper.selectById(r.getPlanId());
if (plan == null || StringUtils.isNotBlank(plan.getTaskId())) continue;
if (sharedTaskId == null) {
sharedTaskId = cpTaskService.forceGenerateTask(plan);
} else {
EfcodeCpPlan planUpdate = new EfcodeCpPlan();
planUpdate.setId(plan.getId());
planUpdate.setTaskId(sharedTaskId);
planUpdate.setReserveStatus(3L);
cpPlanMapper.updateById(planUpdate);
}
}
log.info("[超期取消后置] planGroupId={} 有{}家已同意,生成任务taskId={}",
planGroupId, approvedReserves.size(), sharedTaskId);
}
} }

1
zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpPlanMapper.xml

@ -8,7 +8,6 @@
<select id="selectOtherPageList" resultType="com.zdxt.enforcementcode.domain.vo.EfcodeCpPlanVo"> <select id="selectOtherPageList" resultType="com.zdxt.enforcementcode.domain.vo.EfcodeCpPlanVo">
SELECT SELECT
id, plan_type, plan_date, plan_time, id, plan_type, plan_date, plan_time,
plan_actual_date, plan_actual_time,
enforce_content, enterprise_name, enterprise_number, enterprise_id, enforce_content, enterprise_name, enterprise_number, enterprise_id,
enforce_user_names, enforce_user_ids, enforce_user_codes, enforce_user_tels, enforce_user_names, enforce_user_ids, enforce_user_codes, enforce_user_tels,
is_public, is_union, union_bureau_dept_names, is_public, is_union, union_bureau_dept_names,

60
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_mine.vue

@ -1,5 +1,18 @@
<template> <template>
<div class="plan-mine"> <div class="plan-mine">
<!-- 状态过滤栏 -->
<div class="filter-bar">
<div
v-for="opt in filterOptions"
:key="opt.label"
class="filter-item"
:class="{ active: filterStatus === opt.value }"
@click="onFilterChange(opt.value)"
>
{{ opt.label }}
</div>
</div>
<!-- 搜索触发栏 --> <!-- 搜索触发栏 -->
<div class="search-trigger" @click="showSearchPopup = true"> <div class="search-trigger" @click="showSearchPopup = true">
<van-icon name="search" size="16" color="#666" /> <van-icon name="search" size="16" color="#666" />
@ -46,7 +59,7 @@
@click="onToggleExpand(item)" @click="onToggleExpand(item)"
> >
<div class="card-header"> <div class="card-header">
<div class="card-type">{{ item.isUnion === 1 ? '联合执法' : '非联合执法' }}</div> <div class="card-type">{{ item.isUnion === 1 ? '联合执法' : '非联合执法' }} / {{ item.isPublic === 1 ? '公开' : '非公开' }}</div>
<div class="status blue"> <div class="status blue">
{{ getStatusText(item.reserveStatus) }} {{ getStatusText(item.reserveStatus) }}
</div> </div>
@ -199,6 +212,20 @@ import { getPlanList, deletePlan } from '@/api/enforcement/plan';
const emit = defineEmits(['edit']); const emit = defineEmits(['edit']);
// 状态过滤
const filterStatus = ref(null);
const filterOptions = [
{ label: '全部', value: null },
{ label: '待预约', value: '1,4,5' },
{ label: '预约中', value: '2' },
{ label: '预约完成', value: '3,6,7' },
];
const onFilterChange = (val) => {
filterStatus.value = val;
doSearch();
};
// 排序相关 // 排序相关
const sortField = ref('createTime'); // createTime | planDate const sortField = ref('createTime'); // createTime | planDate
const sortOrder = ref('desc'); // desc | asc const sortOrder = ref('desc'); // desc | asc
@ -294,7 +321,7 @@ const onToggleExpand = (item) => {
// 状态文本映射 // 状态文本映射
const getStatusText = (status) => { const getStatusText = (status) => {
const map = { 0: '草稿', 1: '待预约(未发起联合)', 2: '预约中', 3: '预约完成', 4: '重新预约中', 5: '待预约(还有位置可以加入)', 6: '待预约(人数已满)', 7: '预约完成(人数已满)' }; const map = { 0: '草稿', 1: '待预约(未发起联合)', 2: '预约中', 3: '预约完成', 4: '重新预约', 5: '待预约(还有位置可以加入)', 6: '待预约(人数已满)', 7: '预约完成(人数已满)' };
return map[status] || '待确认'; return map[status] || '待确认';
}; };
@ -346,6 +373,10 @@ const fetchList = () => {
// 携带排序条件 // 携带排序条件
params.orderByColumn = sortField.value; params.orderByColumn = sortField.value;
params.isAsc = sortOrder.value; params.isAsc = sortOrder.value;
// 携带状态过滤
if (filterStatus.value) {
params['params[reserveStatusList]'] = filterStatus.value;
}
getPlanList( getPlanList(
params, params,
(res) => { (res) => {
@ -407,6 +438,31 @@ const onDeletePlan = (item) => {
box-sizing: border-box; box-sizing: border-box;
} }
.filter-bar {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 0;
overflow-x: auto;
.filter-item {
flex-shrink: 0;
font-size: 13px;
color: #666;
padding: 5px 14px;
border-radius: 16px;
background: #f5f5f5;
cursor: pointer;
transition: all 0.2s;
&.active {
color: #fff;
background: linear-gradient(135deg, #1890ff, #0b63d1);
font-weight: 500;
}
}
}
.search-trigger { .search-trigger {
margin-top: 8px; margin-top: 8px;
display: flex; display: flex;

4
zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/cp/AppEnfCpAutoReserveTest.java

@ -39,7 +39,7 @@ public class AppEnfCpAutoReserveTest {
// forceMatch=true: 跳过日期校验 // forceMatch=true: 跳过日期校验
// updatePlan=false: 不更新计划状态 // updatePlan=false: 不更新计划状态
// insertReserve=false: 不插入预约记录 // insertReserve=false: 不插入预约记录
Map<String, List<EfcodeCpReserve>> result = cpPlanService.autoMatchReserveV2(true, false, false); Map<String, List<EfcodeCpReserve>> result = cpPlanService.autoMatchReserveV3(true, false, false);
System.out.println("匹配结果组数: " + result.size()); System.out.println("匹配结果组数: " + result.size());
for (Map.Entry<String, List<EfcodeCpReserve>> entry : result.entrySet()) { for (Map.Entry<String, List<EfcodeCpReserve>> entry : result.entrySet()) {
@ -69,7 +69,7 @@ public class AppEnfCpAutoReserveTest {
// forceMatch=true: 跳过日期校验 // forceMatch=true: 跳过日期校验
// updatePlan=true: 更新计划状态(system_reserved=1, reserve_status=2) // updatePlan=true: 更新计划状态(system_reserved=1, reserve_status=2)
// insertReserve=true: 插入预约记录到数据库 // insertReserve=true: 插入预约记录到数据库
Map<String, List<EfcodeCpReserve>> result = cpPlanService.autoMatchReserveV2(true, true, true); Map<String, List<EfcodeCpReserve>> result = cpPlanService.autoMatchReserveV3(true, true, true);
System.out.println("匹配结果组数: " + result.size()); System.out.println("匹配结果组数: " + result.size());
int totalReserves = 0; int totalReserves = 0;

Loading…
Cancel
Save