package com.ruoyi.task.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.ArrayList; import java.util.List; /** * 任务模块的 MVC 配置:把 {@link TaskAvailabilityInterceptor} 挂到任务模块自己的端点前缀上。 * *

为什么是 2 个前缀(而不是逐个枚举 42 个端点)

* 任务模块的端点**全部**由本模块的 2 个 Controller 提供,且它们的 URL 前缀 * 与其他模块**没有任何重叠**: * * ⚠️ 特别注意 {@code /smartor/serviceSubtask/**} 不会误伤满意度模块的 * {@code /smartor/serviceSubtaskDetail/**}:Spring 的路径匹配里 * {@code serviceSubtask} 与 {@code serviceSubtaskDetail} 是两个不同的段。 *

* 因此这里用前缀即可精确覆盖,无需像满意度模块那样逐个列 17 个精确路径。 * 唯一需要额外处理的是"电话模块保留原 URL 后落在这个前缀里的 6 条端点", * 见 {@link #excludedPhonePaths()}。 * 若将来又有其它模块往这两个前缀下加端点,同样需要加到排除清单里。 */ @Configuration public class TaskWebConfig implements WebMvcConfigurer { /** * 任务(原 {@code ServiceTaskController}) */ private static final String SERVICETASK_PATTERN = "/smartor/servicetask/**"; /** * 子任务(原 {@code ServiceSubtaskController}) */ private static final String SERVICESUBTASK_PATTERN = "/smartor/serviceSubtask/**"; /** * 挂在 {@code /smartor/serviceSubtask/**} 下、但归电话模块(ruoyi-phone)的 6 条端点。 *

* 电话模块化时刻意保留原 URL(外部电话平台的回调地址不能改),于是这几条 * 落在任务模块的前缀里。它们必须从"任务开关"的拦截范围里排除, * 否则会出现"关掉 task.enabled 顺手把电话回调也关了"——外部平台正在通话, * 回调被拦会直接把随访打断。它们由 {@code phone.enabled} 管。 *

* ⚠️ 这里是字符串字面量而不是引用 {@code PhoneWebConfig} 的常量: * 依赖方向只能是 {@code ruoyi-phone -> ruoyi-task},反过来会形成 Maven 循环依赖。 * 改电话端点路径时两边都要改;{@code TaskSwitchCheck} 里有断言盯着这 6 条。 */ private static final String[] PHONE_OWNED_SUBTASK_PATHS = new String[]{ "/smartor/serviceSubtask/phoneCallBack", "/smartor/serviceSubtask/phoneCallBackYQ", "/smartor/serviceSubtask/taskPull", "/smartor/serviceSubtask/saveQuestionAnswerPhone", "/smartor/serviceSubtask/recordAcceptshanghai", "/smartor/serviceSubtask/recordAccept", }; @Autowired private TaskAvailabilityInterceptor taskAvailabilityInterceptor; /** * 供测试/非 Spring 环境直接构造 */ public TaskWebConfig() { } public TaskWebConfig(TaskAvailabilityInterceptor interceptor) { this.taskAvailabilityInterceptor = interceptor; } /** * 本模块需要"关闭即明确报错"的 URL 前缀(供校验脚本/单元测试断言) */ public static List guardedPathPatterns() { List patterns = new ArrayList<>(); patterns.add(SERVICETASK_PATTERN); patterns.add(SERVICESUBTASK_PATTERN); return patterns; } /** * 从任务开关拦截范围里排除的路径(电话模块自己的 6 条,供校验脚本/单元测试断言) */ public static List excludedPhonePaths() { List paths = new ArrayList<>(); for (String p : PHONE_OWNED_SUBTASK_PATHS) { paths.add(p); } return paths; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(taskAvailabilityInterceptor) .addPathPatterns(guardedPathPatterns()) .excludePathPatterns(PHONE_OWNED_SUBTASK_PATHS) // 拦截器本身很轻(只读一个 boolean),order 给个小值让它在业务拦截器之前执行 .order(-100); } }