From 3549bb5f5eaca51aa196948c0e7edb6bf833dd7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BA=84=E9=94=90=E6=B3=A2?= <10549902+zhuangruibo@user.noreply.gitee.com> Date: Mon, 25 May 2026 18:07:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=A7=E6=B3=95=E7=AB=AF-=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../013-计划任务表设计.sql | 51 +- .../controller/EfcodeCpLogController.java | 105 ++++ .../AppEnfCpReserveController.java | 37 ++ .../enforcementcode/domain/EfcodeCpLog.java | 71 +++ .../domain/bo/EfcodeCpLogBo.java | 72 +++ .../domain/vo/EfcodeCpLogVo.java | 86 ++++ .../domain/vo/EfcodeCpReserveVo.java | 20 + .../mapper/EfcodeCpLogMapper.java | 15 + .../mapper/EfcodeCpReserveMapper.java | 12 + .../quartz/job/CpPlanAutoMatchJob.java | 28 ++ .../quartz/job/ENFDemoTimeJob.java | 34 ++ .../service/IEfcodeCpLogService.java | 68 +++ .../service/IEfcodeCpPlanService.java | 6 + .../service/IEfcodeCpReserveService.java | 16 + .../service/impl/EfcodeCpLogServiceImpl.java | 138 ++++++ .../service/impl/EfcodeCpPlanServiceImpl.java | 11 + .../impl/EfcodeCpReserveServiceImpl.java | 74 ++- .../enforcementcode/EfcodeCpLogMapper.xml | 6 + .../enforcementcode/EfcodeCpReserveMapper.xml | 43 ++ .../src/api/enforcement/reserve.js | 16 + .../router/enforcement-app/enf-main-router.js | 9 + .../views/enforcement/my/enforcementMy.vue | 4 +- .../my/reserve/cp_reserve_list.vue | 102 ++++ .../my/reserve/cp_reserve_manual.vue | 457 ++++++++++++++++++ .../my/reserve/cp_reserve_system.vue | 442 +++++++++++++++++ .../rest/test/cp/AppEnfCpReserveTest.java | 220 +++++++++ 26 files changed, 2130 insertions(+), 13 deletions(-) create mode 100644 zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeCpLogController.java create mode 100644 zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/EfcodeCpLog.java create mode 100644 zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/bo/EfcodeCpLogBo.java create mode 100644 zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpLogVo.java create mode 100644 zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeCpLogMapper.java create mode 100644 zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/CpPlanAutoMatchJob.java create mode 100644 zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/ENFDemoTimeJob.java create mode 100644 zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpLogService.java create mode 100644 zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpLogServiceImpl.java create mode 100644 zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpLogMapper.xml create mode 100644 zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/reserve.js create mode 100644 zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_list.vue create mode 100644 zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_manual.vue create mode 100644 zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_system.vue create mode 100644 zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/cp/AppEnfCpReserveTest.java diff --git a/script/sql/zfjd-refactoring-v1/013-计划任务表设计.sql b/script/sql/zfjd-refactoring-v1/013-计划任务表设计.sql index eef8e9a5..a1b299a8 100644 --- a/script/sql/zfjd-refactoring-v1/013-计划任务表设计.sql +++ b/script/sql/zfjd-refactoring-v1/013-计划任务表设计.sql @@ -17,14 +17,14 @@ CREATE TABLE `efcode_cp_plan` `enforce_user_names` varchar(512) NOT NULL COMMENT '执法人员姓名(多个逗号分隔)', `enforce_user_ids` varchar(512) NOT NULL COMMENT '执法人员姓名(多个逗号分隔)', - `enforce_user_tels` varchar(512) NULL COMMENT '执法人员电话号码(多个逗号分隔)', + `enforce_user_tels` varchar(512) NULL COMMENT '执法人员电话号码(多个逗号分隔)', `enforce_user_codes` varchar(512) NOT NULL COMMENT '执法人员证件编号(多个逗号分隔)', `is_public` tinyint NOT NULL DEFAULT 1 COMMENT '是否公开:1=是,0=否', `is_union` tinyint NOT NULL DEFAULT 1 COMMENT '是否联合执法:1=是,0=否', `union_bureau_dept_names` varchar(500) DEFAULT NULL COMMENT '联合执法单位(多个逗号分隔)', - `reserve_status` tinyint NOT NULL DEFAULT 0 COMMENT '预约状态:0=草稿,1=待预约,2=预约中,3=预约完成', + `reserve_status` tinyint NOT NULL DEFAULT 0 COMMENT '预约状态:0=草稿,1=待预约(未发起联合),2=预约中,3=预约完成,4=重新预约中,5=待预约(还有位置可以加入)', `system_reserved` tinyint NOT NULL DEFAULT 0 COMMENT '是否已经经过系统推荐预约:1=是,0=否', `manual_reserved` tinyint NOT NULL DEFAULT 0 COMMENT '是否已经经过手动预约:1=是,0=否', `bureau_dept_id` varchar(50) NOT NULL COMMENT '执法单位ID', @@ -64,7 +64,7 @@ CREATE TABLE `efcode_cp_plan_users` `plan_id` varchar(50) NOT NULL COMMENT '计划ID', `user_id` varchar(50) NOT NULL COMMENT '用户ID', `user_name` varchar(100) NOT NULL COMMENT '用户名称', - `user_tel` varchar(50) NULL COMMENT '执法人员电话号码', + `user_tel` varchar(50) NULL COMMENT '执法人员电话号码', `create_by` varchar(64) DEFAULT '' COMMENT '创建者', `create_dept` varchar(64) DEFAULT NULL COMMENT '创建人部门', `update_by` varchar(64) DEFAULT '' COMMENT '更新者', @@ -81,12 +81,12 @@ CREATE TABLE `efcode_cp_reserve` `op_status` tinyint NOT NULL COMMENT '操作状态' DEFAULT 3 COMMENT '操作状态:1=同意,2=拒绝,3=待确认,4=超期取消', `op_order` int NOT NULL COMMENT '联合时用户的操作顺序', - `op_time` datetime NULL COMMENT '联合时用户的操作时间', + `op_time` datetime NULL COMMENT '联合时用户的操作时间', `op_message` varchar(500) NOT NULL COMMENT '联合时用户输入的操作消息', `op_set_date` datetime NOT NULL COMMENT '联合时用户选择的操作时间', `op_set_time` tinyint NOT NULL COMMENT '执行时段:1=上午,2=下午,3=其他', - `res_from` tinyint NOT NULL COMMENT '来自' COMMENT '来自:系统匹配=1,手动匹配=0', + `res_from` tinyint NOT NULL COMMENT '来自' COMMENT '来自:系统匹配=1,手动匹配=0', `create_by` varchar(64) DEFAULT '' COMMENT '创建者', `create_dept` varchar(64) DEFAULT NULL COMMENT '创建人部门', `update_by` varchar(64) DEFAULT '' COMMENT '更新者', @@ -117,7 +117,7 @@ CREATE TABLE `efcode_cp_notice` `enterprise_number` varchar(32) DEFAULT NULL COMMENT '企业统一社会信用代码', `contact_person` varchar(100) NOT NULL COMMENT '企业联系人', - `contact_phone` varchar(200) NULL COMMENT '企业联系电话', + `contact_phone` varchar(200) NULL COMMENT '企业联系电话', `enforce_content` varchar(1000) NOT NULL COMMENT '执法事项', `enforce_requirement` varchar(1000) NOT NULL COMMENT '执法要求', @@ -142,7 +142,7 @@ CREATE TABLE `efcode_cp_notice_users` `notice_id` varchar(50) NOT NULL COMMENT '通知ID', `user_id` varchar(50) NOT NULL COMMENT '用户ID', `user_name` varchar(100) NOT NULL COMMENT '用户名称', - `user_tel` varchar(50) NULL COMMENT '执法人员电话号码', + `user_tel` varchar(50) NULL COMMENT '执法人员电话号码', `create_by` varchar(64) DEFAULT '' COMMENT '创建者', `create_dept` varchar(64) DEFAULT NULL COMMENT '创建人部门', `update_by` varchar(64) DEFAULT '' COMMENT '更新者', @@ -179,13 +179,46 @@ CREATE TABLE `efcode_cp_setting` `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' ) comment '行政执法检查计划-设置表' row_format = DYNAMIC; +CREATE TABLE `efcode_cp_log` +( + `id` varchar(50) NOT NULL COMMENT '主键ID' PRIMARY KEY, + `record_id` varchar(50) NULL COMMENT '关联记录', + `table_name` varchar(50) NULL COMMENT '关联表', + `log_type` varchar(50) NULL COMMENT '日志类型', + `op_slog` varchar(2000) NULL COMMENT '短日志', + `op_llog` text NULL COMMENT '长日志', + `op_user_id` varchar(50) NOT NULL COMMENT '操作人ID', + `op_user_name` varchar(50) NOT NULL COMMENT '操作人姓名', + `remark` varchar(500) NULL COMMENT '备注', + `create_by` varchar(64) DEFAULT '' COMMENT '创建者', + `create_dept` varchar(64) DEFAULT NULL COMMENT '创建人部门', + `update_by` varchar(64) DEFAULT '' COMMENT '更新者', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' +) COMMENT '行政执法检查计划-日志表' ROW_FORMAT = DYNAMIC; + /*初始化数据*/ INSERT INTO `efcode_cp_setting` (`id`, `setting_name`, `setting_value`, `remark`, `create_by`, `create_dept`) VALUES ('CP_SETTING_SUBMIT_DEADLINE', '下阶段计划提交最晚时间', '26', '每月几号前需提交下阶段计划<=', '0', '0'), - ('CP_SETTING_AUTO_MATCH_START', '系统自动推荐匹配开始时间', '26', '系统自动推荐匹配的开始时间(号)>=', '0', - '0'), + ('CP_SETTING_AUTO_MATCH_START', '系统自动推荐匹配开始时间', '27', '系统自动推荐匹配的开始时间(号)=', '0', '0'), + ('CP_SETTING_RESERVE_CANCEL_DURATION', '预约自动取消时长', '7', '发起预约后,如果多长时间没有处理,则自动取消', + '0', '0'), ('CP_SETTING_MANUAL_MATCH_DAYS', '手工匹配距计划开始天数', '3', '手工匹配距离计划开始的天数>=', '0', '0'), ('CP_MAX_UNION_UNIT', '单次联合单位最大数量', '3', '单次联合单位最大数量<=3', '0', '0'), ('CP_MAX_INNER_UNIT_AC_PERSON_NUM', '单位内部单次计划最多参与人数', '3', '单位内部单次计划最多参与人数<=3', '0', '0'); + +/*创建计划任务*/ +INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, + create_time, remark) +VALUES ('计划自动匹配预约', + 'DEFAULT', + 'cpPlanAutoMatchJob.execute()', + '0 0 2 * * ?', + '3', + '1', + '0', + 'admin', + NOW(), + '每天凌晨2点扫描待预约计划并自动匹配生成预约记录'); diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeCpLogController.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeCpLogController.java new file mode 100644 index 00000000..74e78f3c --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeCpLogController.java @@ -0,0 +1,105 @@ +package com.zdxt.enforcementcode.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import com.zdxt.enforcementcode.domain.vo.EfcodeCpLogVo; +import com.zdxt.enforcementcode.domain.bo.EfcodeCpLogBo; +import com.zdxt.enforcementcode.service.IEfcodeCpLogService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 行政执法检查计划-日志 + * + * @author Lion Li + * @date 2026-05-25 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/enforcementcode/cpLog") +public class EfcodeCpLogController extends BaseController { + + private final IEfcodeCpLogService efcodeCpLogService; + + /** + * 查询行政执法检查计划-日志列表 + */ + @SaCheckPermission("enforcementcode:cpLog:list") + @GetMapping("/list") + public TableDataInfo list(EfcodeCpLogBo bo, PageQuery pageQuery) { + return efcodeCpLogService.queryPageList(bo, pageQuery); + } + + /** + * 导出行政执法检查计划-日志列表 + */ + @SaCheckPermission("enforcementcode:cpLog:export") + @Log(title = "行政执法检查计划-日志", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(EfcodeCpLogBo bo, HttpServletResponse response) { + List list = efcodeCpLogService.queryList(bo); + ExcelUtil.exportExcel(list, "行政执法检查计划-日志", EfcodeCpLogVo.class, response); + } + + /** + * 获取行政执法检查计划-日志详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("enforcementcode:cpLog:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable String id) { + return R.ok(efcodeCpLogService.queryById(id)); + } + + /** + * 新增行政执法检查计划-日志 + */ + @SaCheckPermission("enforcementcode:cpLog:add") + @Log(title = "行政执法检查计划-日志", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody EfcodeCpLogBo bo) { + return toAjax(efcodeCpLogService.insertByBo(bo)); + } + + /** + * 修改行政执法检查计划-日志 + */ + @SaCheckPermission("enforcementcode:cpLog:edit") + @Log(title = "行政执法检查计划-日志", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody EfcodeCpLogBo bo) { + return toAjax(efcodeCpLogService.updateByBo(bo)); + } + + /** + * 删除行政执法检查计划-日志 + * + * @param ids 主键串 + */ + @SaCheckPermission("enforcementcode:cpLog:remove") + @Log(title = "行政执法检查计划-日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable String[] ids) { + return toAjax(efcodeCpLogService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfCpReserveController.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfCpReserveController.java index e27418a9..50822b09 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfCpReserveController.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfCpReserveController.java @@ -1,7 +1,14 @@ package com.zdxt.enforcementcode.controller.app.enforcement; import com.zdxt.enforcementcode.controller.web.supervision.EfcodeCpReserveController; +import com.zdxt.enforcementcode.domain.bo.EfcodeCpReserveBo; +import com.zdxt.enforcementcode.domain.vo.EfcodeCpReserveVo; import com.zdxt.enforcementcode.service.IEfcodeCpReserveService; +import org.dromara.common.core.domain.R; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -16,7 +23,37 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/app-enf/cpReserve") public class AppEnfCpReserveController extends EfcodeCpReserveController { + @Autowired + private IEfcodeCpReserveService cpReserveService; + public AppEnfCpReserveController(IEfcodeCpReserveService efcodeCpReserveService) { super(efcodeCpReserveService); + this.cpReserveService = efcodeCpReserveService; + } + + /** + * 查询当前用户相关的预约列表(仅查询当前用户计划所关联的预约记录) + */ + @Override + @GetMapping("/list") + public TableDataInfo list(EfcodeCpReserveBo bo, PageQuery pageQuery) { + bo.setCreateBy(LoginHelper.getUserId()); + return cpReserveService.queryPageList(bo, pageQuery); + } + + /** + * 同意预约 + */ + @PutMapping("/approve/{id}") + public R approve(@PathVariable String id) { + return cpReserveService.approveReserve(id); + } + + /** + * 拒绝预约 + */ + @PutMapping("/reject/{id}") + public R reject(@PathVariable String id) { + return cpReserveService.rejectReserve(id); } } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/EfcodeCpLog.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/EfcodeCpLog.java new file mode 100644 index 00000000..608f64b5 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/EfcodeCpLog.java @@ -0,0 +1,71 @@ +package com.zdxt.enforcementcode.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 行政执法检查计划-日志对象 efcode_cp_log + * + * @author Lion Li + * @date 2026-05-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("efcode_cp_log") +public class EfcodeCpLog extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id") + private String id; + + /** + * 关联记录 + */ + private String recordId; + + /** + * 关联表 + */ + private String tableName; + + /** + * 日志类型 + */ + private String logType; + + /** + * 短日志 + */ + private String opSlog; + + /** + * 长日志 + */ + private String opLlog; + + /** + * 操作人ID + */ + private String opUserId; + + /** + * 操作人姓名 + */ + private String opUserName; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/bo/EfcodeCpLogBo.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/bo/EfcodeCpLogBo.java new file mode 100644 index 00000000..39f2039f --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/bo/EfcodeCpLogBo.java @@ -0,0 +1,72 @@ +package com.zdxt.enforcementcode.domain.bo; + +import com.zdxt.enforcementcode.domain.EfcodeCpLog; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 行政执法检查计划-日志业务对象 efcode_cp_log + * + * @author Lion Li + * @date 2026-05-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = EfcodeCpLog.class, reverseConvertGenerate = false) +public class EfcodeCpLogBo extends BaseEntity { + + /** + * 主键ID + */ + @NotBlank(message = "主键ID不能为空", groups = { EditGroup.class }) + private String id; + + /** + * 关联记录 + */ + private String recordId; + + /** + * 关联表 + */ + private String tableName; + + /** + * 日志类型 + */ + private String logType; + + /** + * 短日志 + */ + private String opSlog; + + /** + * 长日志 + */ + private String opLlog; + + /** + * 操作人ID + */ + @NotBlank(message = "操作人ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private String opUserId; + + /** + * 操作人姓名 + */ + @NotBlank(message = "操作人姓名不能为空", groups = { AddGroup.class, EditGroup.class }) + private String opUserName; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpLogVo.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpLogVo.java new file mode 100644 index 00000000..3b1d30d9 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpLogVo.java @@ -0,0 +1,86 @@ +package com.zdxt.enforcementcode.domain.vo; + +import com.zdxt.enforcementcode.domain.EfcodeCpLog; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 行政执法检查计划-日志视图对象 efcode_cp_log + * + * @author Lion Li + * @date 2026-05-25 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = EfcodeCpLog.class) +public class EfcodeCpLogVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private String id; + + /** + * 关联记录 + */ + @ExcelProperty(value = "关联记录") + private String recordId; + + /** + * 关联表 + */ + @ExcelProperty(value = "关联表") + private String tableName; + + /** + * 日志类型 + */ + @ExcelProperty(value = "日志类型") + private String logType; + + /** + * 短日志 + */ + @ExcelProperty(value = "短日志") + private String opSlog; + + /** + * 长日志 + */ + @ExcelProperty(value = "长日志") + private String opLlog; + + /** + * 操作人ID + */ + @ExcelProperty(value = "操作人ID") + private String opUserId; + + /** + * 操作人姓名 + */ + @ExcelProperty(value = "操作人姓名") + private String opUserName; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpReserveVo.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpReserveVo.java index 057ce7a5..9095a4b4 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpReserveVo.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpReserveVo.java @@ -96,5 +96,25 @@ public class EfcodeCpReserveVo implements Serializable { @ExcelProperty(value = "来自:系统匹配=1,手动匹配=0") private Long resFrom; + // ===== 计划关联字段(非数据库映射,由服务层填充) ===== + + /** 计划日期 */ + private Date planDate; + + /** 执行时段:1=上午,2=下午,3=其他 */ + private Long planTime; + + /** 企业名称 */ + private String enterpriseName; + + /** 执法事项 */ + private String enforceContent; + + /** 执法单位名称 */ + private String bureauDeptName; + + /** 执法人员姓名 */ + private String enforceUserNames; + } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeCpLogMapper.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeCpLogMapper.java new file mode 100644 index 00000000..26e3a030 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeCpLogMapper.java @@ -0,0 +1,15 @@ +package com.zdxt.enforcementcode.mapper; + +import com.zdxt.enforcementcode.domain.EfcodeCpLog; +import com.zdxt.enforcementcode.domain.vo.EfcodeCpLogVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 行政执法检查计划-日志Mapper接口 + * + * @author Lion Li + * @date 2026-05-25 + */ +public interface EfcodeCpLogMapper extends BaseMapperPlus { + +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeCpReserveMapper.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeCpReserveMapper.java index fd76f785..cd4830db 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeCpReserveMapper.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeCpReserveMapper.java @@ -1,7 +1,9 @@ package com.zdxt.enforcementcode.mapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.zdxt.enforcementcode.domain.EfcodeCpReserve; import com.zdxt.enforcementcode.domain.vo.EfcodeCpReserveVo; +import org.apache.ibatis.annotations.Param; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; /** @@ -12,4 +14,14 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; */ public interface EfcodeCpReserveMapper extends BaseMapperPlus { + /** + * 分页查询预约处理列表(手动预约 / 系统匹配),关联计划表获取计划详情 + */ + Page selectReservePageList( + @Param("page") Page page, + @Param("resFrom") Long resFrom, + @Param("opStatus") Long opStatus, + @Param("currentUserId") Long currentUserId + ); + } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/CpPlanAutoMatchJob.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/CpPlanAutoMatchJob.java new file mode 100644 index 00000000..c2bc3f99 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/CpPlanAutoMatchJob.java @@ -0,0 +1,28 @@ +package com.zdxt.enforcementcode.quartz.job; + +import com.zdxt.enforcementcode.service.IEfcodeCpPlanService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 计划自动匹配预约 - 定时任务 + *

定期扫描待预约状态的计划,按规则自动匹配并生成预约记录

+ * + * @author zrb + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class CpPlanAutoMatchJob { + + private final IEfcodeCpPlanService cpPlanService; + + /** + * 任务执行入口(public,供 JobInvokeUtil 通过反射调用) + */ + public void execute() { + log.info("[CpPlanAutoMatchJob] 定时任务触发:计划自动匹配预约"); + cpPlanService.autoMatchReserve(); + } +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/ENFDemoTimeJob.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/ENFDemoTimeJob.java new file mode 100644 index 00000000..26b37df4 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/ENFDemoTimeJob.java @@ -0,0 +1,34 @@ +package com.zdxt.enforcementcode.quartz.job; + +import lombok.extern.slf4j.Slf4j; +import org.quartz.JobExecutionContext; +import org.springframework.scheduling.quartz.QuartzJobBean; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 演示定时任务 - 每秒打印当前时间 + * + * @author ruoyi + */ +@Slf4j +@Component +public class ENFDemoTimeJob extends QuartzJobBean { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Override + protected void executeInternal(JobExecutionContext context) { + execute(); + } + + /** + * 任务执行入口(public,供 JobInvokeUtil 通过反射调用) + */ + public void execute() { + log.info("[Quartz Demo] 当前时间: {}", LocalDateTime.now().format(FORMATTER)); + } + +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpLogService.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpLogService.java new file mode 100644 index 00000000..eaac2b49 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpLogService.java @@ -0,0 +1,68 @@ +package com.zdxt.enforcementcode.service; + +import com.zdxt.enforcementcode.domain.vo.EfcodeCpLogVo; +import com.zdxt.enforcementcode.domain.bo.EfcodeCpLogBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 行政执法检查计划-日志Service接口 + * + * @author Lion Li + * @date 2026-05-25 + */ +public interface IEfcodeCpLogService { + + /** + * 查询行政执法检查计划-日志 + * + * @param id 主键 + * @return 行政执法检查计划-日志 + */ + EfcodeCpLogVo queryById(String id); + + /** + * 分页查询行政执法检查计划-日志列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 行政执法检查计划-日志分页列表 + */ + TableDataInfo queryPageList(EfcodeCpLogBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的行政执法检查计划-日志列表 + * + * @param bo 查询条件 + * @return 行政执法检查计划-日志列表 + */ + List queryList(EfcodeCpLogBo bo); + + /** + * 新增行政执法检查计划-日志 + * + * @param bo 行政执法检查计划-日志 + * @return 是否新增成功 + */ + Boolean insertByBo(EfcodeCpLogBo bo); + + /** + * 修改行政执法检查计划-日志 + * + * @param bo 行政执法检查计划-日志 + * @return 是否修改成功 + */ + Boolean updateByBo(EfcodeCpLogBo bo); + + /** + * 校验并批量删除行政执法检查计划-日志信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpPlanService.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpPlanService.java index f9efa5f7..7aae9304 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpPlanService.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpPlanService.java @@ -75,4 +75,10 @@ public interface IEfcodeCpPlanService { * @return 是否删除成功 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 计划自动匹配预约(定时任务调用) + *

扫描待预约状态的计划,按规则自动匹配并生成预约记录

+ */ + void autoMatchReserve(); } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpReserveService.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpReserveService.java index ddc982d7..fb8fd872 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpReserveService.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpReserveService.java @@ -84,4 +84,20 @@ public interface IEfcodeCpReserveService { * @return 操作结果 */ R doReserve(String targetPlanId, String opMessage); + + /** + * 同意预约 + * + * @param reserveId 预约记录ID + * @return 操作结果 + */ + R approveReserve(String reserveId); + + /** + * 拒绝预约 + * + * @param reserveId 预约记录ID + * @return 操作结果 + */ + R rejectReserve(String reserveId); } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpLogServiceImpl.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpLogServiceImpl.java new file mode 100644 index 00000000..3dd03c08 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpLogServiceImpl.java @@ -0,0 +1,138 @@ +package com.zdxt.enforcementcode.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import com.zdxt.enforcementcode.domain.bo.EfcodeCpLogBo; +import com.zdxt.enforcementcode.domain.vo.EfcodeCpLogVo; +import com.zdxt.enforcementcode.domain.EfcodeCpLog; +import com.zdxt.enforcementcode.mapper.EfcodeCpLogMapper; +import com.zdxt.enforcementcode.service.IEfcodeCpLogService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 行政执法检查计划-日志Service业务层处理 + * + * @author Lion Li + * @date 2026-05-25 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class EfcodeCpLogServiceImpl implements IEfcodeCpLogService { + + private final EfcodeCpLogMapper baseMapper; + + /** + * 查询行政执法检查计划-日志 + * + * @param id 主键 + * @return 行政执法检查计划-日志 + */ + @Override + public EfcodeCpLogVo queryById(String id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询行政执法检查计划-日志列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 行政执法检查计划-日志分页列表 + */ + @Override + public TableDataInfo queryPageList(EfcodeCpLogBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的行政执法检查计划-日志列表 + * + * @param bo 查询条件 + * @return 行政执法检查计划-日志列表 + */ + @Override + public List queryList(EfcodeCpLogBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(EfcodeCpLogBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(EfcodeCpLog::getId); + lqw.eq(StringUtils.isNotBlank(bo.getRecordId()), EfcodeCpLog::getRecordId, bo.getRecordId()); + lqw.like(StringUtils.isNotBlank(bo.getTableName()), EfcodeCpLog::getTableName, bo.getTableName()); + lqw.eq(StringUtils.isNotBlank(bo.getLogType()), EfcodeCpLog::getLogType, bo.getLogType()); + lqw.eq(StringUtils.isNotBlank(bo.getOpSlog()), EfcodeCpLog::getOpSlog, bo.getOpSlog()); + lqw.eq(StringUtils.isNotBlank(bo.getOpLlog()), EfcodeCpLog::getOpLlog, bo.getOpLlog()); + lqw.eq(StringUtils.isNotBlank(bo.getOpUserId()), EfcodeCpLog::getOpUserId, bo.getOpUserId()); + lqw.like(StringUtils.isNotBlank(bo.getOpUserName()), EfcodeCpLog::getOpUserName, bo.getOpUserName()); + return lqw; + } + + /** + * 新增行政执法检查计划-日志 + * + * @param bo 行政执法检查计划-日志 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(EfcodeCpLogBo bo) { + EfcodeCpLog add = MapstructUtils.convert(bo, EfcodeCpLog.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改行政执法检查计划-日志 + * + * @param bo 行政执法检查计划-日志 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(EfcodeCpLogBo bo) { + EfcodeCpLog update = MapstructUtils.convert(bo, EfcodeCpLog.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(EfcodeCpLog entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除行政执法检查计划-日志信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java index bd4be5c4..054a418d 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java @@ -344,4 +344,15 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService { } return baseMapper.deleteByIds(ids) > 0; } + + /** + * 计划自动匹配预约(定时任务调用) + *

扫描待预约状态的计划,按规则自动匹配并生成预约记录

+ */ + @Override + public void autoMatchReserve() { + log.info("[CpPlan] 开始执行计划自动匹配预约..."); + // TODO 后续实现:扫描待预约计划 → 按企业+日期+时段匹配 → 自动生成预约记录 + log.info("[CpPlan] 计划自动匹配预约执行完毕"); + } } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpReserveServiceImpl.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpReserveServiceImpl.java index 6796eb3c..1c05ea7c 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpReserveServiceImpl.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpReserveServiceImpl.java @@ -60,8 +60,12 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { */ @Override public TableDataInfo queryPageList(EfcodeCpReserveBo bo, PageQuery pageQuery) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + Page result = baseMapper.selectReservePageList( + pageQuery.build(), + bo.getResFrom(), + bo.getOpStatus(), + bo.getCreateBy() + ); return TableDataInfo.build(result); } @@ -80,7 +84,7 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { private LambdaQueryWrapper buildQueryWrapper(EfcodeCpReserveBo bo) { Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.orderByAsc(EfcodeCpReserve::getId); + lqw.orderByDesc(EfcodeCpReserve::getReserveTime); lqw.eq(StringUtils.isNotBlank(bo.getPlanId()), EfcodeCpReserve::getPlanId, bo.getPlanId()); lqw.eq(bo.getReserveTime() != null, EfcodeCpReserve::getReserveTime, bo.getReserveTime()); lqw.eq(bo.getOpStatus() != null, EfcodeCpReserve::getOpStatus, bo.getOpStatus()); @@ -90,6 +94,21 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { lqw.eq(bo.getOpSetDate() != null, EfcodeCpReserve::getOpSetDate, bo.getOpSetDate()); lqw.eq(bo.getOpSetTime() != null, EfcodeCpReserve::getOpSetTime, bo.getOpSetTime()); lqw.eq(bo.getResFrom() != null, EfcodeCpReserve::getResFrom, bo.getResFrom()); + // 如果指定了createBy,则筛选当前用户计划关联的预约记录(planId IN 当前用户的计划) + if (bo.getCreateBy() != null) { + List myPlanIds = cpPlanMapper.selectList( + Wrappers.lambdaQuery() + .eq(EfcodeCpPlan::getCreateBy, bo.getCreateBy()) + .eq(EfcodeCpPlan::getIsDelete, 0L) + .select(EfcodeCpPlan::getId) + ).stream().map(EfcodeCpPlan::getId).collect(Collectors.toList()); + if (myPlanIds.isEmpty()) { + // 当前用户无计划,返回空结果 + lqw.eq(EfcodeCpReserve::getId, "__IMPOSSIBLE__"); + } else { + lqw.in(EfcodeCpReserve::getPlanId, myPlanIds); + } + } return lqw; } @@ -291,4 +310,53 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { record.setResFrom(resFrom); baseMapper.insert(record); } + + /** + * 同意预约 + */ + @Override + public R approveReserve(String reserveId) { + EfcodeCpReserve reserve = baseMapper.selectById(reserveId); + if (reserve == null) { + return R.fail("预约记录不存在"); + } + if (!Long.valueOf(3L).equals(reserve.getOpStatus())) { + return R.fail("该预约记录已被处理"); + } + reserve.setOpStatus(1L); // 同意 + reserve.setOpTime(new Date()); + baseMapper.updateById(reserve); + afterOperate(reserve, "approve"); + return R.ok(); + } + + /** + * 拒绝预约 + */ + @Override + public R rejectReserve(String reserveId) { + EfcodeCpReserve reserve = baseMapper.selectById(reserveId); + if (reserve == null) { + return R.fail("预约记录不存在"); + } + if (!Long.valueOf(3L).equals(reserve.getOpStatus())) { + return R.fail("该预约记录已被处理"); + } + reserve.setOpStatus(2L); // 拒绝 + reserve.setOpTime(new Date()); + baseMapper.updateById(reserve); + afterOperate(reserve, "reject"); + return R.ok(); + } + + /** + * 同意/拒绝操作后置处理 + * + * @param reserve 预约记录 + * @param action 操作类型: "approve" 或 "reject" + */ + private void afterOperate(EfcodeCpReserve reserve, String action) { + // TODO: 可在此处扩展后置逻辑,如通知、状态同步等 + log.info("预约记录[{}]执行{}操作后置处理, planGroupId={}", reserve.getId(), action, reserve.getPlanGroupId()); + } } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpLogMapper.xml b/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpLogMapper.xml new file mode 100644 index 00000000..55b52c36 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpLogMapper.xml @@ -0,0 +1,6 @@ + + + + diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpReserveMapper.xml b/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpReserveMapper.xml index 13b9c2ed..ba6e8911 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpReserveMapper.xml +++ b/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpReserveMapper.xml @@ -3,4 +3,47 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + + + + diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/reserve.js b/zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/reserve.js new file mode 100644 index 00000000..81d1bbcd --- /dev/null +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/reserve.js @@ -0,0 +1,16 @@ +import { _get, _post, _put } from "@/http/index"; + +// region 预约处理接口 + +const reserveBaseUrl = "/app-enf/cpReserve"; + +// 预约列表(分页,支持 resFrom 过滤:0=手动预约,1=系统匹配) +export const getReserveList = (params, success, error) => _get(reserveBaseUrl + "/list", params, success, error); + +// 预约处理:同意 +export const approveReserve = (id, success, error) => _put(reserveBaseUrl + "/approve/" + id, {}, success, error); + +// 预约处理:拒绝 +export const rejectReserve = (id, success, error) => _put(reserveBaseUrl + "/reject/" + id, {}, success, error); + +// endregion diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/router/enforcement-app/enf-main-router.js b/zdxt-web-client/zdxt-efcode-enforcement-app/src/router/enforcement-app/enf-main-router.js index 7a7da10f..e5cd1181 100644 --- a/zdxt-web-client/zdxt-efcode-enforcement-app/src/router/enforcement-app/enf-main-router.js +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/router/enforcement-app/enf-main-router.js @@ -90,6 +90,15 @@ const routes = [ isKeepAlive: false, }, }, + // 执法端-预约处理列表 + { + path: "/enforcement/reserve", + name: "cpReserveList", + component: () => import("@/views/enforcement/my/reserve/cp_reserve_list.vue"), + meta: { + isKeepAlive: false, + }, + }, // 执法端-登记页面 { path: "/enforcement/enforcementRegister", diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/enforcementMy.vue b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/enforcementMy.vue index cc665352..4e5b58b1 100644 --- a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/enforcementMy.vue +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/enforcementMy.vue @@ -120,13 +120,15 @@ const onMenuClick = (item) => { switch (item.key) { case 'notice': case 'task': - case 'appointment': // 跳至消息中心待办 tab,并带类型过滤参数 router.push({ path: '/enforcement/message', query: { tab: 'todo', type: item.key }, }); break; + case 'appointment': + router.push({ path: '/enforcement/reserve' }); + break; case 'plan': router.push({ path: '/enforcement/plan' }); break; diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_list.vue b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_list.vue new file mode 100644 index 00000000..2d232ed2 --- /dev/null +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_list.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_manual.vue b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_manual.vue new file mode 100644 index 00000000..556e717b --- /dev/null +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_manual.vue @@ -0,0 +1,457 @@ + + + + + diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_system.vue b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_system.vue new file mode 100644 index 00000000..dd933b99 --- /dev/null +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_system.vue @@ -0,0 +1,442 @@ + + + + + diff --git a/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/cp/AppEnfCpReserveTest.java b/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/cp/AppEnfCpReserveTest.java new file mode 100644 index 00000000..fa790c3a --- /dev/null +++ b/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/cp/AppEnfCpReserveTest.java @@ -0,0 +1,220 @@ +package com.zdxt.rest.test.cp; + +import cn.dev33.satoken.context.mock.SaTokenContextMockUtil; +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.zdxt.enforcementcode.domain.EfcodeCpPlan; +import com.zdxt.enforcementcode.domain.EfcodeCpReserve; +import com.zdxt.enforcementcode.mapper.EfcodeCpPlanMapper; +import com.zdxt.enforcementcode.mapper.EfcodeCpReserveMapper; +import org.dromara.ZdxtAdminApplication; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 预约记录批量生成测试 + *

+ * 基于已创建的计划数据,为多个用户交替创建 efcode_cp_reserve 预约记录。 + * 模拟场景:用户A的计划被用户B预约,用户B的计划被用户C预约...循环交替。 + * 预约状态交替:待确认(3)、已同意(1)、已拒绝(2) + * 预约来源交替:手动预约(0)、系统匹配(1) + *

+ */ +@SpringBootTest(classes = ZdxtAdminApplication.class) +@AutoConfigureMockMvc +@ActiveProfiles({"dev", "dev-cust-zrb"}) +@DisplayName("AppEnfCpReserve 批量生成预约记录测试") +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@Tag("dev") +public class AppEnfCpReserveTest { + + @Autowired + private EfcodeCpPlanMapper cpPlanMapper; + + @Autowired + private EfcodeCpReserveMapper cpReserveMapper; + + /** + * 测试账号对应的 userId(需从数据库匹配) + * 这里通过查询 plan 表的 create_by 字段获取对应用户ID + */ + private static final String[] TEST_ACCOUNTS = {"liuqianlin", "baining", "caizifan", "chenchong4"}; + + /** 每个用户最多取多少条计划来生成预约 */ + private static final int MAX_PLANS_PER_USER = 50; + + /** 预约留言模板 */ + private static final String[] MESSAGES = { + "希望联合执法,请确认时间", + "我单位有相关检查需求,申请联合", + "建议合并检查,减轻企业负担", + "时间安排一致,申请联合执法", + "", // 部分无留言 + "请尽快确认预约", + "", + "我方已做好准备,等待确认" + }; + + @BeforeEach + public void setUp() { + SaTokenContextMockUtil.setMockContext(); + MockHttpServletRequest mockRequest = new MockHttpServletRequest(); + mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest)); + } + + @AfterEach + public void tearDown() { + try { + StpUtil.logout(); + } catch (Exception ignored) { + } + RequestContextHolder.resetRequestAttributes(); + SaTokenContextMockUtil.clearContext(); + } + + @DisplayName("基于已有计划批量生成交替预约记录") + @Test + @Order(1) + public void testBatchCreateReserves() { + // 1. 收集每个用户的计划(通过 enforce_user_names LIKE 账号中文名识别) + // 实际通过 create_by 字段分组获取不同用户的计划 + Map> userPlansMap = loadUserPlansMap(); + + List userIds = new ArrayList<>(userPlansMap.keySet()); + Assertions.assertTrue(userIds.size() >= 2, "至少需要2个用户的计划数据才能交叉预约"); + + System.out.println("========== 检测到 " + userIds.size() + " 个用户的计划数据 =========="); + for (Long uid : userIds) { + System.out.println(" userId=" + uid + ", 计划数=" + userPlansMap.get(uid).size()); + } + + Random random = new Random(42); // 固定种子,可重复 + int totalCreated = 0; + int reserveIndex = 0; + + // 2. 交替为每个用户的计划创建来自其他用户的预约 + for (int ownerIdx = 0; ownerIdx < userIds.size(); ownerIdx++) { + Long ownerUserId = userIds.get(ownerIdx); + List ownerPlans = userPlansMap.get(ownerUserId); + + // 限制数量 + int planCount = Math.min(ownerPlans.size(), MAX_PLANS_PER_USER); + + for (int planIdx = 0; planIdx < planCount; planIdx++) { + EfcodeCpPlan targetPlan = ownerPlans.get(planIdx); + + // 选择预约发起者:循环选取其他用户 + int reserverIdx = (ownerIdx + 1 + planIdx) % userIds.size(); + if (reserverIdx == ownerIdx) { + reserverIdx = (reserverIdx + 1) % userIds.size(); + } + Long reserverUserId = userIds.get(reserverIdx); + List reserverPlans = userPlansMap.get(reserverUserId); + + // 找预约者匹配的计划(同日期+同时段+同企业),如果没有就用预约者的任意一条计划 + EfcodeCpPlan reserverPlan = findMatchingPlan(reserverPlans, targetPlan); + if (reserverPlan == null && !reserverPlans.isEmpty()) { + reserverPlan = reserverPlans.get(planIdx % reserverPlans.size()); + } + if (reserverPlan == null) continue; + + // 3. 确定 planGroupId + String planGroupId = targetPlan.getId(); + + // 4. 交替 opStatus: 3(待确认), 1(已同意), 2(已拒绝), 3, 1, 2... + long opStatus = getAlternatingStatus(reserveIndex); + // 5. 交替 resFrom: 0(手动), 1(系统) + long resFrom = reserveIndex % 2; + // 6. 留言 + String message = MESSAGES[reserveIndex % MESSAGES.length]; + + // 插入目标计划方的记录(计划拥有者) + insertReserve(targetPlan.getId(), planGroupId, "", targetPlan.getPlanDate(), + targetPlan.getPlanTime(), resFrom, opStatus); + + // 插入预约发起方的记录 + insertReserve(reserverPlan.getId(), planGroupId, message, targetPlan.getPlanDate(), + targetPlan.getPlanTime(), resFrom, 3L); // 发起方始终待确认 + + totalCreated += 2; + reserveIndex++; + } + + System.out.println("[userId=" + ownerUserId + "] 已为其 " + planCount + " 条计划生成预约记录"); + } + + System.out.println("========== 预约记录生成完成 =========="); + System.out.println("总计插入: " + totalCreated + " 条预约记录"); + Assertions.assertTrue(totalCreated > 0, "应至少生成1条预约记录"); + } + + /** + * 从数据库加载各用户的计划,按 create_by 分组 + * 只取未删除、reserve_status=1(待预约)的计划 + */ + private Map> loadUserPlansMap() { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(EfcodeCpPlan::getIsDelete, 0L); + lqw.eq(EfcodeCpPlan::getReserveStatus, 1L); // 待预约状态 + lqw.like(EfcodeCpPlan::getEnforceContent, "批量测试执法事项"); // 只取测试数据 + lqw.orderByAsc(EfcodeCpPlan::getPlanDate); + List allPlans = cpPlanMapper.selectList(lqw); + + return allPlans.stream() + .filter(p -> p.getCreateBy() != null) + .collect(Collectors.groupingBy(EfcodeCpPlan::getCreateBy)); + } + + /** + * 在预约者的计划列表中查找与目标计划匹配的计划(同日期+同时段+同企业) + */ + private EfcodeCpPlan findMatchingPlan(List plans, EfcodeCpPlan target) { + if (plans == null || plans.isEmpty()) return null; + for (EfcodeCpPlan p : plans) { + if (p.getPlanDate() != null && p.getPlanDate().equals(target.getPlanDate()) + && Objects.equals(p.getPlanTime(), target.getPlanTime()) + && Objects.equals(p.getEnterpriseId(), target.getEnterpriseId())) { + return p; + } + } + return null; + } + + /** + * 交替状态: 3, 1, 2, 3, 1, 2... + */ + private long getAlternatingStatus(int index) { + int mod = index % 3; + return mod == 0 ? 3L : (mod == 1 ? 1L : 2L); + } + + /** + * 插入一条预约记录 + */ + private void insertReserve(String planId, String planGroupId, String opMessage, + Date opSetDate, Long opSetTime, Long resFrom, Long opStatus) { + EfcodeCpReserve record = new EfcodeCpReserve(); + record.setPlanId(planId); + record.setPlanGroupId(planGroupId); + record.setReserveTime(new Date()); + record.setOpStatus(opStatus); + record.setOpOrder(0L); + record.setOpMessage(opMessage); + record.setOpSetDate(opSetDate); + record.setOpSetTime(opSetTime); + record.setResFrom(resFrom); + cpReserveMapper.insert(record); + } +}