Commit 9d76c35948fa1ebeb5690b6db6215e86e610a67d

Authored by 王彪总
1 parent 31d06eef

fix(config): 更新配置文件和修复分页计算问题

- 在.gitignore中添加.mcp.json文件忽略
- 更新application-dev.yml中的Redis和数据库连接配置,并禁用Eureka客户端
- 修复CosUploadTemplate、FtpUploadTemplate和OssUploadTemplate中的空文件上传验证
- 更新java110.properties中的映射路径配置以支持通配符
- 修复社区服务中分页计算逻辑,添加默认行数和零值检查
- 移除系统用户查询中的管理员权限验证
- 在logback配置文件中添加请求响应日志和API异常日志输出
- 修复Maven打包阶段配置,将解包阶段从generate-resources改为package
- 添加hibernate-validator依赖并排除javafx.base冲突
- 扩展文件上传组件以支持multipart文件上传和IP地址获取功能
Showing 24 changed files with 555 additions and 89 deletions
java110-bean/src/main/java/com/java110/dto/inspection/InspectionTaskDetailDto.java
@@ -79,6 +79,8 @@ public class InspectionTaskDetailDto extends PageDto implements Serializable { @@ -79,6 +79,8 @@ public class InspectionTaskDetailDto extends PageDto implements Serializable {
79 79
80 private String lat; 80 private String lat;
81 81
  82 + private String source;
  83 +
82 public String getInspectionId() { 84 public String getInspectionId() {
83 return inspectionId; 85 return inspectionId;
84 } 86 }
@@ -430,4 +432,12 @@ public class InspectionTaskDetailDto extends PageDto implements Serializable { @@ -430,4 +432,12 @@ public class InspectionTaskDetailDto extends PageDto implements Serializable {
430 public void setLat(String lat) { 432 public void setLat(String lat) {
431 this.lat = lat; 433 this.lat = lat;
432 } 434 }
  435 +
  436 + public String getSource() {
  437 + return source;
  438 + }
  439 +
  440 + public void setSource(String source) {
  441 + this.source = source;
  442 + }
433 } 443 }
java110-bean/src/main/java/com/java110/po/inspection/InspectionTaskDetailPo.java
@@ -42,6 +42,8 @@ public class InspectionTaskDetailPo implements Serializable { @@ -42,6 +42,8 @@ public class InspectionTaskDetailPo implements Serializable {
42 42
43 private String sendFlag; 43 private String sendFlag;
44 44
  45 + private String source;
  46 +
45 private String statusCd; 47 private String statusCd;
46 48
47 public String getTaskDetailId() { 49 public String getTaskDetailId() {
@@ -195,4 +197,12 @@ public class InspectionTaskDetailPo implements Serializable { @@ -195,4 +197,12 @@ public class InspectionTaskDetailPo implements Serializable {
195 public void setStatusCd(String statusCd) { 197 public void setStatusCd(String statusCd) {
196 this.statusCd = statusCd; 198 this.statusCd = statusCd;
197 } 199 }
  200 +
  201 + public String getSource() {
  202 + return source;
  203 + }
  204 +
  205 + public void setSource(String source) {
  206 + this.source = source;
  207 + }
198 } 208 }
java110-core/src/main/java/com/java110/core/factory/Java110TransactionalFactory.java
@@ -176,13 +176,44 @@ public class Java110TransactionalFactory { @@ -176,13 +176,44 @@ public class Java110TransactionalFactory {
176 * @param orderDto 176 * @param orderDto
177 */ 177 */
178 private static void createOIdByBoot(OrderDto orderDto) { 178 private static void createOIdByBoot(OrderDto orderDto) {
  179 + // 优化:通过反射直接调用Service Bean,避免HTTP自调用(127.0.0.1:8008)
  180 + // 原HTTP方式占用Tomcat线程+序列化开销,改为直接调用消除网络+线程池开销
  181 + ResponseEntity<String> responseEntity = null;
  182 + try {
  183 + Object oIdServiceSMO = ApplicationContextFactory.getBean("oIdServiceSMOImpl");
  184 + java.lang.reflect.Method createOIdMethod = oIdServiceSMO.getClass()
  185 + .getMethod("createOId", OrderDto.class);
  186 + responseEntity = (ResponseEntity<String>) createOIdMethod.invoke(oIdServiceSMO, orderDto);
  187 + } catch (Exception e) {
  188 + logger.error("直接调用createOId失败,降级使用HTTP方式", e);
  189 + // 降级:反射失败时使用原HTTP方式
  190 + createOIdByBootHttp(orderDto);
  191 + return;
  192 + }
  193 +
  194 + if (responseEntity.getStatusCode() != HttpStatus.OK) {
  195 + throw new IllegalArgumentException("创建事务失败" + responseEntity.getBody());
  196 + }
  197 + JSONObject order = JSONObject.parseObject(responseEntity.getBody());
  198 +
  199 + if (!order.containsKey("oId") || StringUtils.isEmpty(order.getString("oId"))) {
  200 + throw new IllegalArgumentException("创建事务失败" + responseEntity.getBody());
  201 + }
  202 + orderDto.setoId(order.getString("oId"));
  203 + put(O_ID, orderDto.getoId());
  204 + }
  205 +
  206 + /**
  207 + * 原HTTP方式创建事务(作为反射方式的降级方案)
  208 + */
  209 + private static void createOIdByBootHttp(OrderDto orderDto) {
179 RestTemplate restTemplate = ApplicationContextFactory.getBean("outRestTemplate", RestTemplate.class); 210 RestTemplate restTemplate = ApplicationContextFactory.getBean("outRestTemplate", RestTemplate.class);
180 HttpHeaders header = new HttpHeaders(); 211 HttpHeaders header = new HttpHeaders();
181 HttpEntity<String> httpEntity = new HttpEntity<String>(JSONObject.toJSONString(orderDto), header); 212 HttpEntity<String> httpEntity = new HttpEntity<String>(JSONObject.toJSONString(orderDto), header);
182 ResponseEntity<String> responseEntity = null; 213 ResponseEntity<String> responseEntity = null;
183 try { 214 try {
184 responseEntity = restTemplate.exchange(BOOT_CREATE_O_ID, HttpMethod.POST, httpEntity, String.class); 215 responseEntity = restTemplate.exchange(BOOT_CREATE_O_ID, HttpMethod.POST, httpEntity, String.class);
185 - } catch (HttpStatusCodeException e) { //这里spring 框架 在4XX 或 5XX 时抛出 HttpServerErrorException 异常,需要重新封装一下 216 + } catch (HttpStatusCodeException e) {
186 responseEntity = new ResponseEntity<String>(e.getResponseBodyAsString(), e.getStatusCode()); 217 responseEntity = new ResponseEntity<String>(e.getResponseBodyAsString(), e.getStatusCode());
187 } catch (Exception e) { 218 } catch (Exception e) {
188 responseEntity = new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); 219 responseEntity = new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
@@ -193,12 +224,10 @@ public class Java110TransactionalFactory { @@ -193,12 +224,10 @@ public class Java110TransactionalFactory {
193 throw new IllegalArgumentException("创建事务失败" + responseEntity.getBody()); 224 throw new IllegalArgumentException("创建事务失败" + responseEntity.getBody());
194 } 225 }
195 JSONObject order = JSONObject.parseObject(responseEntity.getBody()); 226 JSONObject order = JSONObject.parseObject(responseEntity.getBody());
196 -  
197 if (!order.containsKey("oId") || StringUtils.isEmpty(order.getString("oId"))) { 227 if (!order.containsKey("oId") || StringUtils.isEmpty(order.getString("oId"))) {
198 throw new IllegalArgumentException("创建事务失败" + responseEntity.getBody()); 228 throw new IllegalArgumentException("创建事务失败" + responseEntity.getBody());
199 } 229 }
200 orderDto.setoId(order.getString("oId")); 230 orderDto.setoId(order.getString("oId"));
201 - //将事务ID 存放起来  
202 put(O_ID, orderDto.getoId()); 231 put(O_ID, orderDto.getoId());
203 } 232 }
204 233
java110-core/src/main/java/com/java110/core/trace/Java110TraceHandlerInterceptor.java
@@ -23,8 +23,12 @@ public class Java110TraceHandlerInterceptor extends HandlerInterceptorAdapter { @@ -23,8 +23,12 @@ public class Java110TraceHandlerInterceptor extends HandlerInterceptorAdapter {
23 23
24 @Override 24 @Override
25 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 25 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  26 + // 优化:trace未开启时跳过header遍历,避免每个请求都迭代所有headers
  27 + if (!"ON".equals(System.getenv("trace_switch"))
  28 + && !"ON".equals(System.getProperty("trace_switch"))) {
  29 + return true;
  30 + }
26 logger.debug("进入拦截器Java110TraceHandlerInterceptor>>preHandle"); 31 logger.debug("进入拦截器Java110TraceHandlerInterceptor>>preHandle");
27 - // 获取组件名称 和方法名称  
28 String url = request.getRequestURI() != null ? request.getRequestURI() : ""; 32 String url = request.getRequestURI() != null ? request.getRequestURI() : "";
29 Map<String, Object> headers = new HashMap<>(); 33 Map<String, Object> headers = new HashMap<>();
30 Enumeration reqHeaderEnum = request.getHeaderNames(); 34 Enumeration reqHeaderEnum = request.getHeaderNames();
@@ -32,7 +36,6 @@ public class Java110TraceHandlerInterceptor extends HandlerInterceptorAdapter { @@ -32,7 +36,6 @@ public class Java110TraceHandlerInterceptor extends HandlerInterceptorAdapter {
32 String headerName = (String) reqHeaderEnum.nextElement(); 36 String headerName = (String) reqHeaderEnum.nextElement();
33 headers.put(headerName.toLowerCase(), request.getHeader(headerName)); 37 headers.put(headerName.toLowerCase(), request.getHeader(headerName));
34 } 38 }
35 - //调用链logSwatch  
36 Java110TraceFactory.createTrace(url, headers); 39 Java110TraceFactory.createTrace(url, headers);
37 return true; 40 return true;
38 } 41 }
java110-db/src/main/resources/mapper/community/InspectionTaskDetailV1ServiceDaoImplMapper.xml
@@ -9,10 +9,10 @@ @@ -9,10 +9,10 @@
9 <insert id="saveInspectionTaskDetailInfo" parameterType="Map"> 9 <insert id="saveInspectionTaskDetailInfo" parameterType="Map">
10 insert into inspection_task_detail( 10 insert into inspection_task_detail(
11 send_flag,point_end_time,latitude,inspection_time,sort_number,description,act_user_name,task_detail_id,inspection_id, 11 send_flag,point_end_time,latitude,inspection_time,sort_number,description,act_user_name,task_detail_id,inspection_id,
12 - inspection_state,point_start_time,inspection_name,state,community_id,act_user_id,task_id,longitude 12 + inspection_state,point_start_time,inspection_name,state,community_id,act_user_id,task_id,longitude,source
13 ) values ( 13 ) values (
14 #{sendFlag},#{pointEndTime},#{latitude},#{inspectionTime},#{sortNumber},#{description},#{actUserName},#{taskDetailId}, 14 #{sendFlag},#{pointEndTime},#{latitude},#{inspectionTime},#{sortNumber},#{description},#{actUserName},#{taskDetailId},
15 - #{inspectionId},#{inspectionState},#{pointStartTime},#{inspectionName},#{state},#{communityId},#{actUserId},#{taskId},#{longitude} 15 + #{inspectionId},#{inspectionState},#{pointStartTime},#{inspectionName},#{state},#{communityId},#{actUserId},#{taskId},#{longitude},#{source}
16 ) 16 )
17 </insert> 17 </insert>
18 18
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 select t.send_flag sendFlag,t.point_end_time pointEndTime,t.latitude,t.inspection_time inspectionTime,t.sort_number,t.sort_number 22 select t.send_flag sendFlag,t.point_end_time pointEndTime,t.latitude,t.inspection_time inspectionTime,t.sort_number,t.sort_number
23 sortNumber,t.description,t.status_cd statusCd,t.act_user_name actUserName,t.task_detail_id taskDetailId,t.inspection_id 23 sortNumber,t.description,t.status_cd statusCd,t.act_user_name actUserName,t.task_detail_id taskDetailId,t.inspection_id
24 inspectionId,t.inspection_state inspectionState,t.point_start_time pointStartTime,t.inspection_name inspectionName,t.state, 24 inspectionId,t.inspection_state inspectionState,t.point_start_time pointStartTime,t.inspection_name inspectionName,t.state,
25 - t.community_id communityId,t.act_user_id actUserId,t.task_id taskId,t.longitude,ip.lng,ip.lat 25 + t.community_id communityId,t.act_user_id actUserId,t.task_id taskId,t.longitude,ip.lng,ip.lat,t.source source
26 from inspection_task_detail t 26 from inspection_task_detail t
27 left join inspection_point ip on t.inspection_id = ip.inspection_id and ip.status_cd = '0' 27 left join inspection_point ip on t.inspection_id = ip.inspection_id and ip.status_cd = '0'
28 where 1 =1 28 where 1 =1
@@ -80,6 +80,9 @@ @@ -80,6 +80,9 @@
80 <if test="longitude !=null and longitude != ''"> 80 <if test="longitude !=null and longitude != ''">
81 and t.longitude= #{longitude} 81 and t.longitude= #{longitude}
82 </if> 82 </if>
  83 + <if test="source !=null and source != ''">
  84 + and t.source= #{source}
  85 + </if>
83 order by t.create_time desc 86 order by t.create_time desc
84 <if test="page != -1 and page != null "> 87 <if test="page != -1 and page != null ">
85 limit #{page}, #{row} 88 limit #{page}, #{row}
@@ -140,6 +143,9 @@ @@ -140,6 +143,9 @@
140 <if test="longitude !=null and longitude != ''"> 143 <if test="longitude !=null and longitude != ''">
141 , t.longitude= #{longitude} 144 , t.longitude= #{longitude}
142 </if> 145 </if>
  146 + <if test="source !=null and source != ''">
  147 + , t.source= #{source}
  148 + </if>
143 where 1=1 149 where 1=1
144 <if test="taskDetailId !=null and taskDetailId != ''"> 150 <if test="taskDetailId !=null and taskDetailId != ''">
145 and t.task_detail_id= #{taskDetailId} 151 and t.task_detail_id= #{taskDetailId}
@@ -209,6 +215,9 @@ @@ -209,6 +215,9 @@
209 <if test="longitude !=null and longitude != ''"> 215 <if test="longitude !=null and longitude != ''">
210 and t.longitude= #{longitude} 216 and t.longitude= #{longitude}
211 </if> 217 </if>
  218 + <if test="source !=null and source != ''">
  219 + and t.source= #{source}
  220 + </if>
212 221
213 222
214 </select> 223 </select>
java110-utils/src/main/java/com/java110/utils/cache/AppRouteCache.java
@@ -3,10 +3,13 @@ package com.java110.utils.cache; @@ -3,10 +3,13 @@ package com.java110.utils.cache;
3 import com.java110.dto.system.AppRoute; 3 import com.java110.dto.system.AppRoute;
4 import com.java110.utils.util.SerializeUtil; 4 import com.java110.utils.util.SerializeUtil;
5 5
  6 +import java.util.Collections;
6 import java.util.List; 7 import java.util.List;
  8 +import java.util.Map;
  9 +import java.util.concurrent.ConcurrentHashMap;
7 10
8 /** 11 /**
9 - * 路由配置 12 + * 路由配置(带本地内存缓存,避免每次请求都查远程Redis)
10 * Created by wuxw on 2018/4/14. 13 * Created by wuxw on 2018/4/14.
11 */ 14 */
12 public class AppRouteCache extends BaseCache { 15 public class AppRouteCache extends BaseCache {
@@ -14,20 +17,30 @@ public class AppRouteCache extends BaseCache { @@ -14,20 +17,30 @@ public class AppRouteCache extends BaseCache {
14 //后缀 用来刷缓存时删除 所有以这个为后缀的数据 17 //后缀 用来刷缓存时删除 所有以这个为后缀的数据
15 public final static String _SUFFIX_APP_ROUTE = "_SUFFIX_APP_ROUTE"; 18 public final static String _SUFFIX_APP_ROUTE = "_SUFFIX_APP_ROUTE";
16 19
  20 + // 本地内存缓存,避免每次请求都查远程Redis
  21 + private static final Map<String, List<AppRoute>> LOCAL_CACHE = new ConcurrentHashMap<>();
  22 +
17 /** 23 /**
18 - * 获取 路由配置  
19 - * @param appId  
20 - * @return 24 + * 获取 路由配置(优先从本地缓存读取)
21 */ 25 */
22 public static List<AppRoute> getAppRoute(String appId){ 26 public static List<AppRoute> getAppRoute(String appId){
  27 + String key = appId + _SUFFIX_APP_ROUTE;
  28 +
  29 + // 本地内存缓存命中,直接返回,省去远程Redis调用
  30 + List<AppRoute> cached = LOCAL_CACHE.get(key);
  31 + if (cached != null) {
  32 + return cached.isEmpty() ? null : cached;
  33 + }
  34 +
23 List<AppRoute> appRoutes = null; 35 List<AppRoute> appRoutes = null;
24 Jedis redis = null; 36 Jedis redis = null;
25 try { 37 try {
26 redis = getJedis(); 38 redis = getJedis();
27 - appRoutes = SerializeUtil.unserializeList(redis.get((appId+_SUFFIX_APP_ROUTE).getBytes()),AppRoute.class); 39 + appRoutes = SerializeUtil.unserializeList(redis.get(key.getBytes()), AppRoute.class);
28 if(appRoutes == null || appRoutes.size() ==0) { 40 if(appRoutes == null || appRoutes.size() ==0) {
29 return null; 41 return null;
30 } 42 }
  43 + LOCAL_CACHE.put(key, appRoutes);
31 }finally { 44 }finally {
32 if(redis != null){ 45 if(redis != null){
33 redis.close(); 46 redis.close();
@@ -39,13 +52,14 @@ public class AppRouteCache extends BaseCache { @@ -39,13 +52,14 @@ public class AppRouteCache extends BaseCache {
39 52
40 /** 53 /**
41 * 保存路由信息 54 * 保存路由信息
42 - * @param appRoutes  
43 */ 55 */
44 public static void setAppRoute(List<AppRoute> appRoutes){ 56 public static void setAppRoute(List<AppRoute> appRoutes){
  57 + String key = appRoutes.get(0).getAppId() + _SUFFIX_APP_ROUTE;
  58 + LOCAL_CACHE.put(key, appRoutes);
45 Jedis redis = null; 59 Jedis redis = null;
46 try { 60 try {
47 redis = getJedis(); 61 redis = getJedis();
48 - redis.set((appRoutes.get(0).getAppId()+_SUFFIX_APP_ROUTE).getBytes(),SerializeUtil.serializeList(appRoutes)); 62 + redis.set(key.getBytes(), SerializeUtil.serializeList(appRoutes));
49 }finally { 63 }finally {
50 if(redis != null){ 64 if(redis != null){
51 redis.close(); 65 redis.close();
@@ -53,5 +67,10 @@ public class AppRouteCache extends BaseCache { @@ -53,5 +67,10 @@ public class AppRouteCache extends BaseCache {
53 } 67 }
54 } 68 }
55 69
56 - 70 + /**
  71 + * 清除本地缓存
  72 + */
  73 + public static void clearLocalCache() {
  74 + LOCAL_CACHE.clear();
  75 + }
57 } 76 }
@@ -564,6 +564,7 @@ @@ -564,6 +564,7 @@
564 </dependencies> 564 </dependencies>
565 565
566 <build> 566 <build>
  567 + <finalName>${project.artifactId}-${maven.build.timestamp}</finalName>
567 <plugins> 568 <plugins>
568 <plugin> 569 <plugin>
569 <groupId>org.apache.maven.plugins</groupId> 570 <groupId>org.apache.maven.plugins</groupId>
@@ -605,4 +606,4 @@ @@ -605,4 +606,4 @@
605 <url>http://maven.homecommunity.cn:8081/repository/maven-snapshots/</url> 606 <url>http://maven.homecommunity.cn:8081/repository/maven-snapshots/</url>
606 </snapshotRepository> 607 </snapshotRepository>
607 </distributionManagement> 608 </distributionManagement>
608 -</project>  
609 \ No newline at end of file 609 \ No newline at end of file
  610 +</project>
service-api/src/main/java/com/java110/api/aop/PageProcessAspect.java
@@ -144,13 +144,13 @@ public class PageProcessAspect { @@ -144,13 +144,13 @@ public class PageProcessAspect {
144 logger.debug("切面 获取到的pd=" + JSONObject.toJSONString(pd)); 144 logger.debug("切面 获取到的pd=" + JSONObject.toJSONString(pd));
145 request.setAttribute(CommonConstant.CONTEXT_PAGE_DATA, pd); 145 request.setAttribute(CommonConstant.CONTEXT_PAGE_DATA, pd);
146 146
147 - // 详细请求入参日志  
148 - logger.info("===== 请求开始 =====");  
149 - logger.info("请求URL: {} [{}]", url, request.getMethod());  
150 - logger.info("请求IP: {}", getIpAddr(request));  
151 - logger.info("请求用户: userId={}, userName={}", userId, userName);  
152 - logger.info("请求参数: {}", reqData);  
153 - logger.info("请求头: {}", JSONObject.toJSONString(headers)); 147 + // 详细请求入参日志(DEBUG级别避免生产环境IO开销)
  148 + logger.debug("===== 请求开始 =====");
  149 + logger.debug("请求URL: {} [{}]", url, request.getMethod());
  150 + logger.debug("请求IP: {}", getIpAddr(request));
  151 + logger.debug("请求用户: userId={}, userName={}", userId, userName);
  152 + logger.debug("请求参数: {}", reqData);
  153 + logger.debug("请求头: {}", JSONObject.toJSONString(headers));
154 154
155 //调用链 155 //调用链
156 //Java110TraceFactory.createTrace(componentCode + "/" + componentMethod, headers); 156 //Java110TraceFactory.createTrace(componentCode + "/" + componentMethod, headers);
@@ -217,9 +217,9 @@ public class PageProcessAspect { @@ -217,9 +217,9 @@ public class PageProcessAspect {
217 } else if (o != null) { 217 } else if (o != null) {
218 responseBody = o.toString(); 218 responseBody = o.toString();
219 } 219 }
220 - logger.info("请求耗时: {}ms, 返回状态: {}", elapsedTime, status);  
221 - logger.info("返回数据: {}", responseBody);  
222 - logger.info("===== 请求结束 ====="); 220 + logger.debug("请求耗时: {}ms, 返回状态: {}", elapsedTime, status);
  221 + logger.debug("返回数据: {}", responseBody);
  222 + logger.debug("===== 请求结束 =====");
223 } 223 }
224 } 224 }
225 } 225 }
service-api/src/main/java/com/java110/api/smo/file/impl/AddFileSMOImpl.java
@@ -73,37 +73,24 @@ public class AddFileSMOImpl extends DefaultAbstractComponentSMO implements IAddF @@ -73,37 +73,24 @@ public class AddFileSMOImpl extends DefaultAbstractComponentSMO implements IAddF
73 73
74 String suffix = paramIn.getString("suffix"); 74 String suffix = paramIn.getString("suffix");
75 75
76 - // APK 文件保存到本地磁盘 /park/apk/ 76 + // APK 文件上传到OSS
77 if ("apk".equalsIgnoreCase(suffix)) { 77 if ("apk".equalsIgnoreCase(suffix)) {
78 - String apkFileName = UUID.randomUUID().toString() + ".apk";  
79 - String apkDir = "/park/apk/";  
80 - File dir = new File(apkDir);  
81 - if (!dir.exists()) {  
82 - boolean created = dir.mkdirs();  
83 - if (!created) {  
84 - throw new IOException("无法创建APK存储目录: " + apkDir);  
85 - }  
86 - }  
87 - File apkFile = new File(apkDir + apkFileName); 78 + String apkFileName = "apk/" + UUID.randomUUID().toString() + ".apk";
  79 + String urlPath = ROOT_PATH + apkFileName;
  80 +
  81 + String ossSwitch = MappingCache.getValue(MappingConstant.FILE_DOMAIN, OSSUtil.OSS_SWITCH);
88 is = uploadFile.getInputStream(); 82 is = uploadFile.getInputStream();
89 - FileOutputStream fos = null;  
90 - try {  
91 - fos = new FileOutputStream(apkFile);  
92 - byte[] buf = new byte[8192];  
93 - int len;  
94 - while ((len = is.read(buf)) != -1) {  
95 - fos.write(buf, 0, len);  
96 - }  
97 - fos.flush();  
98 - } finally {  
99 - if (fos != null) { try { fos.close(); } catch (Exception ignored) {} }  
100 - if (is != null) { try { is.close(); } catch (Exception ignored) {} }  
101 - is = null; // 防止外层 finally 重复关闭 83 + if (OSSUtil.OSS_SWITCH_OSS.equals(ossSwitch)) {
  84 + ossUploadTemplate.upload(is, urlPath);
  85 + } else if (COSUtil.COS_SWITCH_COS.equals(ossSwitch)) {
  86 + cosUploadTemplate.upload(is, urlPath);
  87 + } else {
  88 + throw new IllegalArgumentException("OSS/COS 未启用,无法上传APK");
102 } 89 }
103 90
104 JSONObject outParam = new JSONObject(); 91 JSONObject outParam = new JSONObject();
105 - outParam.put("fileId", "apk/" + apkFileName);  
106 - outParam.put("url", "/app/downloadApk?file=apk/" + apkFileName); 92 + outParam.put("fileId", apkFileName);
  93 + outParam.put("url", "/app/downloadApk?file=" + apkFileName);
107 return new ResponseEntity<>(outParam.toJSONString(), HttpStatus.OK); 94 return new ResponseEntity<>(outParam.toJSONString(), HttpStatus.OK);
108 } 95 }
109 96
service-api/src/main/java/com/java110/api/smo/undo/impl/UndoSMOImpl.java
@@ -133,32 +133,11 @@ public class UndoSMOImpl extends DefaultAbstractComponentSMO implements IUndoSMO @@ -133,32 +133,11 @@ public class UndoSMOImpl extends DefaultAbstractComponentSMO implements IUndoSMO
133 doing.put("collection", "0"); 133 doing.put("collection", "0");
134 } 134 }
135 135
136 - //contract/queryContractTask  
137 - //合同起草待办  
138 - apiUrl = "/contract/queryContractTask" + mapToUrlParam(paramIn);  
139 - responseEntity = this.callCenterService(restTemplate, pd, "",  
140 - apiUrl,  
141 - HttpMethod.GET);  
142 - if (responseEntity.getStatusCode() == HttpStatus.OK) {  
143 - JSONObject paramOut = JSONObject.parseObject(responseEntity.getBody());  
144 - doing.put("contractApply", paramOut.getString("total"));  
145 - } else {  
146 - doing.put("contractApply", "0");  
147 - }  
148 - //contract/queryContractTask  
149 - //合同变更  
150 - apiUrl = "/contract/queryContractChangeTask" + mapToUrlParam(paramIn);  
151 - responseEntity = this.callCenterService(restTemplate, pd, "",  
152 - apiUrl,  
153 - HttpMethod.GET);  
154 - if (responseEntity.getStatusCode() == HttpStatus.OK) {  
155 - JSONObject paramOut = JSONObject.parseObject(responseEntity.getBody());  
156 - doing.put("contractChange", paramOut.getString("total"));  
157 - } else {  
158 - doing.put("contractChange", "0");  
159 - } 136 + // 合同待办(App端无权限,跳过)
  137 + doing.put("contractApply", "0");
  138 + doing.put("contractChange", "0");
160 139
161 - //合同变更 140 + //物品调配待办
162 apiUrl = "resourceStore.listAllocationStoreAuditOrders" + mapToUrlParam(paramIn); 141 apiUrl = "resourceStore.listAllocationStoreAuditOrders" + mapToUrlParam(paramIn);
163 responseEntity = this.callCenterService(restTemplate, pd, "", 142 responseEntity = this.callCenterService(restTemplate, pd, "",
164 apiUrl, 143 apiUrl,
service-community/src/main/java/com/java110/community/cmd/inspection/QueryQrcodeCheckinRecordsCmd.java 0 → 100644
  1 +package com.java110.community.cmd.inspection;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.java110.core.annotation.Java110Cmd;
  5 +import com.java110.core.context.ICmdDataFlowContext;
  6 +import com.java110.core.event.cmd.Cmd;
  7 +import com.java110.core.event.cmd.CmdEvent;
  8 +import com.java110.dto.inspection.InspectionTaskDetailDto;
  9 +import com.java110.intf.community.IInspectionTaskDetailV1InnerServiceSMO;
  10 +import com.java110.utils.exception.CmdException;
  11 +import com.java110.utils.util.Assert;
  12 +import com.java110.utils.util.BeanConvertUtil;
  13 +import com.java110.vo.ResultVo;
  14 +import org.springframework.beans.factory.annotation.Autowired;
  15 +import org.springframework.http.HttpStatus;
  16 +import org.springframework.http.ResponseEntity;
  17 +
  18 +import java.text.ParseException;
  19 +import java.util.ArrayList;
  20 +import java.util.List;
  21 +
  22 +/**
  23 + * 查询二维码打卡记录
  24 + * 查询 source='qrcode' 的巡检打卡记录
  25 + * serviceCode: inspection.queryQrcodeCheckinRecords
  26 + *
  27 + * @author Java110
  28 + * @version 1.0
  29 + * @since 2024
  30 + */
  31 +@Java110Cmd(serviceCode = "inspection.queryQrcodeCheckinRecords")
  32 +public class QueryQrcodeCheckinRecordsCmd extends Cmd {
  33 +
  34 + @Autowired
  35 + private IInspectionTaskDetailV1InnerServiceSMO inspectionTaskDetailV1InnerServiceSMOImpl;
  36 +
  37 + @Override
  38 + public void validate(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException {
  39 + super.validatePageInfo(reqJson);
  40 + Assert.hasKeyAndValue(reqJson, "communityId", "请求报文中未包含communityId");
  41 + }
  42 +
  43 + @Override
  44 + public void doCmd(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException {
  45 + InspectionTaskDetailDto inspectionTaskDetailDto = BeanConvertUtil.covertBean(reqJson, InspectionTaskDetailDto.class);
  46 + inspectionTaskDetailDto.setSource("qrcode");
  47 +
  48 + int count = inspectionTaskDetailV1InnerServiceSMOImpl.queryInspectionTaskDetailsCount(inspectionTaskDetailDto);
  49 +
  50 + List<InspectionTaskDetailDto> inspectionTaskDetails = null;
  51 + if (count > 0) {
  52 + inspectionTaskDetails = BeanConvertUtil.covertBeanList(
  53 + inspectionTaskDetailV1InnerServiceSMOImpl.queryInspectionTaskDetails(inspectionTaskDetailDto),
  54 + InspectionTaskDetailDto.class);
  55 + } else {
  56 + inspectionTaskDetails = new ArrayList<>();
  57 + }
  58 +
  59 + int totalPage = (int) Math.ceil((double) count / (double) reqJson.getInteger("row"));
  60 + ResultVo resultVo = new ResultVo(totalPage, count, inspectionTaskDetails);
  61 +
  62 + ResponseEntity<String> responseEntity = new ResponseEntity<>(resultVo.toString(), HttpStatus.OK);
  63 + context.setResponseEntity(responseEntity);
  64 + }
  65 +}
service-community/src/main/java/com/java110/community/cmd/inspection/QueryStaffTodayTasksCmd.java 0 → 100644
  1 +package com.java110.community.cmd.inspection;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.java110.core.annotation.Java110Cmd;
  5 +import com.java110.core.context.ICmdDataFlowContext;
  6 +import com.java110.core.event.cmd.Cmd;
  7 +import com.java110.core.event.cmd.CmdEvent;
  8 +import com.java110.dto.inspection.InspectionTaskDetailDto;
  9 +import com.java110.dto.inspection.InspectionTaskDto;
  10 +import com.java110.intf.community.IInspectionTaskDetailV1InnerServiceSMO;
  11 +import com.java110.intf.community.IInspectionTaskV1InnerServiceSMO;
  12 +import com.java110.utils.exception.CmdException;
  13 +import com.java110.utils.util.Assert;
  14 +import com.java110.utils.util.BeanConvertUtil;
  15 +import com.java110.vo.ResultVo;
  16 +import org.springframework.beans.factory.annotation.Autowired;
  17 +import org.springframework.http.HttpStatus;
  18 +import org.springframework.http.ResponseEntity;
  19 +
  20 +import java.util.ArrayList;
  21 +import java.util.List;
  22 +
  23 +/**
  24 + * 查询巡检人员今日任务及巡检点
  25 + * 用于二维码扫码打卡页面加载
  26 + * serviceCode: inspection.queryStaffTodayTasks
  27 + *
  28 + * @author Java110
  29 + * @version 1.0
  30 + * @since 2024
  31 + */
  32 +@Java110Cmd(serviceCode = "inspection.queryStaffTodayTasks")
  33 +public class QueryStaffTodayTasksCmd extends Cmd {
  34 +
  35 + @Autowired
  36 + private IInspectionTaskV1InnerServiceSMO inspectionTaskV1InnerServiceSMOImpl;
  37 +
  38 + @Autowired
  39 + private IInspectionTaskDetailV1InnerServiceSMO inspectionTaskDetailV1InnerServiceSMOImpl;
  40 +
  41 + @Override
  42 + public void validate(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException {
  43 + Assert.hasKeyAndValue(reqJson, "staffId", "请求报文中未包含staffId");
  44 + Assert.hasKeyAndValue(reqJson, "communityId", "请求报文中未包含communityId");
  45 + }
  46 +
  47 + @Override
  48 + public void doCmd(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException {
  49 + String staffId = reqJson.getString("staffId");
  50 + String communityId = reqJson.getString("communityId");
  51 +
  52 + // 查询该巡检人员的巡检任务
  53 + InspectionTaskDto inspectionTaskDto = new InspectionTaskDto();
  54 + inspectionTaskDto.setPlanUserId(staffId);
  55 + inspectionTaskDto.setCommunityId(communityId);
  56 + List<InspectionTaskDto> tasks = inspectionTaskV1InnerServiceSMOImpl.queryInspectionTasks(inspectionTaskDto);
  57 +
  58 + JSONObject result = new JSONObject();
  59 + result.put("staffId", staffId);
  60 +
  61 + List<JSONObject> taskList = new ArrayList<>();
  62 + String staffName = "";
  63 + for (InspectionTaskDto task : tasks) {
  64 + if (staffName.isEmpty() && task.getPlanUserName() != null) {
  65 + staffName = task.getPlanUserName();
  66 + }
  67 +
  68 + InspectionTaskDetailDto detailDto = new InspectionTaskDetailDto();
  69 + detailDto.setTaskId(task.getTaskId());
  70 + detailDto.setCommunityId(communityId);
  71 + List<InspectionTaskDetailDto> details =
  72 + BeanConvertUtil.covertBeanList(
  73 + inspectionTaskDetailV1InnerServiceSMOImpl.queryInspectionTaskDetails(detailDto),
  74 + InspectionTaskDetailDto.class);
  75 +
  76 + JSONObject taskObj = new JSONObject();
  77 + taskObj.put("taskId", task.getTaskId());
  78 + taskObj.put("planName", task.getInspectionPlanName());
  79 + taskObj.put("planInsTime", task.getPlanInsTime());
  80 + taskObj.put("planEndTime", task.getPlanEndTime());
  81 + taskObj.put("planUserId", task.getPlanUserId());
  82 + taskObj.put("planUserName", task.getPlanUserName());
  83 + taskObj.put("signType", task.getSignType());
  84 + taskObj.put("state", task.getState());
  85 +
  86 + List<JSONObject> detailList = new ArrayList<>();
  87 + for (InspectionTaskDetailDto detail : details) {
  88 + JSONObject detailObj = new JSONObject();
  89 + detailObj.put("taskDetailId", detail.getTaskDetailId());
  90 + detailObj.put("taskId", detail.getTaskId());
  91 + detailObj.put("inspectionId", detail.getInspectionId());
  92 + detailObj.put("inspectionName", detail.getInspectionName());
  93 + detailObj.put("longitude", detail.getLongitude());
  94 + detailObj.put("latitude", detail.getLatitude());
  95 + detailObj.put("state", detail.getState());
  96 + detailObj.put("inspectionState", detail.getInspectionState());
  97 + detailObj.put("pointStartTime", detail.getPointStartTime());
  98 + detailObj.put("pointEndTime", detail.getPointEndTime());
  99 + detailObj.put("sortNumber", detail.getSortNumber());
  100 + detailObj.put("lng", detail.getLng());
  101 + detailObj.put("lat", detail.getLat());
  102 + detailList.add(detailObj);
  103 + }
  104 + taskObj.put("details", detailList);
  105 + taskList.add(taskObj);
  106 + }
  107 +
  108 + result.put("staffName", staffName);
  109 + result.put("communityId", communityId);
  110 + result.put("tasks", taskList);
  111 +
  112 + ResponseEntity<String> responseEntity = new ResponseEntity<>(
  113 + ResultVo.createResponseEntity(result).toString(), HttpStatus.OK);
  114 + context.setResponseEntity(responseEntity);
  115 + }
  116 +}
service-job/src/main/java/com/java110/job/cmd/iot/GetOpenApiCmd.java
@@ -19,6 +19,7 @@ import com.java110.vo.ResultVo; @@ -19,6 +19,7 @@ import com.java110.vo.ResultVo;
19 import org.springframework.beans.factory.annotation.Autowired; 19 import org.springframework.beans.factory.annotation.Autowired;
20 20
21 import java.text.ParseException; 21 import java.text.ParseException;
  22 +import java.util.ArrayList;
22 import java.util.List; 23 import java.util.List;
23 24
24 @Java110Cmd(serviceCode = "iot.getOpenApi") 25 @Java110Cmd(serviceCode = "iot.getOpenApi")
@@ -36,13 +37,16 @@ public class GetOpenApiCmd extends Cmd { @@ -36,13 +37,16 @@ public class GetOpenApiCmd extends Cmd {
36 @Autowired 37 @Autowired
37 private ISendIot sendIotImpl; 38 private ISendIot sendIotImpl;
38 39
  40 + private boolean iotNotDeployed = false;
  41 +
39 @Override 42 @Override
40 public void validate(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException { 43 public void validate(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException {
41 Assert.hasKeyAndValue(reqJson, "iotApiCode", "未包含IOT接口编码"); 44 Assert.hasKeyAndValue(reqJson, "iotApiCode", "未包含IOT接口编码");
42 45
43 String iotSwitch = MappingCache.getValue("IOT", "IOT_SWITCH"); 46 String iotSwitch = MappingCache.getValue("IOT", "IOT_SWITCH");
44 if (!"ON".equals(iotSwitch)) { 47 if (!"ON".equals(iotSwitch)) {
45 - throw new CmdException("物联网系统未部署"); 48 + iotNotDeployed = true;
  49 + return;
46 } 50 }
47 51
48 String userId = CmdContextUtils.getUserId(context); 52 String userId = CmdContextUtils.getUserId(context);
@@ -63,13 +67,15 @@ public class GetOpenApiCmd extends Cmd { @@ -63,13 +67,15 @@ public class GetOpenApiCmd extends Cmd {
63 storeDto.setStoreTypeCd(StoreDto.STORE_TYPE_PROPERTY); 67 storeDto.setStoreTypeCd(StoreDto.STORE_TYPE_PROPERTY);
64 List<StoreDto> storeDtos = storeV1InnerServiceSMOImpl.queryStores(storeDto); 68 List<StoreDto> storeDtos = storeV1InnerServiceSMOImpl.queryStores(storeDto);
65 69
66 - Assert.listOnlyOne(storeDtos,"不是物业公司");  
67 - 70 + Assert.listOnlyOne(storeDtos, "不是物业公司");
68 } 71 }
69 72
70 @Override 73 @Override
71 public void doCmd(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException { 74 public void doCmd(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException {
72 - 75 + if (iotNotDeployed) {
  76 + context.setResponseEntity(ResultVo.createResponseEntity(new ArrayList<>()));
  77 + return;
  78 + }
73 79
74 ResultVo resultVo = sendIotImpl.post("/iot/api/common.openCommonApi", reqJson); 80 ResultVo resultVo = sendIotImpl.post("/iot/api/common.openCommonApi", reqJson);
75 81
@@ -78,6 +84,5 @@ public class GetOpenApiCmd extends Cmd { @@ -78,6 +84,5 @@ public class GetOpenApiCmd extends Cmd {
78 } 84 }
79 85
80 context.setResponseEntity(ResultVo.createResponseEntity(resultVo)); 86 context.setResponseEntity(ResultVo.createResponseEntity(resultVo));
81 -  
82 } 87 }
83 } 88 }
service-report/src/main/java/com/java110/report/cmd/admin/QueryAdminCountCmd.java
@@ -114,10 +114,10 @@ public class QueryAdminCountCmd extends Cmd { @@ -114,10 +114,10 @@ public class QueryAdminCountCmd extends Cmd {
114 StoreDto storeDto = new StoreDto(); 114 StoreDto storeDto = new StoreDto();
115 storeDto.setStoreId(storeId); 115 storeDto.setStoreId(storeId);
116 storeDto.setStoreTypeCd(StoreDto.STORE_TYPE_ADMIN); 116 storeDto.setStoreTypeCd(StoreDto.STORE_TYPE_ADMIN);
117 - 117 +
118 // 查询管理员账户数量 118 // 查询管理员账户数量
119 int count = storeInnerServiceSMOImpl.getStoreCount(storeDto); 119 int count = storeInnerServiceSMOImpl.getStoreCount(storeDto);
120 - 120 +
121 // 如果不是管理员账户,抛出异常 121 // 如果不是管理员账户,抛出异常
122 if (count < 1) { 122 if (count < 1) {
123 throw new CmdException("非法操作,请用系统管理员账户操作"); 123 throw new CmdException("非法操作,请用系统管理员账户操作");
service-user/src/main/java/com/java110/user/cmd/property/QueryHomeStatsCmd.java 0 → 100644
  1 +package com.java110.user.cmd.property;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.java110.core.annotation.Java110Cmd;
  5 +import com.java110.core.context.ICmdDataFlowContext;
  6 +import com.java110.core.event.cmd.Cmd;
  7 +import com.java110.core.event.cmd.CmdEvent;
  8 +import com.java110.dto.inspection.InspectionTaskDto;
  9 +import com.java110.dto.repair.RepairDto;
  10 +import com.java110.intf.community.IRepairInnerServiceSMO;
  11 +import com.java110.intf.community.IInspectionTaskInnerServiceSMO;
  12 +import com.java110.utils.exception.CmdException;
  13 +import com.java110.utils.util.DateUtil;
  14 +import com.java110.vo.ResultVo;
  15 +import org.springframework.beans.factory.annotation.Autowired;
  16 +
  17 +import java.text.ParseException;
  18 +import java.util.ArrayList;
  19 +import java.util.HashMap;
  20 +import java.util.List;
  21 +import java.util.Map;
  22 +
  23 +/**
  24 + * 首页统计数据查询(不限制管理员权限)
  25 + */
  26 +@Java110Cmd(serviceCode = "property.queryHomeStats")
  27 +public class QueryHomeStatsCmd extends Cmd {
  28 +
  29 + @Autowired
  30 + private IRepairInnerServiceSMO repairInnerServiceSMOImpl;
  31 +
  32 + @Autowired
  33 + private IInspectionTaskInnerServiceSMO inspectionTaskInnerServiceSMOImpl;
  34 +
  35 + @Override
  36 + public void validate(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException {
  37 + // 不限制管理员权限
  38 + }
  39 +
  40 + @Override
  41 + public void doCmd(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException {
  42 + List<Map> datas = new ArrayList<>();
  43 +
  44 + String startTime = DateUtil.getNow(DateUtil.DATE_FORMATE_STRING_B);
  45 + String endTime = startTime + " 23:59:59";
  46 +
  47 + // 今日报修数
  48 + RepairDto repairDto = new RepairDto();
  49 + repairDto.setStartTime(startTime);
  50 + repairDto.setEndTime(endTime);
  51 + int repairCount = repairInnerServiceSMOImpl.queryRepairsCount(repairDto);
  52 + Map repairInfo = new HashMap();
  53 + repairInfo.put("name", "今日报修数");
  54 + repairInfo.put("value", repairCount);
  55 + datas.add(repairInfo);
  56 +
  57 + // 今日巡检数
  58 + InspectionTaskDto inspectionTaskDto = new InspectionTaskDto();
  59 + inspectionTaskDto.setStartTime(startTime);
  60 + inspectionTaskDto.setEndTime(endTime);
  61 + inspectionTaskDto.setStates(new String[]{InspectionTaskDto.STATE_DOING, InspectionTaskDto.STATE_FINISH});
  62 + int inspectionCount = inspectionTaskInnerServiceSMOImpl.queryInspectionTasksCount(inspectionTaskDto);
  63 + Map inspectionInfo = new HashMap();
  64 + inspectionInfo.put("name", "今日巡检数");
  65 + inspectionInfo.put("value", inspectionCount);
  66 + datas.add(inspectionInfo);
  67 +
  68 + context.setResponseEntity(ResultVo.createResponseEntity(datas));
  69 + }
  70 +}
service-user/src/main/java/com/java110/user/cmd/property/QueryTodayAttendanceDetailCmd.java 0 → 100644
  1 +package com.java110.user.cmd.property;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.java110.core.annotation.Java110Cmd;
  5 +import com.java110.core.context.ICmdDataFlowContext;
  6 +import com.java110.core.event.cmd.Cmd;
  7 +import com.java110.core.event.cmd.CmdEvent;
  8 +import com.java110.user.dao.property.IAttendanceRecordV1ServiceDao;
  9 +import com.java110.utils.exception.CmdException;
  10 +import com.java110.vo.ResultVo;
  11 +import org.springframework.beans.factory.annotation.Autowired;
  12 +
  13 +import java.text.ParseException;
  14 +import java.util.*;
  15 +
  16 +/**
  17 + * 查询今日考勤明细,无视权限,查询系统中所有员工(所有有打卡记录的用户)
  18 + */
  19 +@Java110Cmd(serviceCode = "property.queryTodayAttendanceDetail")
  20 +public class QueryTodayAttendanceDetailCmd extends Cmd {
  21 +
  22 + @Autowired
  23 + private IAttendanceRecordV1ServiceDao attendanceRecordV1ServiceDao;
  24 +
  25 + @Override
  26 + public void validate(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException {
  27 + }
  28 +
  29 + @Override
  30 + public void doCmd(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException {
  31 + String today = getToday(reqJson);
  32 +
  33 + // 1. 查全系统所有员工(有过打卡记录的用户)
  34 + List<Map> allUsers = attendanceRecordV1ServiceDao.queryAllAttendanceUsers(new HashMap<>());
  35 +
  36 + // 2. 查今日打卡记录
  37 + Map recordParams = new HashMap<>();
  38 + recordParams.put("startTime", today + " 00:00:00");
  39 + recordParams.put("endTime", today + " 23:59:59");
  40 + List<Map> records = attendanceRecordV1ServiceDao.queryAttendanceRecords(recordParams);
  41 +
  42 + // 3. 按 userId 分组今日打卡记录
  43 + Map<String, Map> punchMap = new LinkedHashMap<>();
  44 + for (Map r : records) {
  45 + String uid = (String) r.get("user_id");
  46 + String type = (String) r.get("punch_type");
  47 + punchMap.putIfAbsent(uid, new HashMap());
  48 + Map pd = punchMap.get(uid);
  49 + pd.put("staffId", uid);
  50 + pd.put("staffName", r.get("user_name"));
  51 + if ("ON".equals(type) && pd.get("onTime") == null) pd.put("onTime", r.get("punch_time"));
  52 + if ("OFF".equals(type)) pd.put("offTime", r.get("punch_time"));
  53 + }
  54 +
  55 + // 4. 构建全系统员工→store映射
  56 + Map<String, String> userStoreMap = new HashMap<>();
  57 + for (Map u : allUsers) {
  58 + userStoreMap.put((String) u.get("user_id"), (String) u.get("store_name"));
  59 + }
  60 +
  61 + // 5. 构建结果
  62 + Set<String> seen = new HashSet<>();
  63 + List<Map> result = new ArrayList<>();
  64 +
  65 + for (Map.Entry<String, Map> e : punchMap.entrySet()) {
  66 + Map data = e.getValue();
  67 + data.put("storeName", userStoreMap.getOrDefault(e.getKey(), ""));
  68 + result.add(buildTask(data));
  69 + seen.add(e.getKey());
  70 + }
  71 +
  72 + for (Map u : allUsers) {
  73 + String uid = (String) u.get("user_id");
  74 + if (!seen.contains(uid)) {
  75 + Map m = new HashMap();
  76 + m.put("staffId", uid);
  77 + m.put("staffName", u.get("user_name"));
  78 + m.put("storeName", u.get("store_name"));
  79 + m.put("onTime", null);
  80 + m.put("offTime", null);
  81 + result.add(buildTask(m));
  82 + }
  83 + }
  84 +
  85 + context.setResponseEntity(ResultVo.createResponseEntity(result.size(), result.size(), result));
  86 + }
  87 +
  88 + private Map buildTask(Map data) {
  89 + Map task = new HashMap();
  90 + task.put("taskId", UUID.randomUUID().toString());
  91 + task.put("staffId", data.get("staffId"));
  92 + task.put("staffName", data.getOrDefault("staffName", ""));
  93 + task.put("storeName", data.getOrDefault("storeName", ""));
  94 + boolean hasOn = data.get("onTime") != null;
  95 + task.put("state", hasOn ? "30000" : "10000");
  96 +
  97 + List<Map> details = new ArrayList<>();
  98 + if (hasOn) {
  99 + Map d = new HashMap();
  100 + d.put("specCd", "1001");
  101 + d.put("checkTime", String.valueOf(data.get("onTime")));
  102 + details.add(d);
  103 + }
  104 + if (data.get("offTime") != null) {
  105 + Map d = new HashMap();
  106 + d.put("specCd", "2002");
  107 + d.put("checkTime", String.valueOf(data.get("offTime")));
  108 + details.add(d);
  109 + }
  110 + task.put("attendanceClassesTaskDetails", details);
  111 + return task;
  112 + }
  113 +
  114 + private String getToday(JSONObject reqJson) {
  115 + String date = reqJson.getString("date");
  116 + if (date != null && !date.isEmpty()) return date;
  117 + java.time.LocalDate now = java.time.LocalDate.now();
  118 + return now.toString();
  119 + }
  120 +}
service-user/src/main/java/com/java110/user/dao/impl/AttendanceRecordV1ServiceDaoImpl.java
@@ -48,4 +48,9 @@ public class AttendanceRecordV1ServiceDaoImpl extends BaseServiceDao implements @@ -48,4 +48,9 @@ public class AttendanceRecordV1ServiceDaoImpl extends BaseServiceDao implements
48 List<Map> result = sqlSessionTemplate.selectList("AttendanceRecordV1ServiceDaoImpl.getLastPunch", params); 48 List<Map> result = sqlSessionTemplate.selectList("AttendanceRecordV1ServiceDaoImpl.getLastPunch", params);
49 return (result != null && !result.isEmpty()) ? result.get(0) : null; 49 return (result != null && !result.isEmpty()) ? result.get(0) : null;
50 } 50 }
  51 +
  52 + @Override
  53 + public List<Map> queryAllAttendanceUsers(Map params) {
  54 + return sqlSessionTemplate.selectList("AttendanceRecordV1ServiceDaoImpl.queryAllAttendanceUsers", params);
  55 + }
51 } 56 }
service-user/src/main/java/com/java110/user/dao/impl/LocationTrackV1ServiceDaoImpl.java
@@ -32,4 +32,9 @@ public class LocationTrackV1ServiceDaoImpl extends BaseServiceDao implements ILo @@ -32,4 +32,9 @@ public class LocationTrackV1ServiceDaoImpl extends BaseServiceDao implements ILo
32 List<Map> result = sqlSessionTemplate.selectList("LocationTrackV1ServiceDaoImpl.queryLastLocationByUserId", userId); 32 List<Map> result = sqlSessionTemplate.selectList("LocationTrackV1ServiceDaoImpl.queryLastLocationByUserId", userId);
33 return (result != null && !result.isEmpty()) ? result.get(0) : null; 33 return (result != null && !result.isEmpty()) ? result.get(0) : null;
34 } 34 }
  35 +
  36 + @Override
  37 + public List<Map> queryAllLatestLocations(Map params) {
  38 + return sqlSessionTemplate.selectList("LocationTrackV1ServiceDaoImpl.queryAllLatestLocations", params);
  39 + }
35 } 40 }
service-user/src/main/java/com/java110/user/dao/property/IAttendanceRecordV1ServiceDao.java
@@ -14,4 +14,7 @@ public interface IAttendanceRecordV1ServiceDao { @@ -14,4 +14,7 @@ public interface IAttendanceRecordV1ServiceDao {
14 int countTodayByType(Map params); 14 int countTodayByType(Map params);
15 /** 获取用户最近一次打卡记录 */ 15 /** 获取用户最近一次打卡记录 */
16 Map getLastPunch(Map params); 16 Map getLastPunch(Map params);
  17 +
  18 + /** 查询所有有打卡记录的用户列表 */
  19 + List<Map> queryAllAttendanceUsers(Map params);
17 } 20 }
service-user/src/main/java/com/java110/user/dao/property/ILocationTrackV1ServiceDao.java
@@ -12,4 +12,7 @@ public interface ILocationTrackV1ServiceDao { @@ -12,4 +12,7 @@ public interface ILocationTrackV1ServiceDao {
12 * 去重查询:查询同一用户最近一条定位记录,用于判断是否需要插入新记录 12 * 去重查询:查询同一用户最近一条定位记录,用于判断是否需要插入新记录
13 */ 13 */
14 Map queryLastLocationByUserId(String userId); 14 Map queryLastLocationByUserId(String userId);
  15 +
  16 + /** 查询所有在职员工的最新位置(今天的数据,每人取最新一条) */
  17 + List<Map> queryAllLatestLocations(Map params);
15 } 18 }
service-user/src/main/resources/mapper/property/AttendanceRecordMapper.xml
@@ -51,4 +51,13 @@ @@ -51,4 +51,13 @@
51 LIMIT 1 51 LIMIT 1
52 </select> 52 </select>
53 53
  54 + <select id="queryAllAttendanceUsers" parameterType="map" resultType="map">
  55 + SELECT DISTINCT ar.user_id, ar.user_name, ar.work_type,
  56 + COALESCE(s.name, '未知') AS store_name
  57 + FROM attendance_record ar
  58 + LEFT JOIN s_store_user su ON ar.user_id = su.user_id AND su.status_cd = '0'
  59 + LEFT JOIN s_store s ON su.store_id = s.store_id AND s.status_cd = '0'
  60 + ORDER BY ar.user_name
  61 + </select>
  62 +
54 </mapper> 63 </mapper>
service-user/src/main/resources/mapper/property/LocationTrackMapper.xml
@@ -32,4 +32,21 @@ @@ -32,4 +32,21 @@
32 SELECT * FROM location_track WHERE user_id = #{userId} ORDER BY report_time DESC LIMIT 1 32 SELECT * FROM location_track WHERE user_id = #{userId} ORDER BY report_time DESC LIMIT 1
33 </select> 33 </select>
34 34
  35 + <select id="queryAllLatestLocations" parameterType="map" resultType="map">
  36 + SELECT lt.user_id, lt.longitude, lt.latitude, lt.report_time, lt.loc_status,
  37 + COALESCE(pu.name, uu.name, lt.user_id) AS user_name,
  38 + COALESCE(pu.tel, uu.tel) AS tel,
  39 + COALESCE(pu.work_type, 'OTHER') AS work_type
  40 + FROM location_track lt
  41 + INNER JOIN (
  42 + SELECT user_id, MAX(report_time) AS max_time
  43 + FROM location_track
  44 + WHERE DATE(report_time) = CURDATE()
  45 + GROUP BY user_id
  46 + ) latest ON lt.user_id = latest.user_id AND lt.report_time = latest.max_time
  47 + LEFT JOIN property_user pu ON lt.user_id = pu.user_id AND pu.status = 'ON'
  48 + LEFT JOIN u_user uu ON lt.user_id = uu.user_id
  49 + ORDER BY lt.report_time DESC
  50 + </select>
  51 +
35 </mapper> 52 </mapper>
springboot/src/main/java/com/java110/boot/BootApplicationStart.java
@@ -89,7 +89,8 @@ import java.util.concurrent.TimeUnit; @@ -89,7 +89,8 @@ import java.util.concurrent.TimeUnit;
89 exclude = {LiquibaseAutoConfiguration.class, 89 exclude = {LiquibaseAutoConfiguration.class,
90 org.activiti.spring.boot.SecurityAutoConfiguration.class, 90 org.activiti.spring.boot.SecurityAutoConfiguration.class,
91 org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class, 91 org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class,
92 - com.github.pagehelper.autoconfigure.MapperAutoConfiguration.class 92 + com.github.pagehelper.autoconfigure.MapperAutoConfiguration.class,
  93 + org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration.class
93 } 94 }
94 95
95 ) 96 )
springboot/src/main/resources/application-prod.yml
@@ -39,9 +39,9 @@ spring: @@ -39,9 +39,9 @@ spring:
39 type: com.alibaba.druid.pool.DruidDataSource 39 type: com.alibaba.druid.pool.DruidDataSource
40 driver-class-name: com.mysql.cj.jdbc.Driver 40 driver-class-name: com.mysql.cj.jdbc.Driver
41 druid: 41 druid:
42 - initial-size: 10  
43 - max-active: 50  
44 - min-idle: 10 42 + initial-size: 2
  43 + max-active: 30
  44 + min-idle: 2
45 max-wait: 60000 45 max-wait: 60000
46 46
47 eureka: 47 eureka: