Compare commits
15 Commits
01993779a7
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 0797785176 | |||
| 86adb47392 | |||
| 780cd56ffe | |||
| 8cf9140f56 | |||
| 2f56ca07cb | |||
| 6987a0e790 | |||
| 0bfc9cbc86 | |||
| d5e7787e89 | |||
| aa2084090a | |||
| a138f3b916 | |||
| 380fd117c5 | |||
| a2e23ea264 | |||
| 3b26591f9d | |||
| 8d13978e84 | |||
| a2d9cfec02 |
@@ -63,6 +63,10 @@ public class AuthProvider {
|
|||||||
DEFAULT_SKIP_URL.add("/manager/check-upload");
|
DEFAULT_SKIP_URL.add("/manager/check-upload");
|
||||||
DEFAULT_SKIP_URL.add("/assets/**");
|
DEFAULT_SKIP_URL.add("/assets/**");
|
||||||
DEFAULT_SKIP_URL.add("/iam/sso/token/**");
|
DEFAULT_SKIP_URL.add("/iam/sso/token/**");
|
||||||
|
DEFAULT_SKIP_URL.add("/blade-transport/customer-archive/public/**");
|
||||||
|
DEFAULT_SKIP_URL.add("/customer-archive/public/**");
|
||||||
|
DEFAULT_SKIP_URL.add("/blade-openapi/openApi/mk/process/commonCallback");
|
||||||
|
DEFAULT_SKIP_URL.add("/openApi/mk/process/commonCallback");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+24
@@ -38,6 +38,8 @@ public interface IBusinessProcessClient {
|
|||||||
String QUERY_TODO_LIST = API_PREFIX + "/queryTodoList";
|
String QUERY_TODO_LIST = API_PREFIX + "/queryTodoList";
|
||||||
String QUERY_BUSINESS_PROCESS_SNAPSHOT = API_PREFIX + "/queryBusinessProcessSnapshot";
|
String QUERY_BUSINESS_PROCESS_SNAPSHOT = API_PREFIX + "/queryBusinessProcessSnapshot";
|
||||||
String QUERY_APPROVED_RECORD_LIST = API_PREFIX + "/queryApprovedRecordsNoAttachments";
|
String QUERY_APPROVED_RECORD_LIST = API_PREFIX + "/queryApprovedRecordsNoAttachments";
|
||||||
|
String GET_CURRENT_NODES = API_PREFIX + "/getCurrentNodes";
|
||||||
|
String GET_PROCESS_INFO = API_PREFIX + "/getProcessInfo";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交业务流程
|
* 提交业务流程
|
||||||
@@ -102,4 +104,26 @@ public interface IBusinessProcessClient {
|
|||||||
*/
|
*/
|
||||||
@GetMapping(QUERY_APPROVED_RECORD_LIST)
|
@GetMapping(QUERY_APPROVED_RECORD_LIST)
|
||||||
FR<List<ProcessApprovedRecordVO>> queryApprovedRecordsNoAttachments(@RequestParam(name = "bizId", required = false) String bizId, @RequestParam(name = "processInstanceId", required = false) String processInstanceId);
|
FR<List<ProcessApprovedRecordVO>> queryApprovedRecordsNoAttachments(@RequestParam(name = "bizId", required = false) String bizId, @RequestParam(name = "processInstanceId", required = false) String processInstanceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程当前节点详情
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例id
|
||||||
|
* @param loginName MK登录名(手机号)
|
||||||
|
* @return 当前节点详情
|
||||||
|
*/
|
||||||
|
@GetMapping(GET_CURRENT_NODES)
|
||||||
|
FR<Object> getCurrentNodes(@RequestParam("processInstanceId") String processInstanceId,
|
||||||
|
@RequestParam(value = "loginName", required = false) String loginName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程实例详情
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例id
|
||||||
|
* @param loginName MK登录名(手机号)
|
||||||
|
* @return 流程实例详情
|
||||||
|
*/
|
||||||
|
@GetMapping(GET_PROCESS_INFO)
|
||||||
|
FR<Object> getProcessInfo(@RequestParam("processInstanceId") String processInstanceId,
|
||||||
|
@RequestParam(value = "loginName", required = false) String loginName);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -43,6 +43,12 @@ public class MeasurementUnit extends BaseEntity {
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计量单位编码
|
||||||
|
*/
|
||||||
|
@Schema(description = "计量单位编码")
|
||||||
|
private String unitCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计量单位
|
* 计量单位
|
||||||
*/
|
*/
|
||||||
|
|||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.system.pojo.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OA组织(公司/部门)分页同步结果
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "OA组织分页同步结果")
|
||||||
|
public class OaOrgSyncPageVO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "同步阶段:company / department")
|
||||||
|
private String stage;
|
||||||
|
|
||||||
|
@Schema(description = "当前页")
|
||||||
|
private Integer current;
|
||||||
|
|
||||||
|
@Schema(description = "每页条数")
|
||||||
|
private Integer size;
|
||||||
|
|
||||||
|
@Schema(description = "OA总条数")
|
||||||
|
private Long total;
|
||||||
|
|
||||||
|
@Schema(description = "本页从OA拉取的条数")
|
||||||
|
private Integer fetchedCount;
|
||||||
|
|
||||||
|
@Schema(description = "本页同步成功条数")
|
||||||
|
private Integer syncedCount;
|
||||||
|
|
||||||
|
@Schema(description = "本页跳过条数")
|
||||||
|
private Integer skippedCount;
|
||||||
|
|
||||||
|
@Schema(description = "是否已到最后一页")
|
||||||
|
private Boolean finished;
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package org.springblade.transport.feign;
|
||||||
|
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.transport.pojo.dto.CustomerProcessNodeSyncDTO;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客商档案 Feign接口
|
||||||
|
*/
|
||||||
|
@FeignClient(value = "blade-transport")
|
||||||
|
public interface ICustomerArchiveClient {
|
||||||
|
|
||||||
|
String API_PREFIX = "/feign/client/customerArchive";
|
||||||
|
String SYNC_PROCESS_NODE = API_PREFIX + "/syncProcessNode";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 MK 当前节点同步客商当前节点、当前处理人和审批状态
|
||||||
|
*
|
||||||
|
* @param param 同步参数
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
@PostMapping(SYNC_PROCESS_NODE)
|
||||||
|
FR<Boolean> syncProcessNode(@RequestBody CustomerProcessNodeSyncDTO param);
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package org.springblade.transport.feign;
|
||||||
|
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.transport.pojo.dto.MkProcessSyncDTO;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 业务流程同步 Feign
|
||||||
|
*/
|
||||||
|
@FeignClient(value = "blade-transport")
|
||||||
|
public interface IMkProcessClient {
|
||||||
|
|
||||||
|
String API_PREFIX = "/feign/client/mkProcess";
|
||||||
|
String APPLY = API_PREFIX + "/apply";
|
||||||
|
|
||||||
|
@PostMapping(APPLY)
|
||||||
|
FR<Boolean> apply(@RequestBody MkProcessSyncDTO param);
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package org.springblade.transport.pojo.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客商流程当前节点同步参数
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "客商流程当前节点同步参数")
|
||||||
|
public class CustomerProcessNodeSyncDTO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "客商ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "当前节点")
|
||||||
|
private String currentNode;
|
||||||
|
|
||||||
|
@Schema(description = "当前处理人")
|
||||||
|
private String currentProcessor;
|
||||||
|
|
||||||
|
@Schema(description = "审批状态")
|
||||||
|
private String approvalStatus;
|
||||||
|
|
||||||
|
@Schema(description = "MK 流程实例详情,传入后按 currentHandlers.fdName 和 handlerInfos.nodeName 回写")
|
||||||
|
private Object processInfo;
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package org.springblade.transport.pojo.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 流程节点同步参数
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "MK 流程节点同步参数")
|
||||||
|
public class MkProcessSyncDTO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "业务类型,如 project-apply")
|
||||||
|
private String bizType;
|
||||||
|
|
||||||
|
@Schema(description = "业务主键")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "动作:sync / approve / reject")
|
||||||
|
private String action;
|
||||||
|
|
||||||
|
@Schema(description = "处理人姓名")
|
||||||
|
private String processorName;
|
||||||
|
|
||||||
|
@Schema(description = "MK 流程实例详情")
|
||||||
|
private Object processInfo;
|
||||||
|
}
|
||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.transport.pojo.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运单车辆实时定位结果
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "运单车辆实时定位结果")
|
||||||
|
public class WaybillLocateVO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "运单ID")
|
||||||
|
private Long waybillId;
|
||||||
|
|
||||||
|
@Schema(description = "车牌号")
|
||||||
|
private String vehicleNo;
|
||||||
|
|
||||||
|
@Schema(description = "经度")
|
||||||
|
private BigDecimal longitude;
|
||||||
|
|
||||||
|
@Schema(description = "纬度")
|
||||||
|
private BigDecimal latitude;
|
||||||
|
|
||||||
|
@Schema(description = "地址")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
@Schema(description = "定位时间")
|
||||||
|
private String locateTime;
|
||||||
|
|
||||||
|
@Schema(description = "速度")
|
||||||
|
private String speed;
|
||||||
|
|
||||||
|
@Schema(description = "方向")
|
||||||
|
private String direction;
|
||||||
|
|
||||||
|
@Schema(description = "LBS原始数据")
|
||||||
|
private Map<String, Object> rawData;
|
||||||
|
}
|
||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.transport.pojo.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运单历史轨迹结果
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "运单历史轨迹结果")
|
||||||
|
public class WaybillTrackVO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "运单ID")
|
||||||
|
private Long waybillId;
|
||||||
|
|
||||||
|
@Schema(description = "车牌号")
|
||||||
|
private String vehicleNo;
|
||||||
|
|
||||||
|
@Schema(description = "开始日期")
|
||||||
|
private String startDate;
|
||||||
|
|
||||||
|
@Schema(description = "结束日期")
|
||||||
|
private String endDate;
|
||||||
|
|
||||||
|
@Schema(description = "轨迹点数量")
|
||||||
|
private Integer total;
|
||||||
|
|
||||||
|
@Schema(description = "轨迹点列表")
|
||||||
|
private List<WaybillTrackPointVO> points = new ArrayList<>();
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Schema(description = "轨迹点")
|
||||||
|
public static class WaybillTrackPointVO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "车牌号")
|
||||||
|
private String vehicleNo;
|
||||||
|
|
||||||
|
@Schema(description = "经度")
|
||||||
|
private BigDecimal longitude;
|
||||||
|
|
||||||
|
@Schema(description = "纬度")
|
||||||
|
private BigDecimal latitude;
|
||||||
|
|
||||||
|
@Schema(description = "定位时间")
|
||||||
|
private String locateTime;
|
||||||
|
|
||||||
|
@Schema(description = "速度")
|
||||||
|
private String speed;
|
||||||
|
|
||||||
|
@Schema(description = "方向")
|
||||||
|
private String direction;
|
||||||
|
|
||||||
|
@Schema(description = "地址")
|
||||||
|
private String address;
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
@@ -44,6 +44,10 @@ public class OpenApiApplication {
|
|||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
BladeApplication.disableNacosLaunchConfig();
|
BladeApplication.disableNacosLaunchConfig();
|
||||||
|
// 当前处理人刷新依赖 RedisLockClient;Nacos 全局 blade.lock.enabled=false 时仍需为本服务开启
|
||||||
|
if (System.getProperty("blade.lock.enabled") == null) {
|
||||||
|
System.setProperty("blade.lock.enabled", "true");
|
||||||
|
}
|
||||||
BladeApplication.run(AppConstant.APPLICATION_OPENAPI_NAME, OpenApiApplication.class, args);
|
BladeApplication.run(AppConstant.APPLICATION_OPENAPI_NAME, OpenApiApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import io.swagger.v3.oas.annotations.Hidden;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
|
import org.springblade.core.secure.constant.AuthConstant;
|
||||||
import org.springblade.core.tool.api.FR;
|
import org.springblade.core.tool.api.FR;
|
||||||
import org.springblade.openapi.mk.api.IApi4MK;
|
import org.springblade.openapi.mk.api.IApi4MK;
|
||||||
import org.springblade.openapi.mk.pojo.dto.Api4MKProcessApprovalDTO;
|
import org.springblade.openapi.mk.pojo.dto.Api4MKProcessApprovalDTO;
|
||||||
@@ -49,6 +51,7 @@ public class Api4MK implements IApi4MK {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
public FR<Boolean> processCommonCallback(Api4MKProcessApprovalDTO param) {
|
public FR<Boolean> processCommonCallback(Api4MKProcessApprovalDTO param) {
|
||||||
log.info("mk流程通用回调 操作名称:{} 参数:{}", ProcessOperationType.getOperationName(param.getOperation()), JSON.toJSONString(param));
|
log.info("mk流程通用回调 操作名称:{} 参数:{}", ProcessOperationType.getOperationName(param.getOperation()), JSON.toJSONString(param));
|
||||||
callback(param, ProcessHandler::approve);
|
callback(param, ProcessHandler::approve);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ spring:
|
|||||||
- nacos:blade-${spring.profiles.active}.yaml?group=DEFAULT_GROUP&refreshEnabled=true
|
- nacos:blade-${spring.profiles.active}.yaml?group=DEFAULT_GROUP&refreshEnabled=true
|
||||||
- nacos:blade-openapi-dynamictp.yaml?group=DEFAULT_GROUP&refreshEnabled=true
|
- nacos:blade-openapi-dynamictp.yaml?group=DEFAULT_GROUP&refreshEnabled=true
|
||||||
- optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml?group=DEFAULT_GROUP&refreshEnabled=true
|
- optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml?group=DEFAULT_GROUP&refreshEnabled=true
|
||||||
|
- optional:classpath:openapi-lock.yaml
|
||||||
cloud:
|
cloud:
|
||||||
nacos:
|
nacos:
|
||||||
username: ${NACOS_USERNAME:${NACOS_PROD_USERNAME:nacos}}
|
username: ${NACOS_USERNAME:${NACOS_PROD_USERNAME:nacos}}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# openapi 当前处理人刷新依赖 Redisson 分布式锁。
|
||||||
|
# 该文件必须在 nacos blade-*.yaml 之后导入,用于覆盖全局 blade.lock.enabled=false。
|
||||||
|
# 连接信息与业务 Redis 保持一致,避免 Redisson 因缺少密码出现 NOAUTH。
|
||||||
|
blade:
|
||||||
|
lock:
|
||||||
|
enabled: true
|
||||||
|
address: redis://${spring.data.redis.host:127.0.0.1}:${spring.data.redis.port:6379}
|
||||||
|
password: ${spring.data.redis.password:}
|
||||||
|
database: ${spring.data.redis.database:0}
|
||||||
@@ -62,6 +62,10 @@
|
|||||||
<groupId>org.springblade</groupId>
|
<groupId>org.springblade</groupId>
|
||||||
<artifactId>blade-mk-api</artifactId>
|
<artifactId>blade-mk-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springblade</groupId>
|
||||||
|
<artifactId>blade-transport-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 其他依赖 -->
|
<!-- 其他依赖 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
+18
-4
@@ -17,6 +17,7 @@ import org.springblade.process.pojo.dto.ApprovalDTO;
|
|||||||
import org.springblade.process.pojo.vo.ApprovalVO;
|
import org.springblade.process.pojo.vo.ApprovalVO;
|
||||||
import org.springblade.process.pojo.vo.ProcessApprovedRecordVO;
|
import org.springblade.process.pojo.vo.ProcessApprovedRecordVO;
|
||||||
import org.springblade.process.service.IBusinessProcessService;
|
import org.springblade.process.service.IBusinessProcessService;
|
||||||
|
import org.springblade.thirdparty.mk.pojo.dto.MKProcessCreateDTO;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@@ -52,29 +53,42 @@ public class BusinessProcessController extends BladeController {
|
|||||||
return R.data(pages);
|
return R.data(pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/isEditView")
|
@PostMapping("/processSubmit")
|
||||||
@ApiOperationSupport(order = 2)
|
@ApiOperationSupport(order = 2)
|
||||||
|
@Operation(summary = "提交MK审核流", description = "调用mk processSubmit,传入templateCode/submitIdentity/formInstanceId")
|
||||||
|
public R<String> processSubmit(@Validated @RequestBody MKProcessCreateDTO param) {
|
||||||
|
return R.data(businessProcessService.processSubmit(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/processDelete")
|
||||||
|
@ApiOperationSupport(order = 7)
|
||||||
|
public R<Boolean> processDelete(@RequestBody MKProcessCreateDTO param) {
|
||||||
|
return R.data(businessProcessService.processDelete(param == null ? null : param.getFormInstanceId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/isEditView")
|
||||||
|
@ApiOperationSupport(order = 3)
|
||||||
@Operation(summary = "是否编辑页", description = "传入业务id")
|
@Operation(summary = "是否编辑页", description = "传入业务id")
|
||||||
public R<Boolean> isEditView(@Valid @NotBlank(message = "业务id不能为空") String bizId) {
|
public R<Boolean> isEditView(@Valid @NotBlank(message = "业务id不能为空") String bizId) {
|
||||||
return R.data(businessProcessService.isEditView(bizId));
|
return R.data(businessProcessService.isEditView(bizId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/getMKApprovalUrl")
|
@GetMapping("/getMKApprovalUrl")
|
||||||
@ApiOperationSupport(order = 3)
|
@ApiOperationSupport(order = 4)
|
||||||
@Operation(summary = "获取mk审批页链接", description = "传入业务id或流程实例id")
|
@Operation(summary = "获取mk审批页链接", description = "传入业务id或流程实例id")
|
||||||
public R<String> getMKApprovalUrl(String bizId, String processInstanceId) {
|
public R<String> getMKApprovalUrl(String bizId, String processInstanceId) {
|
||||||
return R.data(businessProcessService.getMKApprovalUrl(bizId, processInstanceId));
|
return R.data(businessProcessService.getMKApprovalUrl(bizId, processInstanceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/getApprovedRecords")
|
@GetMapping("/getApprovedRecords")
|
||||||
@ApiOperationSupport(order = 4)
|
@ApiOperationSupport(order = 5)
|
||||||
@Operation(summary = "查询审批记录", description = "传入业务id或流程实例id")
|
@Operation(summary = "查询审批记录", description = "传入业务id或流程实例id")
|
||||||
public R<List<ProcessApprovedRecordVO>> getApprovedRecords(String bizId, String processInstanceId) {
|
public R<List<ProcessApprovedRecordVO>> getApprovedRecords(String bizId, String processInstanceId) {
|
||||||
return R.data(businessProcessService.queryApprovedRecords(bizId, processInstanceId));
|
return R.data(businessProcessService.queryApprovedRecords(bizId, processInstanceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/downloadFile")
|
@GetMapping("/downloadFile")
|
||||||
@ApiOperationSupport(order = 5)
|
@ApiOperationSupport(order = 6)
|
||||||
@Operation(summary = "下载附件", description = "传入附件id")
|
@Operation(summary = "下载附件", description = "传入附件id")
|
||||||
public void downloadFile(HttpServletResponse response, @Valid @NotBlank(message = "附件id不能为空") String fileId) {
|
public void downloadFile(HttpServletResponse response, @Valid @NotBlank(message = "附件id不能为空") String fileId) {
|
||||||
businessProcessService.downloadFile(response, fileId);
|
businessProcessService.downloadFile(response, fileId);
|
||||||
|
|||||||
+20
@@ -3,6 +3,8 @@ package org.springblade.process.feign;
|
|||||||
import io.swagger.v3.oas.annotations.Hidden;
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
|
import org.springblade.core.secure.constant.AuthConstant;
|
||||||
import org.springblade.core.tool.api.FR;
|
import org.springblade.core.tool.api.FR;
|
||||||
import org.springblade.process.pojo.dto.BusinessProcessCurrentHandlerRefreshDTO;
|
import org.springblade.process.pojo.dto.BusinessProcessCurrentHandlerRefreshDTO;
|
||||||
import org.springblade.process.pojo.dto.BusinessProcessDeleteDTO;
|
import org.springblade.process.pojo.dto.BusinessProcessDeleteDTO;
|
||||||
@@ -13,8 +15,10 @@ import org.springblade.process.pojo.vo.ProcessApprovedRecordVO;
|
|||||||
import org.springblade.process.pojo.vo.ProcessTodoVO;
|
import org.springblade.process.pojo.vo.ProcessTodoVO;
|
||||||
import org.springblade.process.service.IBusinessProcessService;
|
import org.springblade.process.service.IBusinessProcessService;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -74,4 +78,20 @@ public class BusinessProcessClient implements IBusinessProcessClient {
|
|||||||
public FR<List<ProcessApprovedRecordVO>> queryApprovedRecordsNoAttachments(String bizId, String processInstanceId) {
|
public FR<List<ProcessApprovedRecordVO>> queryApprovedRecordsNoAttachments(String bizId, String processInstanceId) {
|
||||||
return FR.data(businessProcessService.queryApprovedRecordsNoAttachments(bizId, processInstanceId));
|
return FR.data(businessProcessService.queryApprovedRecordsNoAttachments(bizId, processInstanceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
|
@GetMapping(GET_CURRENT_NODES)
|
||||||
|
@Override
|
||||||
|
public FR<Object> getCurrentNodes(@RequestParam("processInstanceId") String processInstanceId,
|
||||||
|
@RequestParam(value = "loginName", required = false) String loginName) {
|
||||||
|
return FR.data(businessProcessService.getCurrentNodes(processInstanceId, loginName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
|
@GetMapping(GET_PROCESS_INFO)
|
||||||
|
@Override
|
||||||
|
public FR<Object> getProcessInfo(@RequestParam("processInstanceId") String processInstanceId,
|
||||||
|
@RequestParam(value = "loginName", required = false) String loginName) {
|
||||||
|
return FR.data(businessProcessService.getProcessInfo(processInstanceId, loginName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
@@ -6,6 +6,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import org.springblade.process.pojo.dto.*;
|
import org.springblade.process.pojo.dto.*;
|
||||||
import org.springblade.process.pojo.entity.BusinessProcess;
|
import org.springblade.process.pojo.entity.BusinessProcess;
|
||||||
import org.springblade.process.pojo.vo.*;
|
import org.springblade.process.pojo.vo.*;
|
||||||
|
import org.springblade.thirdparty.mk.pojo.dto.MKProcessCreateDTO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -25,6 +26,40 @@ public interface IBusinessProcessService extends IService<BusinessProcess> {
|
|||||||
*/
|
*/
|
||||||
BusinessProcessVO submitBusinessProcess(BusinessProcessSubmitDTO<?> param);
|
BusinessProcessVO submitBusinessProcess(BusinessProcessSubmitDTO<?> param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直接调用 MK processSubmit 提交流程
|
||||||
|
*
|
||||||
|
* @param param MK 流程创建参数
|
||||||
|
* @return 流程实例 id
|
||||||
|
*/
|
||||||
|
String processSubmit(MKProcessCreateDTO param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按业务表单实例 id 删除 MK 流程(不删除本地业务流程记录,供驳回后重新提交使用)
|
||||||
|
*
|
||||||
|
* @param formInstanceId 业务表单实例 id
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean processDelete(String formInstanceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程当前节点详情
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例id
|
||||||
|
* @param loginName MK登录名(手机号),可为空,为空时按流程发起人解析
|
||||||
|
* @return 当前节点列表
|
||||||
|
*/
|
||||||
|
List<?> getCurrentNodes(String processInstanceId, String loginName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程实例详情
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例id
|
||||||
|
* @param loginName MK登录名(手机号),可为空,为空时按流程发起人解析
|
||||||
|
* @return 流程实例详情
|
||||||
|
*/
|
||||||
|
Object getProcessInfo(String processInstanceId, String loginName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改业务流程状态
|
* 修改业务流程状态
|
||||||
* @param param
|
* @param param
|
||||||
|
|||||||
+264
@@ -15,6 +15,7 @@ import org.springblade.process.pojo.enums.ApproveStatusEnum;
|
|||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.log.utils.AssertUtils;
|
import org.springblade.core.log.utils.AssertUtils;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
import org.springblade.core.tool.utils.StringUtil;
|
import org.springblade.core.tool.utils.StringUtil;
|
||||||
import org.springblade.process.convert.ApprovalConvert;
|
import org.springblade.process.convert.ApprovalConvert;
|
||||||
import org.springblade.process.convert.BusinessProcessConvert;
|
import org.springblade.process.convert.BusinessProcessConvert;
|
||||||
@@ -24,6 +25,8 @@ import org.springblade.process.pojo.entity.BusinessProcess;
|
|||||||
import org.springblade.process.pojo.enums.TodoStatus;
|
import org.springblade.process.pojo.enums.TodoStatus;
|
||||||
import org.springblade.process.pojo.vo.*;
|
import org.springblade.process.pojo.vo.*;
|
||||||
import org.springblade.process.service.IBusinessProcessService;
|
import org.springblade.process.service.IBusinessProcessService;
|
||||||
|
import org.springblade.system.pojo.entity.User;
|
||||||
|
import org.springblade.system.service.IUserService;
|
||||||
import org.springblade.thirdparty.mk.config.MKProperties;
|
import org.springblade.thirdparty.mk.config.MKProperties;
|
||||||
import org.springblade.thirdparty.mk.constant.MKConstant;
|
import org.springblade.thirdparty.mk.constant.MKConstant;
|
||||||
import org.springblade.thirdparty.mk.constant.MKDoc;
|
import org.springblade.thirdparty.mk.constant.MKDoc;
|
||||||
@@ -39,12 +42,17 @@ import org.springblade.thirdparty.mk.pojo.dto.approval.MKProcessDTO;
|
|||||||
import org.springblade.thirdparty.mk.pojo.dto.sort.*;
|
import org.springblade.thirdparty.mk.pojo.dto.sort.*;
|
||||||
import org.springblade.thirdparty.mk.pojo.vo.*;
|
import org.springblade.thirdparty.mk.pojo.vo.*;
|
||||||
import org.springblade.thirdparty.mk.service.IMKService;
|
import org.springblade.thirdparty.mk.service.IMKService;
|
||||||
|
import org.springblade.transport.feign.ICustomerArchiveClient;
|
||||||
|
import org.springblade.transport.feign.IMkProcessClient;
|
||||||
|
import org.springblade.transport.pojo.dto.CustomerProcessNodeSyncDTO;
|
||||||
|
import org.springblade.transport.pojo.dto.MkProcessSyncDTO;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 业务流程关联表 服务实现类
|
* 业务流程关联表 服务实现类
|
||||||
@@ -61,6 +69,9 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
|||||||
private final IMKService mkService;
|
private final IMKService mkService;
|
||||||
private final MKProperties mkProperties;
|
private final MKProperties mkProperties;
|
||||||
private final ApprovalConvert approvalConvert;
|
private final ApprovalConvert approvalConvert;
|
||||||
|
private final IUserService userService;
|
||||||
|
private final ICustomerArchiveClient customerArchiveClient;
|
||||||
|
private final IMkProcessClient mkProcessClient;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
@@ -114,6 +125,259 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
|||||||
return businessProcessVO;
|
return businessProcessVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public String processSubmit(MKProcessCreateDTO param) {
|
||||||
|
AssertUtils.notNull(param, "提交流程参数不能为空");
|
||||||
|
AssertUtils.notBlank(param.getFormInstanceId(), "表单实例id不能为空");
|
||||||
|
AssertUtils.notBlank(param.getTemplateCode(), "模板编码不能为空");
|
||||||
|
// 前端拿到的手机号可能经 @Sensitive 脱敏(如 137****8880),这里从库取真实手机号覆盖
|
||||||
|
String loginName = resolveCurrentUserPhone();
|
||||||
|
AssertUtils.notBlank(loginName, "当前用户手机号为空,无法提交审核流");
|
||||||
|
param.setSubmitIdentity(loginName);
|
||||||
|
param.setLoginName(loginName);
|
||||||
|
String bizType = param.getBizType();
|
||||||
|
MKProcessCreateDTO mkParam = new MKProcessCreateDTO();
|
||||||
|
mkParam.setFormInstanceId(param.getFormInstanceId());
|
||||||
|
mkParam.setSubject(param.getSubject());
|
||||||
|
mkParam.setSubmitIdentity(loginName);
|
||||||
|
mkParam.setLoginName(loginName);
|
||||||
|
mkParam.setTemplateCode(param.getTemplateCode());
|
||||||
|
mkParam.setFormValues(param.getFormValues());
|
||||||
|
mkParam.setTempVarData(param.getTempVarData());
|
||||||
|
log.info("调用mk processSubmit 参数:{}", JSON.toJSONString(mkParam));
|
||||||
|
String processInstanceId = mkService.processSubmit(mkParam);
|
||||||
|
AssertUtils.notBlank(processInstanceId, "提交流程失败,未返回流程实例id");
|
||||||
|
|
||||||
|
Long bizId;
|
||||||
|
try {
|
||||||
|
bizId = Long.valueOf(param.getFormInstanceId());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new ServiceException("表单实例id格式不正确");
|
||||||
|
}
|
||||||
|
BusinessProcess businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery()
|
||||||
|
.eq(BusinessProcess::getBizId, bizId)
|
||||||
|
);
|
||||||
|
if (businessProcess == null) {
|
||||||
|
businessProcess = new BusinessProcess();
|
||||||
|
businessProcess.setBizId(bizId);
|
||||||
|
businessProcess.setProcessType(param.getTemplateCode());
|
||||||
|
businessProcess.setSubject(param.getSubject());
|
||||||
|
businessProcess.setPromoterId(AuthUtil.getUserId());
|
||||||
|
businessProcess.setPromoterName(AuthUtil.getNickName());
|
||||||
|
businessProcess.setPromoterLoginName(loginName);
|
||||||
|
businessProcess.setSubmitTime(new Date());
|
||||||
|
} else {
|
||||||
|
businessProcess.setProcessType(param.getTemplateCode());
|
||||||
|
if (StringUtil.isNotBlank(param.getSubject())) {
|
||||||
|
businessProcess.setSubject(param.getSubject());
|
||||||
|
}
|
||||||
|
businessProcess.setPromoterLoginName(loginName);
|
||||||
|
if (businessProcess.getSubmitTime() == null) {
|
||||||
|
businessProcess.setSubmitTime(new Date());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
businessProcess.setProcessInstanceId(processInstanceId);
|
||||||
|
businessProcess.setApproveStatus(ApproveStatusEnum.APPROVING.getValue());
|
||||||
|
this.saveOrUpdate(businessProcess);
|
||||||
|
this.getCurrentNodes(processInstanceId, loginName);
|
||||||
|
Object processInfo = this.getProcessInfo(processInstanceId, loginName);
|
||||||
|
this.syncBizFromProcessInfo(bizType, param.getFormInstanceId(), processInfo);
|
||||||
|
return processInstanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public boolean processDelete(String formInstanceId) {
|
||||||
|
AssertUtils.notBlank(formInstanceId, "表单实例id不能为空");
|
||||||
|
Long bizId;
|
||||||
|
try {
|
||||||
|
bizId = Long.valueOf(formInstanceId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new ServiceException("表单实例id格式不正确");
|
||||||
|
}
|
||||||
|
BusinessProcess businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery()
|
||||||
|
.eq(BusinessProcess::getBizId, bizId)
|
||||||
|
);
|
||||||
|
if (businessProcess == null || StringUtil.isBlank(businessProcess.getProcessInstanceId())) {
|
||||||
|
log.warn("客商驳回后删除流程跳过,未找到流程实例 formInstanceId={}", formInstanceId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String loginName = businessProcess.getPromoterLoginName();
|
||||||
|
if (StringUtil.isBlank(loginName)) {
|
||||||
|
loginName = resolveCurrentUserPhone();
|
||||||
|
}
|
||||||
|
AssertUtils.notBlank(loginName, "当前用户手机号为空,无法删除审核流");
|
||||||
|
log.info("调用mk processDelete processInstanceId={} loginName={} formInstanceId={}",
|
||||||
|
businessProcess.getProcessInstanceId(), loginName, formInstanceId);
|
||||||
|
boolean deleted = mkService.processDelete(businessProcess.getProcessInstanceId(), loginName);
|
||||||
|
if (!deleted) {
|
||||||
|
throw new ServiceException("删除MK流程失败");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<?> getCurrentNodes(String processInstanceId, String loginName) {
|
||||||
|
if (StringUtils.isBlank(processInstanceId)) {
|
||||||
|
log.warn("查询当前节点失败,processInstanceId为空");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
String resolvedLoginName = loginName;
|
||||||
|
if (StringUtils.isBlank(resolvedLoginName)) {
|
||||||
|
BusinessProcess businessProcess = this.getBusinessProcessByProcessInstanceId(processInstanceId);
|
||||||
|
resolvedLoginName = resolvePromoterLoginName(businessProcess, null);
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(resolvedLoginName)) {
|
||||||
|
log.warn("查询当前节点失败,loginName为空 processInstanceId={}", processInstanceId);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<MKNodeVO> currentNodes = mkService.getCurrentNodes(processInstanceId, resolvedLoginName);
|
||||||
|
log.info("获取流程当前节点详情 processInstanceId={} loginName={} result={}",
|
||||||
|
processInstanceId, resolvedLoginName, JSON.toJSONString(currentNodes));
|
||||||
|
return currentNodes == null ? Collections.emptyList() : currentNodes;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询当前节点异常 processInstanceId={} loginName={}", processInstanceId, resolvedLoginName, e);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getProcessInfo(String processInstanceId, String loginName) {
|
||||||
|
if (StringUtils.isBlank(processInstanceId)) {
|
||||||
|
log.warn("查询流程实例详情失败,processInstanceId为空");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String resolvedLoginName = loginName;
|
||||||
|
if (StringUtils.isBlank(resolvedLoginName)) {
|
||||||
|
BusinessProcess businessProcess = this.getBusinessProcessByProcessInstanceId(processInstanceId);
|
||||||
|
resolvedLoginName = resolvePromoterLoginName(businessProcess, null);
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(resolvedLoginName)) {
|
||||||
|
log.warn("查询流程实例详情失败,loginName为空 processInstanceId={}", processInstanceId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Object processInfo = mkService.getProcessInfo(processInstanceId, resolvedLoginName);
|
||||||
|
log.info("获取流程实例详情 processInstanceId={} loginName={} result={}",
|
||||||
|
processInstanceId, resolvedLoginName, JSON.toJSONString(processInfo));
|
||||||
|
return processInfo;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询流程实例详情异常 processInstanceId={} loginName={}", processInstanceId, resolvedLoginName, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncBizFromProcessInfo(String bizType, String formInstanceId, Object processInfo) {
|
||||||
|
if (StringUtils.isBlank(formInstanceId) || processInfo == null) {
|
||||||
|
log.warn("同步业务当前节点跳过,formInstanceId或流程实例详情为空 formInstanceId={}", formInstanceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Long bizId;
|
||||||
|
try {
|
||||||
|
bizId = Long.valueOf(formInstanceId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("同步业务当前节点失败,表单实例id不是数字:{}", formInstanceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String resolvedBizType = StringUtils.isBlank(bizType) ? "customer-archive" : bizType;
|
||||||
|
if ("customer-archive".equals(resolvedBizType)) {
|
||||||
|
this.syncCustomerArchiveFromProcessInfo(formInstanceId, processInfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MkProcessSyncDTO param = new MkProcessSyncDTO();
|
||||||
|
param.setBizType(resolvedBizType);
|
||||||
|
param.setId(bizId);
|
||||||
|
param.setAction("sync");
|
||||||
|
param.setProcessInfo(processInfo);
|
||||||
|
try {
|
||||||
|
FR<Boolean> result = mkProcessClient.apply(param);
|
||||||
|
log.info("同步业务当前节点完成 bizType={} bizId={} result={}",
|
||||||
|
resolvedBizType, bizId, JSON.toJSONString(result));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("同步业务当前节点异常 bizType={} bizId={}", resolvedBizType, bizId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncCustomerArchiveFromProcessInfo(String formInstanceId, Object processInfo) {
|
||||||
|
if (StringUtils.isBlank(formInstanceId) || processInfo == null) {
|
||||||
|
log.warn("同步客商当前节点跳过,formInstanceId或流程实例详情为空 formInstanceId={}", formInstanceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Long customerId;
|
||||||
|
try {
|
||||||
|
customerId = Long.valueOf(formInstanceId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("同步客商当前节点失败,表单实例id不是数字:{}", formInstanceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CustomerProcessNodeSyncDTO param = new CustomerProcessNodeSyncDTO();
|
||||||
|
param.setId(customerId);
|
||||||
|
param.setProcessInfo(processInfo);
|
||||||
|
param.setApprovalStatus("reviewing");
|
||||||
|
try {
|
||||||
|
FR<Boolean> result = customerArchiveClient.syncProcessNode(param);
|
||||||
|
log.info("同步客商当前节点完成 customerId={} result={}", customerId, JSON.toJSONString(result));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("同步客商当前节点异常 customerId={}", customerId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readMkNodeName(Object node) {
|
||||||
|
if (node instanceof MKNodeVO vo) {
|
||||||
|
return vo.getNodeName();
|
||||||
|
}
|
||||||
|
if (node instanceof Map<?, ?> map) {
|
||||||
|
Object value = map.get("nodeName");
|
||||||
|
return value == null ? null : String.valueOf(value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<String> readMkHandlerNames(Object node) {
|
||||||
|
List<MKNodeHandlerVO> handlers = null;
|
||||||
|
if (node instanceof MKNodeVO vo) {
|
||||||
|
handlers = vo.getNodeHandlers();
|
||||||
|
} else if (node instanceof Map<?, ?> map && map.get("nodeHandlers") instanceof List<?> list) {
|
||||||
|
return list.stream().map(item -> {
|
||||||
|
if (item instanceof MKNodeHandlerVO handler) {
|
||||||
|
return handler.getHandlerName();
|
||||||
|
}
|
||||||
|
if (item instanceof Map<?, ?> handlerMap) {
|
||||||
|
Object value = handlerMap.get("handlerName");
|
||||||
|
return value == null ? null : String.valueOf(value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (CollectionUtil.isEmpty(handlers)) {
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
return handlers.stream().map(MKNodeHandlerVO::getHandlerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从当前登录用户实体读取真实手机号(绕过接口返回脱敏)
|
||||||
|
*/
|
||||||
|
private String resolveCurrentUserPhone() {
|
||||||
|
Long userId = AuthUtil.getUserId();
|
||||||
|
if (userId != null) {
|
||||||
|
User user = userService.getById(userId);
|
||||||
|
if (user != null && StringUtil.isNotBlank(user.getPhone()) && !user.getPhone().contains("*")) {
|
||||||
|
return user.getPhone().trim();
|
||||||
|
}
|
||||||
|
if (user != null && StringUtil.isNotBlank(user.getAccount()) && user.getAccount().matches("^1\\d{10}$")) {
|
||||||
|
return user.getAccount().trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String account = AuthUtil.getUserAccount();
|
||||||
|
if (StringUtil.isNotBlank(account) && account.matches("^1\\d{10}$")) {
|
||||||
|
return account.trim();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public String updateBusinessProcessStatus(BusinessProcessUpdateDTO param) {
|
public String updateBusinessProcessStatus(BusinessProcessUpdateDTO param) {
|
||||||
|
|||||||
+33
-4
@@ -50,8 +50,10 @@ import org.springblade.system.pojo.entity.Dept;
|
|||||||
import org.springblade.system.pojo.entity.User;
|
import org.springblade.system.pojo.entity.User;
|
||||||
import org.springblade.system.pojo.enums.DictEnum;
|
import org.springblade.system.pojo.enums.DictEnum;
|
||||||
import org.springblade.system.pojo.vo.DeptVO;
|
import org.springblade.system.pojo.vo.DeptVO;
|
||||||
|
import org.springblade.system.pojo.vo.OaOrgSyncPageVO;
|
||||||
import org.springblade.system.pojo.vo.UserVO;
|
import org.springblade.system.pojo.vo.UserVO;
|
||||||
import org.springblade.system.service.IDeptService;
|
import org.springblade.system.service.IDeptService;
|
||||||
|
import org.springblade.system.service.IOASyncService;
|
||||||
import org.springblade.system.wrapper.DeptWrapper;
|
import org.springblade.system.wrapper.DeptWrapper;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@@ -73,6 +75,7 @@ import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE;
|
|||||||
public class DeptController extends BladeController {
|
public class DeptController extends BladeController {
|
||||||
|
|
||||||
private final IDeptService deptService;
|
private final IDeptService deptService;
|
||||||
|
private final IOASyncService oaSyncService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 详情
|
* 详情
|
||||||
@@ -170,12 +173,38 @@ public class DeptController extends BladeController {
|
|||||||
return R.data(deptService.syncIamOrganizations());
|
return R.data(deptService.syncIamOrganizations());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从OA按页同步公司
|
||||||
|
*/
|
||||||
|
@IsAdmin
|
||||||
|
@PostMapping("/sync-oa-company")
|
||||||
|
@ApiOperationSupport(order = 8)
|
||||||
|
@Operation(summary = "同步OA公司")
|
||||||
|
public R<OaOrgSyncPageVO> syncOaCompany(
|
||||||
|
@RequestParam(defaultValue = "1") Integer current,
|
||||||
|
@RequestParam(defaultValue = "20") Integer size) {
|
||||||
|
return R.data(oaSyncService.syncCompanyPage(current, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从OA按页同步部门(需先完成公司同步)
|
||||||
|
*/
|
||||||
|
@IsAdmin
|
||||||
|
@PostMapping("/sync-oa-department")
|
||||||
|
@ApiOperationSupport(order = 9)
|
||||||
|
@Operation(summary = "同步OA部门")
|
||||||
|
public R<OaOrgSyncPageVO> syncOaDepartment(
|
||||||
|
@RequestParam(defaultValue = "1") Integer current,
|
||||||
|
@RequestParam(defaultValue = "20") Integer size) {
|
||||||
|
return R.data(oaSyncService.syncDepartmentPage(current, size));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除
|
* 删除
|
||||||
*/
|
*/
|
||||||
@IsAdmin
|
@IsAdmin
|
||||||
@PostMapping("/remove")
|
@PostMapping("/remove")
|
||||||
@ApiOperationSupport(order = 8)
|
@ApiOperationSupport(order = 10)
|
||||||
@Operation(summary = "删除", description = "传入ids")
|
@Operation(summary = "删除", description = "传入ids")
|
||||||
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
|
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
|
||||||
CacheUtil.clear(SYS_CACHE);
|
CacheUtil.clear(SYS_CACHE);
|
||||||
@@ -188,7 +217,7 @@ public class DeptController extends BladeController {
|
|||||||
*/
|
*/
|
||||||
@PreAuth(AuthConstant.PERMIT_ALL)
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
@GetMapping("/select")
|
@GetMapping("/select")
|
||||||
@ApiOperationSupport(order = 9)
|
@ApiOperationSupport(order = 11)
|
||||||
@Operation(summary = "下拉数据源", description = "传入id集合")
|
@Operation(summary = "下拉数据源", description = "传入id集合")
|
||||||
public R<List<Dept>> select(Long userId, String deptId) {
|
public R<List<Dept>> select(Long userId, String deptId) {
|
||||||
if (Func.isNotEmpty(userId)) {
|
if (Func.isNotEmpty(userId)) {
|
||||||
@@ -205,7 +234,7 @@ public class DeptController extends BladeController {
|
|||||||
*/
|
*/
|
||||||
@PreAuth(AuthConstant.PERMIT_ALL)
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
@GetMapping("/platform-company-select")
|
@GetMapping("/platform-company-select")
|
||||||
@ApiOperationSupport(order = 10)
|
@ApiOperationSupport(order = 12)
|
||||||
@Operation(summary = "平台公司下拉", description = "返回是否平台公司=是的部门列表")
|
@Operation(summary = "平台公司下拉", description = "返回是否平台公司=是的部门列表")
|
||||||
public R<List<Dept>> platformCompanySelect() {
|
public R<List<Dept>> platformCompanySelect() {
|
||||||
return R.data(deptService.listPlatformCompany());
|
return R.data(deptService.listPlatformCompany());
|
||||||
@@ -216,7 +245,7 @@ public class DeptController extends BladeController {
|
|||||||
*/
|
*/
|
||||||
@IsAdmin
|
@IsAdmin
|
||||||
@GetMapping("/dept-leader-info")
|
@GetMapping("/dept-leader-info")
|
||||||
@ApiOperationSupport(order = 11)
|
@ApiOperationSupport(order = 13)
|
||||||
@Operation(summary = "获取部门的主管信息", description = "传入deptId")
|
@Operation(summary = "获取部门的主管信息", description = "传入deptId")
|
||||||
public R<List<UserVO>> deptLeaderInfo(@Parameter(description = "部门id", required = true) @RequestParam Long deptId) {
|
public R<List<UserVO>> deptLeaderInfo(@Parameter(description = "部门id", required = true) @RequestParam Long deptId) {
|
||||||
List<UserVO> list = deptService.deptLeaderInfo(deptId);
|
List<UserVO> list = deptService.deptLeaderInfo(deptId);
|
||||||
|
|||||||
+1
-1
@@ -169,7 +169,7 @@ public class UserController {
|
|||||||
@Operation(summary = "同步OA人员")
|
@Operation(summary = "同步OA人员")
|
||||||
public R<OaPersonSyncPageVO> syncIamAccounts(
|
public R<OaPersonSyncPageVO> syncIamAccounts(
|
||||||
@RequestParam(defaultValue = "1") Integer current,
|
@RequestParam(defaultValue = "1") Integer current,
|
||||||
@RequestParam(defaultValue = "50") Integer size) {
|
@RequestParam(defaultValue = "20") Integer size) {
|
||||||
return R.data(oaSyncService.syncPersonFromUserList(current, size));
|
return R.data(oaSyncService.syncPersonFromUserList(current, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
@@ -13,6 +13,7 @@
|
|||||||
<result column="update_time" property="updateTime"/>
|
<result column="update_time" property="updateTime"/>
|
||||||
<result column="status" property="status"/>
|
<result column="status" property="status"/>
|
||||||
<result column="is_deleted" property="isDeleted"/>
|
<result column="is_deleted" property="isDeleted"/>
|
||||||
|
<result column="unit_code" property="unitCode"/>
|
||||||
<result column="unit_name" property="unitName"/>
|
<result column="unit_name" property="unitName"/>
|
||||||
<result column="dimension" property="dimension"/>
|
<result column="dimension" property="dimension"/>
|
||||||
<result column="remark" property="remark"/>
|
<result column="remark" property="remark"/>
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
mmu.update_time,
|
mmu.update_time,
|
||||||
mmu.status,
|
mmu.status,
|
||||||
mmu.is_deleted,
|
mmu.is_deleted,
|
||||||
|
mmu.unit_code,
|
||||||
mmu.unit_name,
|
mmu.unit_name,
|
||||||
mmu.dimension,
|
mmu.dimension,
|
||||||
mmu.remark
|
mmu.remark
|
||||||
@@ -39,6 +41,10 @@
|
|||||||
LEFT JOIN blade_user uu ON uu.id = mmu.update_user
|
LEFT JOIN blade_user uu ON uu.id = mmu.update_user
|
||||||
WHERE
|
WHERE
|
||||||
mmu.is_deleted = 0
|
mmu.is_deleted = 0
|
||||||
|
<if test="measurementUnit.unitCode != null and measurementUnit.unitCode != ''">
|
||||||
|
<bind name="unitCodeLike" value="'%' + measurementUnit.unitCode + '%'"/>
|
||||||
|
AND mmu.unit_code LIKE #{unitCodeLike}
|
||||||
|
</if>
|
||||||
<if test="measurementUnit.unitName != null and measurementUnit.unitName != ''">
|
<if test="measurementUnit.unitName != null and measurementUnit.unitName != ''">
|
||||||
<bind name="unitNameLike" value="'%' + measurementUnit.unitName + '%'"/>
|
<bind name="unitNameLike" value="'%' + measurementUnit.unitName + '%'"/>
|
||||||
AND mmu.unit_name LIKE #{unitNameLike}
|
AND mmu.unit_name LIKE #{unitNameLike}
|
||||||
|
|||||||
+19
@@ -1,5 +1,6 @@
|
|||||||
package org.springblade.system.service;
|
package org.springblade.system.service;
|
||||||
|
|
||||||
|
import org.springblade.system.pojo.vo.OaOrgSyncPageVO;
|
||||||
import org.springblade.system.pojo.vo.OaPersonSyncPageVO;
|
import org.springblade.system.pojo.vo.OaPersonSyncPageVO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,4 +37,22 @@ public interface IOASyncService {
|
|||||||
* @return 本页同步结果
|
* @return 本页同步结果
|
||||||
*/
|
*/
|
||||||
OaPersonSyncPageVO syncPersonFromUserList(int current, int size);
|
OaPersonSyncPageVO syncPersonFromUserList(int current, int size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按页从 OA 公司接口同步公司
|
||||||
|
*
|
||||||
|
* @param current 当前页,从 1 开始
|
||||||
|
* @param size 每页条数
|
||||||
|
* @return 本页同步结果
|
||||||
|
*/
|
||||||
|
OaOrgSyncPageVO syncCompanyPage(int current, int size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按页从 OA 部门接口同步部门;最后一页完成后更新祖级列表
|
||||||
|
*
|
||||||
|
* @param current 当前页,从 1 开始
|
||||||
|
* @param size 每页条数
|
||||||
|
* @return 本页同步结果
|
||||||
|
*/
|
||||||
|
OaOrgSyncPageVO syncDepartmentPage(int current, int size);
|
||||||
}
|
}
|
||||||
|
|||||||
+21
@@ -46,6 +46,7 @@ public class MeasurementUnitServiceImpl extends BaseServiceImpl<MeasurementUnitM
|
|||||||
|
|
||||||
private static final int STATUS_ENABLED = 1;
|
private static final int STATUS_ENABLED = 1;
|
||||||
private static final int STATUS_DISABLED = 2;
|
private static final int STATUS_DISABLED = 2;
|
||||||
|
private static final int UNIT_CODE_MAX_LENGTH = 50;
|
||||||
private static final int UNIT_NAME_MAX_LENGTH = 50;
|
private static final int UNIT_NAME_MAX_LENGTH = 50;
|
||||||
private static final int DIMENSION_MAX_LENGTH = 20;
|
private static final int DIMENSION_MAX_LENGTH = 20;
|
||||||
private static final int REMARK_MAX_LENGTH = 200;
|
private static final int REMARK_MAX_LENGTH = 200;
|
||||||
@@ -85,6 +86,7 @@ public class MeasurementUnitServiceImpl extends BaseServiceImpl<MeasurementUnitM
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void prepare(MeasurementUnit measurementUnit) {
|
private void prepare(MeasurementUnit measurementUnit) {
|
||||||
|
measurementUnit.setUnitCode(trimToEmpty(measurementUnit.getUnitCode()));
|
||||||
measurementUnit.setUnitName(trimToEmpty(measurementUnit.getUnitName()));
|
measurementUnit.setUnitName(trimToEmpty(measurementUnit.getUnitName()));
|
||||||
measurementUnit.setDimension(trimToEmpty(measurementUnit.getDimension()));
|
measurementUnit.setDimension(trimToEmpty(measurementUnit.getDimension()));
|
||||||
measurementUnit.setRemark(trimToNull(measurementUnit.getRemark()));
|
measurementUnit.setRemark(trimToNull(measurementUnit.getRemark()));
|
||||||
@@ -94,6 +96,12 @@ public class MeasurementUnitServiceImpl extends BaseServiceImpl<MeasurementUnitM
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void validate(MeasurementUnit measurementUnit) {
|
private void validate(MeasurementUnit measurementUnit) {
|
||||||
|
if (Func.isEmpty(measurementUnit.getUnitCode())) {
|
||||||
|
throw new ServiceException("计量单位编码不能为空");
|
||||||
|
}
|
||||||
|
if (measurementUnit.getUnitCode().length() > UNIT_CODE_MAX_LENGTH) {
|
||||||
|
throw new ServiceException("计量单位编码不能超过50字");
|
||||||
|
}
|
||||||
if (Func.isEmpty(measurementUnit.getUnitName())) {
|
if (Func.isEmpty(measurementUnit.getUnitName())) {
|
||||||
throw new ServiceException("计量单位不能为空");
|
throw new ServiceException("计量单位不能为空");
|
||||||
}
|
}
|
||||||
@@ -115,9 +123,22 @@ public class MeasurementUnitServiceImpl extends BaseServiceImpl<MeasurementUnitM
|
|||||||
&& !Objects.equals(measurementUnit.getStatus(), STATUS_DISABLED)) {
|
&& !Objects.equals(measurementUnit.getStatus(), STATUS_DISABLED)) {
|
||||||
throw new ServiceException("启停状态不正确");
|
throw new ServiceException("启停状态不正确");
|
||||||
}
|
}
|
||||||
|
validateUniqueUnitCode(measurementUnit);
|
||||||
validateUniqueUnitName(measurementUnit);
|
validateUniqueUnitName(measurementUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateUniqueUnitCode(MeasurementUnit measurementUnit) {
|
||||||
|
LambdaQueryWrapper<MeasurementUnit> queryWrapper = Wrappers.<MeasurementUnit>lambdaQuery()
|
||||||
|
.eq(MeasurementUnit::getUnitCode, measurementUnit.getUnitCode())
|
||||||
|
.eq(MeasurementUnit::getIsDeleted, 0);
|
||||||
|
if (Func.isNotEmpty(measurementUnit.getId())) {
|
||||||
|
queryWrapper.ne(MeasurementUnit::getId, measurementUnit.getId());
|
||||||
|
}
|
||||||
|
if (count(queryWrapper) > 0L) {
|
||||||
|
throw new ServiceException("该计量单位编码已存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validateUniqueUnitName(MeasurementUnit measurementUnit) {
|
private void validateUniqueUnitName(MeasurementUnit measurementUnit) {
|
||||||
LambdaQueryWrapper<MeasurementUnit> queryWrapper = Wrappers.<MeasurementUnit>lambdaQuery()
|
LambdaQueryWrapper<MeasurementUnit> queryWrapper = Wrappers.<MeasurementUnit>lambdaQuery()
|
||||||
.eq(MeasurementUnit::getUnitName, measurementUnit.getUnitName())
|
.eq(MeasurementUnit::getUnitName, measurementUnit.getUnitName())
|
||||||
|
|||||||
+216
-31
@@ -18,6 +18,7 @@ import org.springblade.system.log.ComposeLogUtil;
|
|||||||
import org.springblade.system.pojo.entity.*;
|
import org.springblade.system.pojo.entity.*;
|
||||||
import org.springblade.system.pojo.enums.DataSync;
|
import org.springblade.system.pojo.enums.DataSync;
|
||||||
import org.springblade.system.pojo.enums.DeptCategory;
|
import org.springblade.system.pojo.enums.DeptCategory;
|
||||||
|
import org.springblade.system.pojo.vo.OaOrgSyncPageVO;
|
||||||
import org.springblade.system.pojo.vo.OaPersonSyncPageVO;
|
import org.springblade.system.pojo.vo.OaPersonSyncPageVO;
|
||||||
import org.springblade.system.service.*;
|
import org.springblade.system.service.*;
|
||||||
import org.springblade.system.util.DataSyncRecordUtils;
|
import org.springblade.system.util.DataSyncRecordUtils;
|
||||||
@@ -124,6 +125,28 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public OaOrgSyncPageVO syncCompanyPage(int current, int size) {
|
||||||
|
try {
|
||||||
|
ComposeLogUtil.addLog(log);
|
||||||
|
return this.syncCompanyFromOaPage(current, size);
|
||||||
|
} finally {
|
||||||
|
ComposeLogUtil.removeLastLog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public OaOrgSyncPageVO syncDepartmentPage(int current, int size) {
|
||||||
|
try {
|
||||||
|
ComposeLogUtil.addLog(log);
|
||||||
|
return this.syncDepartmentFromOaPage(current, size);
|
||||||
|
} finally {
|
||||||
|
ComposeLogUtil.removeLastLog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步并记录
|
* 同步并记录
|
||||||
*
|
*
|
||||||
@@ -166,20 +189,15 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
// 未处理的数据
|
// 未处理的数据
|
||||||
List<Dept> notHandleList = new ArrayList<>();
|
List<Dept> notHandleList = new ArrayList<>();
|
||||||
// 1. 设置查询参数
|
// 1. 设置查询参数
|
||||||
OACompanySearch companySearch = new OACompanySearch();
|
OACompanySearch companySearch = buildCompanySearch(startTime);
|
||||||
companySearch.setCurPage(1);
|
|
||||||
if (startTime != null) {
|
|
||||||
// 开始时间不为空,设置修改时间参数
|
|
||||||
companySearch.setModified(DateUtil.format(startTime, DateUtil.PATTERN_DATETIME));
|
|
||||||
}
|
|
||||||
// 2. 分页查询并处理数据
|
// 2. 分页查询并处理数据
|
||||||
OAUtils.pageSyncHandler(companySearch, param -> oaClient.queryCompanyPage(new OASearch<>(param)), response -> {
|
OAUtils.pageSyncHandler(companySearch, param -> oaClient.queryCompanyPage(new OASearch<>(param)), response -> {
|
||||||
ComposeLogUtil.getLastLog().error("调用OA接口查询公司信息失败 {}", JSON.toJSONString(response));
|
ComposeLogUtil.getLastLog().error("调用OA接口查询公司信息失败 {}", JSON.toJSONString(response));
|
||||||
return new ServiceException("调用OA接口查询公司信息失败");
|
return new ServiceException("调用OA接口查询公司信息失败");
|
||||||
}, 10000, ComposeLogUtil.getLastLog()::info).accept(list -> {
|
}, 10000, ComposeLogUtil.getLastLog()::info).accept(list -> {
|
||||||
// 处理数据
|
// 处理数据
|
||||||
List<Dept> deptList = handleCompany(list);
|
OrgSyncCount syncCount = handleCompany(list);
|
||||||
notHandleList.addAll(deptList);
|
notHandleList.addAll(syncCount.getNotHandledList());
|
||||||
});
|
});
|
||||||
// 3. 未处理的数据
|
// 3. 未处理的数据
|
||||||
if (CollectionUtil.isNotEmpty(notHandleList)) {
|
if (CollectionUtil.isNotEmpty(notHandleList)) {
|
||||||
@@ -203,21 +221,15 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
// 未处理的数据
|
// 未处理的数据
|
||||||
List<Dept> notHandleList = new ArrayList<>();
|
List<Dept> notHandleList = new ArrayList<>();
|
||||||
// 1. 设置查询参数
|
// 1. 设置查询参数
|
||||||
OADepartmentSearch departmentSearch = new OADepartmentSearch();
|
OADepartmentSearch departmentSearch = buildDepartmentSearch(startTime, subCompanyIds);
|
||||||
departmentSearch.setCurPage(1);
|
|
||||||
departmentSearch.setSubcompanyid1(subCompanyIds);
|
|
||||||
if (startTime != null) {
|
|
||||||
// 开始时间不为空,设置修改时间参数
|
|
||||||
departmentSearch.setModified(DateUtil.format(startTime, DateUtil.PATTERN_DATETIME));
|
|
||||||
}
|
|
||||||
// 2. 分页查询并处理数据
|
// 2. 分页查询并处理数据
|
||||||
OAUtils.pageSyncHandler(departmentSearch, param -> oaClient.queryDepartmentPage(new OASearch<>(param)), response -> {
|
OAUtils.pageSyncHandler(departmentSearch, param -> oaClient.queryDepartmentPage(new OASearch<>(param)), response -> {
|
||||||
ComposeLogUtil.getLastLog().error("调用OA接口查询部门信息失败 {}", JSON.toJSONString(response));
|
ComposeLogUtil.getLastLog().error("调用OA接口查询部门信息失败 {}", JSON.toJSONString(response));
|
||||||
return new ServiceException("调用OA接口查询部门信息失败");
|
return new ServiceException("调用OA接口查询部门信息失败");
|
||||||
}, 10000, ComposeLogUtil.getLastLog()::info).accept(list -> {
|
}, 10000, ComposeLogUtil.getLastLog()::info).accept(list -> {
|
||||||
// 处理数据
|
// 处理数据
|
||||||
List<Dept> deptList = handleDept(list);
|
OrgSyncCount syncCount = handleDept(list);
|
||||||
notHandleList.addAll(deptList);
|
notHandleList.addAll(syncCount.getNotHandledList());
|
||||||
});
|
});
|
||||||
// 3. 未处理的数据
|
// 3. 未处理的数据
|
||||||
if (CollectionUtil.isNotEmpty(notHandleList)) {
|
if (CollectionUtil.isNotEmpty(notHandleList)) {
|
||||||
@@ -266,7 +278,7 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
*/
|
*/
|
||||||
private OaPersonSyncPageVO syncPersonFromOaPage(int current, int size) {
|
private OaPersonSyncPageVO syncPersonFromOaPage(int current, int size) {
|
||||||
int pageNo = current < 1 ? 1 : current;
|
int pageNo = current < 1 ? 1 : current;
|
||||||
int pageSize = size < 1 ? 50 : Math.min(size, 200);
|
int pageSize = size < 1 ? 20 : Math.min(size, 200);
|
||||||
OAPersonSearch personSearch = buildPersonSearch(null);
|
OAPersonSearch personSearch = buildPersonSearch(null);
|
||||||
personSearch.setCurPage(pageNo);
|
personSearch.setCurPage(pageNo);
|
||||||
personSearch.setPageSize(pageSize);
|
personSearch.setPageSize(pageSize);
|
||||||
@@ -300,6 +312,139 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
return pageVO;
|
return pageVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按页从 OA 公司接口同步公司
|
||||||
|
*
|
||||||
|
* @param current 当前页
|
||||||
|
* @param size 每页条数
|
||||||
|
* @return 本页同步结果
|
||||||
|
*/
|
||||||
|
private OaOrgSyncPageVO syncCompanyFromOaPage(int current, int size) {
|
||||||
|
int pageNo = current < 1 ? 1 : current;
|
||||||
|
int pageSize = size < 1 ? 20 : Math.min(size, 200);
|
||||||
|
OACompanySearch companySearch = buildCompanySearch(null);
|
||||||
|
companySearch.setCurPage(pageNo);
|
||||||
|
companySearch.setPageSize(pageSize);
|
||||||
|
OAResponse<OACompanyResponse> oaResponse = oaClient.queryCompanyPage(new OASearch<>(companySearch));
|
||||||
|
if (oaResponse == null || !OAConstant.OA_SUCCESS_CODE.equals(oaResponse.getCode()) || oaResponse.getData() == null) {
|
||||||
|
ComposeLogUtil.getLastLog().error("调用OA接口查询公司信息失败 {}", JSON.toJSONString(oaResponse));
|
||||||
|
throw new ServiceException("调用OA接口查询公司信息失败");
|
||||||
|
}
|
||||||
|
OAResponseData<OACompanyResponse> responseData = oaResponse.getData();
|
||||||
|
List<OACompanyResponse> oaCompanies = responseData.getDataList() == null
|
||||||
|
? Collections.emptyList() : responseData.getDataList();
|
||||||
|
long totalSize = responseData.getTotalSize() == null ? 0L : responseData.getTotalSize();
|
||||||
|
OrgSyncCount syncCount = handleCompany(oaCompanies);
|
||||||
|
if (CollectionUtil.isNotEmpty(syncCount.getNotHandledList())) {
|
||||||
|
ComposeLogUtil.getLastLog().warn("同步公司,本页未处理数据:{}", JSON.toJSONString(syncCount.getNotHandledList()));
|
||||||
|
}
|
||||||
|
CacheUtil.clear(SYS_CACHE);
|
||||||
|
CacheUtil.clear(SYS_CACHE, Boolean.FALSE);
|
||||||
|
OaOrgSyncPageVO pageVO = buildOrgSyncPageVO("company", pageNo, pageSize, totalSize, oaCompanies.size(), syncCount);
|
||||||
|
ComposeLogUtil.getLastLog().info("OA公司分页同步完成 {}/{},成功{},跳过{}",
|
||||||
|
pageNo, totalSize, syncCount.getSyncedCount(), syncCount.getSkippedCount());
|
||||||
|
return pageVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按页从 OA 部门接口同步部门
|
||||||
|
*
|
||||||
|
* @param current 当前页
|
||||||
|
* @param size 每页条数
|
||||||
|
* @return 本页同步结果
|
||||||
|
*/
|
||||||
|
private OaOrgSyncPageVO syncDepartmentFromOaPage(int current, int size) {
|
||||||
|
int pageNo = current < 1 ? 1 : current;
|
||||||
|
int pageSize = size < 1 ? 20 : Math.min(size, 200);
|
||||||
|
String subCompanyIds = getSubCompanyIds();
|
||||||
|
if (StringUtils.isEmpty(subCompanyIds)) {
|
||||||
|
ComposeLogUtil.getLastLog().warn("未查询到子公司查询参数,跳过部门同步");
|
||||||
|
OaOrgSyncPageVO emptyPageVO = buildOrgSyncPageVO("department", pageNo, pageSize, 0L, 0, OrgSyncCount.empty());
|
||||||
|
emptyPageVO.setFinished(true);
|
||||||
|
return emptyPageVO;
|
||||||
|
}
|
||||||
|
OADepartmentSearch departmentSearch = buildDepartmentSearch(null, subCompanyIds);
|
||||||
|
departmentSearch.setCurPage(pageNo);
|
||||||
|
departmentSearch.setPageSize(pageSize);
|
||||||
|
OAResponse<OADepartmentResponse> oaResponse = oaClient.queryDepartmentPage(new OASearch<>(departmentSearch));
|
||||||
|
if (oaResponse == null || !OAConstant.OA_SUCCESS_CODE.equals(oaResponse.getCode()) || oaResponse.getData() == null) {
|
||||||
|
ComposeLogUtil.getLastLog().error("调用OA接口查询部门信息失败 {}", JSON.toJSONString(oaResponse));
|
||||||
|
throw new ServiceException("调用OA接口查询部门信息失败");
|
||||||
|
}
|
||||||
|
OAResponseData<OADepartmentResponse> responseData = oaResponse.getData();
|
||||||
|
List<OADepartmentResponse> oaDepartments = responseData.getDataList() == null
|
||||||
|
? Collections.emptyList() : responseData.getDataList();
|
||||||
|
long totalSize = responseData.getTotalSize() == null ? 0L : responseData.getTotalSize();
|
||||||
|
OrgSyncCount syncCount = handleDept(oaDepartments);
|
||||||
|
if (CollectionUtil.isNotEmpty(syncCount.getNotHandledList())) {
|
||||||
|
ComposeLogUtil.getLastLog().warn("同步部门,本页未处理数据:{}", JSON.toJSONString(syncCount.getNotHandledList()));
|
||||||
|
}
|
||||||
|
CacheUtil.clear(SYS_CACHE);
|
||||||
|
CacheUtil.clear(SYS_CACHE, Boolean.FALSE);
|
||||||
|
OaOrgSyncPageVO pageVO = buildOrgSyncPageVO("department", pageNo, pageSize, totalSize, oaDepartments.size(), syncCount);
|
||||||
|
if (Boolean.TRUE.equals(pageVO.getFinished())) {
|
||||||
|
// 部门同步完成后更新祖级列表
|
||||||
|
deptService.updateAncestors(null);
|
||||||
|
}
|
||||||
|
ComposeLogUtil.getLastLog().info("OA部门分页同步完成 {}/{},成功{},跳过{}",
|
||||||
|
pageNo, totalSize, syncCount.getSyncedCount(), syncCount.getSkippedCount());
|
||||||
|
return pageVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装组织分页同步结果
|
||||||
|
*/
|
||||||
|
private OaOrgSyncPageVO buildOrgSyncPageVO(String stage, int pageNo, int pageSize, long totalSize,
|
||||||
|
int fetchedCount, OrgSyncCount syncCount) {
|
||||||
|
OaOrgSyncPageVO pageVO = new OaOrgSyncPageVO();
|
||||||
|
pageVO.setStage(stage);
|
||||||
|
pageVO.setCurrent(pageNo);
|
||||||
|
pageVO.setSize(pageSize);
|
||||||
|
pageVO.setTotal(totalSize);
|
||||||
|
pageVO.setFetchedCount(fetchedCount);
|
||||||
|
pageVO.setSyncedCount(syncCount.getSyncedCount());
|
||||||
|
pageVO.setSkippedCount(syncCount.getSkippedCount());
|
||||||
|
boolean finished = fetchedCount == 0
|
||||||
|
|| fetchedCount < pageSize
|
||||||
|
|| (long) pageNo * pageSize >= totalSize;
|
||||||
|
pageVO.setFinished(finished);
|
||||||
|
return pageVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装 OA 公司分页查询参数
|
||||||
|
*
|
||||||
|
* @param startTime 增量查询开始时间
|
||||||
|
* @return 查询参数
|
||||||
|
*/
|
||||||
|
private OACompanySearch buildCompanySearch(Date startTime) {
|
||||||
|
OACompanySearch companySearch = new OACompanySearch();
|
||||||
|
companySearch.setCurPage(1);
|
||||||
|
companySearch.setPageSize(20);
|
||||||
|
if (startTime != null) {
|
||||||
|
companySearch.setModified(DateUtil.format(startTime, DateUtil.PATTERN_DATETIME));
|
||||||
|
}
|
||||||
|
return companySearch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装 OA 部门分页查询参数
|
||||||
|
*
|
||||||
|
* @param startTime 增量查询开始时间
|
||||||
|
* @param subCompanyIds 子公司 id 列表
|
||||||
|
* @return 查询参数
|
||||||
|
*/
|
||||||
|
private OADepartmentSearch buildDepartmentSearch(Date startTime, String subCompanyIds) {
|
||||||
|
OADepartmentSearch departmentSearch = new OADepartmentSearch();
|
||||||
|
departmentSearch.setCurPage(1);
|
||||||
|
departmentSearch.setPageSize(20);
|
||||||
|
departmentSearch.setSubcompanyid1(subCompanyIds);
|
||||||
|
if (startTime != null) {
|
||||||
|
departmentSearch.setModified(DateUtil.format(startTime, DateUtil.PATTERN_DATETIME));
|
||||||
|
}
|
||||||
|
return departmentSearch;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组装 OA 人员分页查询参数
|
* 组装 OA 人员分页查询参数
|
||||||
*
|
*
|
||||||
@@ -309,7 +454,7 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
private OAPersonSearch buildPersonSearch(Date startTime) {
|
private OAPersonSearch buildPersonSearch(Date startTime) {
|
||||||
OAPersonSearch personSearch = new OAPersonSearch();
|
OAPersonSearch personSearch = new OAPersonSearch();
|
||||||
personSearch.setCurPage(1);
|
personSearch.setCurPage(1);
|
||||||
personSearch.setPageSize(200);
|
personSearch.setPageSize(20);
|
||||||
personSearch.setCreated("");
|
personSearch.setCreated("");
|
||||||
personSearch.setWorkcode("");
|
personSearch.setWorkcode("");
|
||||||
personSearch.setSubcompanyid1("");
|
personSearch.setSubcompanyid1("");
|
||||||
@@ -325,12 +470,11 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
/**
|
/**
|
||||||
* 处理oa公司
|
* 处理oa公司
|
||||||
* @param oaCompanies
|
* @param oaCompanies
|
||||||
* @return 未处理的数据
|
* @return 同步统计
|
||||||
*/
|
*/
|
||||||
private List<Dept> handleCompany(List<OACompanyResponse> oaCompanies) {
|
private OrgSyncCount handleCompany(List<OACompanyResponse> oaCompanies) {
|
||||||
if (CollectionUtil.isEmpty(oaCompanies)) {
|
if (CollectionUtil.isEmpty(oaCompanies)) {
|
||||||
// 数据为空,直接返回
|
return OrgSyncCount.empty();
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
// 获取需要的公司名称
|
// 获取需要的公司名称
|
||||||
Set<String> companyNames = getCompanyNames();
|
Set<String> companyNames = getCompanyNames();
|
||||||
@@ -340,30 +484,36 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
.filter(company -> companyNames.contains(company.getSubcompanyname()))
|
.filter(company -> companyNames.contains(company.getSubcompanyname()))
|
||||||
.map(deptConvert::company2dept)
|
.map(deptConvert::company2dept)
|
||||||
.toList();
|
.toList();
|
||||||
|
int filteredSkipCount = oaCompanies.size() - allParam.size();
|
||||||
|
if (CollectionUtil.isEmpty(allParam)) {
|
||||||
|
return new OrgSyncCount(0, filteredSkipCount, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
// 查询数据库的部门,转换成map
|
// 查询数据库的部门,转换成map
|
||||||
Map<String, Long> deptMap = getAllCompanyDeptMap();
|
Map<String, Long> deptMap = getAllCompanyDeptMap();
|
||||||
|
|
||||||
// 处理部门
|
// 处理部门
|
||||||
return handleDept(allParam, deptMap, DeptCategory.COMPANY);
|
List<Dept> notHandledList = handleDept(allParam, deptMap, DeptCategory.COMPANY);
|
||||||
|
int syncedCount = allParam.size() - notHandledList.size();
|
||||||
|
int skippedCount = filteredSkipCount + notHandledList.size();
|
||||||
|
return new OrgSyncCount(syncedCount, skippedCount, notHandledList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理oa部门
|
* 处理oa部门
|
||||||
* @param oaDepts
|
* @param oaDepts
|
||||||
* @return 未处理的数据
|
* @return 同步统计
|
||||||
*/
|
*/
|
||||||
private List<Dept> handleDept(List<OADepartmentResponse> oaDepts) {
|
private OrgSyncCount handleDept(List<OADepartmentResponse> oaDepts) {
|
||||||
if (CollectionUtil.isEmpty(oaDepts)) {
|
if (CollectionUtil.isEmpty(oaDepts)) {
|
||||||
// 数据为空,直接返回
|
return OrgSyncCount.empty();
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
// 查询所有公司的编码和id的map
|
// 查询所有公司的编码和id的map
|
||||||
Map<String, Long> companyDeptMap = getAllCompanyDeptMap();
|
Map<String, Long> companyDeptMap = getAllCompanyDeptMap();
|
||||||
// 根公司id
|
// 根公司id
|
||||||
String rootCompanyId = getRootCompanyId();
|
String rootCompanyId = getRootCompanyId();
|
||||||
if (rootCompanyId == null) {
|
if (rootCompanyId == null) {
|
||||||
return Collections.emptyList();
|
return new OrgSyncCount(0, oaDepts.size(), Collections.emptyList());
|
||||||
}
|
}
|
||||||
// 根公司下要同步的部门名称
|
// 根公司下要同步的部门名称
|
||||||
Set<String> rootCompanyDeptNames = getRootCompanyDeptNames();
|
Set<String> rootCompanyDeptNames = getRootCompanyDeptNames();
|
||||||
@@ -373,8 +523,9 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
.filter(oaDept -> !rootCompanyId.equals(oaDept.getSubcompanyid1()) || (OAConstant.ROOT_COMPANY_ID.equals(oaDept.getSupdepid()) && rootCompanyDeptNames.contains(oaDept.getDepartmentname())))
|
.filter(oaDept -> !rootCompanyId.equals(oaDept.getSubcompanyid1()) || (OAConstant.ROOT_COMPANY_ID.equals(oaDept.getSupdepid()) && rootCompanyDeptNames.contains(oaDept.getDepartmentname())))
|
||||||
.map(dept -> deptConvert.dept2dept(dept, companyDeptMap))
|
.map(dept -> deptConvert.dept2dept(dept, companyDeptMap))
|
||||||
.toList();
|
.toList();
|
||||||
|
int filteredSkipCount = oaDepts.size() - allParam.size();
|
||||||
if (CollectionUtil.isEmpty(allParam)) {
|
if (CollectionUtil.isEmpty(allParam)) {
|
||||||
return Collections.emptyList();
|
return new OrgSyncCount(0, filteredSkipCount, Collections.emptyList());
|
||||||
}
|
}
|
||||||
Set<String> deptCodes = allParam.stream()
|
Set<String> deptCodes = allParam.stream()
|
||||||
.map(Dept::getDeptCode)
|
.map(Dept::getDeptCode)
|
||||||
@@ -387,7 +538,10 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
.filter(dept -> StringUtils.isNotEmpty(dept.getDeptCode()))
|
.filter(dept -> StringUtils.isNotEmpty(dept.getDeptCode()))
|
||||||
.collect(Collectors.toMap(Dept::getDeptCode, Dept::getId, (a, b) -> b));
|
.collect(Collectors.toMap(Dept::getDeptCode, Dept::getId, (a, b) -> b));
|
||||||
// 处理部门
|
// 处理部门
|
||||||
return this.handleDept(allParam, deptMap, DeptCategory.DEPT);
|
List<Dept> notHandledList = this.handleDept(allParam, deptMap, DeptCategory.DEPT);
|
||||||
|
int syncedCount = allParam.size() - notHandledList.size();
|
||||||
|
int skippedCount = filteredSkipCount + notHandledList.size();
|
||||||
|
return new OrgSyncCount(syncedCount, skippedCount, notHandledList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -441,6 +595,37 @@ public class OASyncServiceImpl implements IOASyncService {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组织同步统计
|
||||||
|
*/
|
||||||
|
private static class OrgSyncCount {
|
||||||
|
private final int syncedCount;
|
||||||
|
private final int skippedCount;
|
||||||
|
private final List<Dept> notHandledList;
|
||||||
|
|
||||||
|
private OrgSyncCount(int syncedCount, int skippedCount, List<Dept> notHandledList) {
|
||||||
|
this.syncedCount = syncedCount;
|
||||||
|
this.skippedCount = skippedCount;
|
||||||
|
this.notHandledList = notHandledList == null ? Collections.emptyList() : notHandledList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static OrgSyncCount empty() {
|
||||||
|
return new OrgSyncCount(0, 0, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSyncedCount() {
|
||||||
|
return syncedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSkippedCount() {
|
||||||
|
return skippedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Dept> getNotHandledList() {
|
||||||
|
return notHandledList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取oa查询参数,子公司id参数
|
* 获取oa查询参数,子公司id参数
|
||||||
* @return
|
* @return
|
||||||
|
|||||||
@@ -32,3 +32,12 @@ iam:
|
|||||||
authorization: ${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}
|
authorization: ${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}
|
||||||
profile-authorization: ${IAM_SSO_PROFILE_AUTHORIZATION:YjNlZmU0ODEwMzJiNGJhZTpkYzQ5NDY1NmQ4MzE0NThjODI5MzlmNzA2ZjliNDY3MQ==}
|
profile-authorization: ${IAM_SSO_PROFILE_AUTHORIZATION:YjNlZmU0ODEwMzJiNGJhZTpkYzQ5NDY1NmQ4MzE0NThjODI5MzlmNzA2ZjliNDY3MQ==}
|
||||||
page-size: ${IAM_SSO_ACCOUNT_PAGE_SIZE:50}
|
page-size: ${IAM_SSO_ACCOUNT_PAGE_SIZE:50}
|
||||||
|
|
||||||
|
# OA组织/人员同步走同一 gwzh 网关,仅需 Authorization(与可用 curl 一致)
|
||||||
|
thirdParty:
|
||||||
|
oa:
|
||||||
|
baseUrl: ${OA_BASE_URL:http://172.16.204.83:38000}
|
||||||
|
queryCompanyPageUrl: ${OA_QUERY_COMPANY_PAGE_URL:/gwzh/OA/OA_GET_COMPANY_LIST}
|
||||||
|
queryDepartmentPageUrl: ${OA_QUERY_DEPARTMENT_PAGE_URL:/gwzh/OA/OA_GET_DEPARTMENT_LIST}
|
||||||
|
queryPersonPageUrl: ${OA_QUERY_PERSON_PAGE_URL:/gwzh/OA/OA_GET_USER_LIST}
|
||||||
|
authorization: ${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}}
|
||||||
|
|||||||
@@ -31,6 +31,10 @@
|
|||||||
<groupId>org.springblade</groupId>
|
<groupId>org.springblade</groupId>
|
||||||
<artifactId>blade-transport-api</artifactId>
|
<artifactId>blade-transport-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springblade</groupId>
|
||||||
|
<artifactId>blade-lbs-api</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springblade</groupId>
|
<groupId>org.springblade</groupId>
|
||||||
<artifactId>blade-user-api</artifactId>
|
<artifactId>blade-user-api</artifactId>
|
||||||
@@ -39,6 +43,10 @@
|
|||||||
<groupId>org.springblade</groupId>
|
<groupId>org.springblade</groupId>
|
||||||
<artifactId>blade-system-api</artifactId>
|
<artifactId>blade-system-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springblade</groupId>
|
||||||
|
<artifactId>blade-process-api</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||||
|
|||||||
+102
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.transport.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.mp.support.Condition;
|
||||||
|
import org.springblade.core.mp.support.Query;
|
||||||
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
|
import org.springblade.core.secure.constant.AuthConstant;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.R;
|
||||||
|
import org.springblade.transport.pojo.vo.CustomerArchiveVO;
|
||||||
|
import org.springblade.transport.pojo.vo.CustomerChangeRecordVO;
|
||||||
|
import org.springblade.transport.service.ICustomerArchiveService;
|
||||||
|
import org.springblade.transport.service.impl.CustomerArchivePublicProcessService;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客商档案公开查看 控制器
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
@TenantIgnore
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
|
@RequestMapping("/customer-archive/public")
|
||||||
|
@Tag(name = "客商档案公开查看", description = "客商档案公开查看")
|
||||||
|
public class CustomerArchivePublicController {
|
||||||
|
|
||||||
|
private final ICustomerArchiveService customerArchiveService;
|
||||||
|
private final CustomerArchivePublicProcessService customerArchivePublicProcessService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公开详情
|
||||||
|
*/
|
||||||
|
@GetMapping("/detail")
|
||||||
|
@ApiOperationSupport(order = 1)
|
||||||
|
@Operation(summary = "公开详情", description = "传入id,无需登录")
|
||||||
|
public R<CustomerArchiveVO> detail(@Parameter(description = "主键", required = true) @RequestParam Long id) {
|
||||||
|
return R.data(customerArchiveService.publicDetail(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公开变更记录分页
|
||||||
|
*/
|
||||||
|
@GetMapping("/change-record/list")
|
||||||
|
@ApiOperationSupport(order = 2)
|
||||||
|
@Operation(summary = "公开变更记录分页", description = "传入客商ID,无需登录")
|
||||||
|
public R<IPage<CustomerChangeRecordVO>> changeRecordList(
|
||||||
|
@Parameter(description = "客商ID", required = true) @RequestParam Long customerId, Query query) {
|
||||||
|
return R.data(customerArchiveService.publicChangeRecordPage(Condition.getPage(query), customerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公开接收流程页 postMessage 数据
|
||||||
|
*/
|
||||||
|
@PostMapping("/process-message")
|
||||||
|
@ApiOperationSupport(order = 3)
|
||||||
|
@Operation(summary = "公开接收流程消息", description = "无需登录,立即查询当前节点,5秒后查询流程实例详情并同步客商")
|
||||||
|
public R processMessage(@RequestBody Map<String, Object> body) {
|
||||||
|
log.info("客商公开页收到流程消息:{}", JSON.toJSONString(body));
|
||||||
|
customerArchivePublicProcessService.handleProcessMessage(body);
|
||||||
|
return R.success("ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
package org.springblade.transport.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
|
import org.springblade.core.secure.constant.AuthConstant;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.R;
|
||||||
|
import org.springblade.transport.mk.MkProcessMessageService;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 业务流程公开查看
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
@TenantIgnore
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
|
@RequestMapping("/mk-process/public")
|
||||||
|
@Tag(name = "MK业务流程公开查看", description = "MK业务流程公开查看")
|
||||||
|
public class MkProcessPublicController {
|
||||||
|
|
||||||
|
private final MkProcessMessageService mkProcessMessageService;
|
||||||
|
|
||||||
|
@GetMapping("/{bizType}/detail")
|
||||||
|
@ApiOperationSupport(order = 1)
|
||||||
|
@Operation(summary = "公开详情", description = "无需登录")
|
||||||
|
public R detail(@PathVariable String bizType,
|
||||||
|
@Parameter(description = "主键", required = true) @RequestParam Long id) {
|
||||||
|
return R.data(mkProcessMessageService.handler(bizType).publicDetail(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{bizType}/process-message")
|
||||||
|
@ApiOperationSupport(order = 2)
|
||||||
|
@Operation(summary = "公开接收流程消息", description = "无需登录,立即查询当前节点,5秒后查询流程实例详情并同步业务")
|
||||||
|
public R processMessage(@PathVariable String bizType, @RequestBody Map<String, Object> body) {
|
||||||
|
log.info("公开页收到流程消息 bizType={} body={}", bizType, JSON.toJSONString(body));
|
||||||
|
mkProcessMessageService.handleProcessMessage(bizType, body);
|
||||||
|
return R.success("ok");
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -105,7 +105,7 @@ public class ProjectApplyController extends BladeController {
|
|||||||
@ApiOperationSupport(order = 4)
|
@ApiOperationSupport(order = 4)
|
||||||
@Operation(summary = "新增或修改", description = "传入projectApply")
|
@Operation(summary = "新增或修改", description = "传入projectApply")
|
||||||
public R submit(@RequestBody ProjectApply projectApply) {
|
public R submit(@RequestBody ProjectApply projectApply) {
|
||||||
return R.status(projectApplyService.submit(projectApply));
|
return projectApplyService.submit(projectApply) ? R.data(projectApply) : R.fail("保存失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/submit-approval")
|
@PostMapping("/submit-approval")
|
||||||
|
|||||||
+20
-1
@@ -53,6 +53,8 @@ import org.springblade.transport.pojo.dto.WaybillImportBatchRequest;
|
|||||||
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
|
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
|
||||||
import org.springblade.transport.pojo.vo.LoadingManageVO;
|
import org.springblade.transport.pojo.vo.LoadingManageVO;
|
||||||
import org.springblade.transport.pojo.vo.WaybillImportBatchVO;
|
import org.springblade.transport.pojo.vo.WaybillImportBatchVO;
|
||||||
|
import org.springblade.transport.pojo.vo.WaybillLocateVO;
|
||||||
|
import org.springblade.transport.pojo.vo.WaybillTrackVO;
|
||||||
import org.springblade.transport.pojo.vo.WaybillPunchRecordsVO;
|
import org.springblade.transport.pojo.vo.WaybillPunchRecordsVO;
|
||||||
import org.springblade.transport.pojo.vo.WaybillVO;
|
import org.springblade.transport.pojo.vo.WaybillVO;
|
||||||
import org.springblade.transport.pojo.dto.WaybillMileageRequest;
|
import org.springblade.transport.pojo.dto.WaybillMileageRequest;
|
||||||
@@ -109,6 +111,23 @@ public class WaybillController extends BladeController {
|
|||||||
return R.data(waybillService.listPunchRecords(waybillId));
|
return R.data(waybillService.listPunchRecords(waybillId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/locate")
|
||||||
|
@ApiOperationSupport(order = 1)
|
||||||
|
@Operation(summary = "车辆实时定位", description = "按运单绑定车牌调用 LBS_LOCATE")
|
||||||
|
public R<WaybillLocateVO> locate(@Parameter(description = "运单ID", required = true) @RequestParam Long id) {
|
||||||
|
return R.data(waybillService.locateVehicle(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/track")
|
||||||
|
@ApiOperationSupport(order = 1)
|
||||||
|
@Operation(summary = "车辆历史轨迹", description = "按运单绑定车牌 + 日期区间调用 LBS_TRACK")
|
||||||
|
public R<WaybillTrackVO> track(
|
||||||
|
@Parameter(description = "运单ID", required = true) @RequestParam Long id,
|
||||||
|
@Parameter(description = "开始日期 YYYY-MM-DD", required = true) @RequestParam String startDate,
|
||||||
|
@Parameter(description = "结束日期 YYYY-MM-DD", required = true) @RequestParam String endDate) {
|
||||||
|
return R.data(waybillService.trackVehicle(id, startDate, endDate));
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
@ApiOperationSupport(order = 2)
|
@ApiOperationSupport(order = 2)
|
||||||
@Operation(summary = "分页", description = "传入waybill")
|
@Operation(summary = "分页", description = "传入waybill")
|
||||||
@@ -194,7 +213,7 @@ public class WaybillController extends BladeController {
|
|||||||
@ApiOperationSupport(order = 9)
|
@ApiOperationSupport(order = 9)
|
||||||
@Operation(summary = "新增或修改", description = "传入waybill")
|
@Operation(summary = "新增或修改", description = "传入waybill")
|
||||||
public R submit(@RequestBody Waybill waybill) {
|
public R submit(@RequestBody Waybill waybill) {
|
||||||
return R.status(waybillService.submit(waybill));
|
return waybillService.submit(waybill) ? R.data(waybill) : R.fail("保存失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/save-draft")
|
@PostMapping("/save-draft")
|
||||||
|
|||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
package org.springblade.transport.feign;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
|
import org.springblade.core.secure.constant.AuthConstant;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.transport.pojo.dto.CustomerProcessNodeSyncDTO;
|
||||||
|
import org.springblade.transport.service.ICustomerArchiveService;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客商档案 Feign实现
|
||||||
|
*/
|
||||||
|
@Hidden
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class CustomerArchiveClient implements ICustomerArchiveClient {
|
||||||
|
|
||||||
|
private final ICustomerArchiveService customerArchiveService;
|
||||||
|
|
||||||
|
@TenantIgnore
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
|
@PostMapping(SYNC_PROCESS_NODE)
|
||||||
|
@Override
|
||||||
|
public FR<Boolean> syncProcessNode(@RequestBody CustomerProcessNodeSyncDTO param) {
|
||||||
|
if (param == null) {
|
||||||
|
return FR.data(false);
|
||||||
|
}
|
||||||
|
if (param.getProcessInfo() != null) {
|
||||||
|
return FR.data(customerArchiveService.syncProcessNodeFromProcessInfo(param.getId(), param.getProcessInfo()));
|
||||||
|
}
|
||||||
|
return FR.data(customerArchiveService.syncProcessNode(
|
||||||
|
param.getId(), param.getCurrentNode(), param.getCurrentProcessor(), param.getApprovalStatus()));
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
package org.springblade.transport.feign;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
|
import org.springblade.core.secure.constant.AuthConstant;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.transport.mk.IMkProcessBizHandler;
|
||||||
|
import org.springblade.transport.mk.MkProcessMessageService;
|
||||||
|
import org.springblade.transport.pojo.dto.MkProcessSyncDTO;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 业务流程同步 Feign 实现
|
||||||
|
*/
|
||||||
|
@Hidden
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MkProcessClient implements IMkProcessClient {
|
||||||
|
|
||||||
|
private final MkProcessMessageService mkProcessMessageService;
|
||||||
|
|
||||||
|
@TenantIgnore
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
|
@PostMapping(APPLY)
|
||||||
|
@Override
|
||||||
|
public FR<Boolean> apply(@RequestBody MkProcessSyncDTO param) {
|
||||||
|
if (param == null || param.getId() == null) {
|
||||||
|
return FR.data(false);
|
||||||
|
}
|
||||||
|
IMkProcessBizHandler handler = mkProcessMessageService.handler(param.getBizType());
|
||||||
|
String action = param.getAction() == null ? "sync" : param.getAction();
|
||||||
|
return switch (action) {
|
||||||
|
case "approve" -> FR.data(handler.approveFromProcess(param.getId(), param.getProcessorName()));
|
||||||
|
case "reject" -> FR.data(handler.rejectFromProcess(param.getId(), param.getProcessorName()));
|
||||||
|
default -> FR.data(handler.syncFromProcessInfo(param.getId(), param.getProcessInfo()));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package org.springblade.transport.mk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 业务流程处理器
|
||||||
|
*/
|
||||||
|
public interface IMkProcessBizHandler {
|
||||||
|
|
||||||
|
String bizType();
|
||||||
|
|
||||||
|
Object publicDetail(Long id);
|
||||||
|
|
||||||
|
boolean syncFromProcessInfo(Long id, Object processInfo);
|
||||||
|
|
||||||
|
boolean approveFromProcess(Long id, String processorName);
|
||||||
|
|
||||||
|
boolean rejectFromProcess(Long id, String processorName);
|
||||||
|
}
|
||||||
+439
@@ -0,0 +1,439 @@
|
|||||||
|
package org.springblade.transport.mk;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.utils.Func;
|
||||||
|
import org.springblade.transport.pojo.entity.ContractManage;
|
||||||
|
import org.springblade.transport.pojo.entity.FormalSettlement;
|
||||||
|
import org.springblade.transport.pojo.entity.PaymentApplication;
|
||||||
|
import org.springblade.transport.pojo.entity.PreSettlement;
|
||||||
|
import org.springblade.transport.pojo.entity.ProjectApply;
|
||||||
|
import org.springblade.transport.pojo.entity.Waybill;
|
||||||
|
import org.springblade.transport.service.IContractManageService;
|
||||||
|
import org.springblade.transport.service.ICustomerArchiveService;
|
||||||
|
import org.springblade.transport.service.IFormalSettlementService;
|
||||||
|
import org.springblade.transport.service.IPaymentApplicationService;
|
||||||
|
import org.springblade.transport.service.IPreSettlementService;
|
||||||
|
import org.springblade.transport.service.IProjectApplyService;
|
||||||
|
import org.springblade.transport.service.IWaybillService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 各业务 MK 流程处理器
|
||||||
|
*/
|
||||||
|
public final class MkProcessBizHandlers {
|
||||||
|
|
||||||
|
private MkProcessBizHandlers() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class CustomerHandler implements IMkProcessBizHandler {
|
||||||
|
private final ICustomerArchiveService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "customer-archive";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.publicDetail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
return service.syncProcessNodeFromProcessInfo(id, processInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
return service.approveFromProcess(id, processorName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
return service.rejectFromProcess(id, processorName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class ProjectHandler implements IMkProcessBizHandler {
|
||||||
|
private final IProjectApplyService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "project-apply";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
ProjectApply entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
|
||||||
|
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(node)) {
|
||||||
|
entity.setCurrentNode(node);
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(processor)) {
|
||||||
|
entity.setCurrentProcessor(processor);
|
||||||
|
}
|
||||||
|
if (!"change_reviewing".equals(entity.getApprovalStatus())) {
|
||||||
|
entity.setApprovalStatus("reviewing");
|
||||||
|
}
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
ProjectApply entity = service.getById(id);
|
||||||
|
if (entity == null || "approved".equals(entity.getApprovalStatus())
|
||||||
|
|| "change_approved".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
boolean change = "change_reviewing".equals(entity.getApprovalStatus());
|
||||||
|
entity.setApprovalStatus(change ? "change_approved" : "approved");
|
||||||
|
entity.setEffectiveType("formal");
|
||||||
|
entity.setCurrentNode("审核通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
entity.setApprovedTime(LocalDateTime.now());
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
ProjectApply entity = service.getById(id);
|
||||||
|
if (entity == null || "rejected".equals(entity.getApprovalStatus())
|
||||||
|
|| "change_rejected".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
boolean change = "change_reviewing".equals(entity.getApprovalStatus());
|
||||||
|
entity.setApprovalStatus(change ? "change_rejected" : "rejected");
|
||||||
|
entity.setCurrentNode("审核不通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class ContractHandler implements IMkProcessBizHandler {
|
||||||
|
private final IContractManageService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "contract-manage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
ContractManage entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
|
||||||
|
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(node)) {
|
||||||
|
entity.setCurrentNode(node);
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(processor)) {
|
||||||
|
entity.setCurrentProcessor(processor);
|
||||||
|
}
|
||||||
|
if (!"change_reviewing".equals(entity.getApprovalStatus())) {
|
||||||
|
entity.setApprovalStatus("reviewing");
|
||||||
|
}
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
ContractManage entity = service.getById(id);
|
||||||
|
if (entity == null || "approved".equals(entity.getApprovalStatus())
|
||||||
|
|| "change_approved".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
boolean change = "change_reviewing".equals(entity.getApprovalStatus());
|
||||||
|
entity.setApprovalStatus(change ? "change_approved" : "approved");
|
||||||
|
entity.setCurrentNode("审核通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
ContractManage entity = service.getById(id);
|
||||||
|
if (entity == null || "rejected".equals(entity.getApprovalStatus())
|
||||||
|
|| "change_rejected".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
boolean change = "change_reviewing".equals(entity.getApprovalStatus());
|
||||||
|
entity.setApprovalStatus(change ? "change_rejected" : "rejected");
|
||||||
|
entity.setCurrentNode("审核不通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class WaybillHandler implements IMkProcessBizHandler {
|
||||||
|
private final IWaybillService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "waybill-manage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
Waybill entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
if (Func.isEmpty(node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entity.setCurrentProcessNode(node);
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
Waybill entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entity.setCurrentProcessNode("审核通过");
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
Waybill entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entity.setCurrentProcessNode("审核不通过");
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class PreSettlementHandler implements IMkProcessBizHandler {
|
||||||
|
private final IPreSettlementService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "pre-settlement";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
PreSettlement entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
|
||||||
|
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(node)) {
|
||||||
|
entity.setCurrentNode(node);
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(processor)) {
|
||||||
|
entity.setCurrentProcessor(processor);
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("reviewing");
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
PreSettlement entity = service.getById(id);
|
||||||
|
if (entity == null || "approved".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("approved");
|
||||||
|
entity.setCurrentNode("审核通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
entity.setApprovedTime(LocalDateTime.now());
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
PreSettlement entity = service.getById(id);
|
||||||
|
if (entity == null || "returned".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("returned");
|
||||||
|
entity.setCurrentNode("审核不通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class FormalSettlementHandler implements IMkProcessBizHandler {
|
||||||
|
private final IFormalSettlementService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "formal-settlement";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
FormalSettlement entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
|
||||||
|
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(node)) {
|
||||||
|
entity.setCurrentNode(node);
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(processor)) {
|
||||||
|
entity.setCurrentProcessor(processor);
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("reviewing");
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
FormalSettlement entity = service.getById(id);
|
||||||
|
if (entity == null || "approved".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("approved");
|
||||||
|
entity.setCurrentNode("审核通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
entity.setApprovedTime(LocalDateTime.now());
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
FormalSettlement entity = service.getById(id);
|
||||||
|
if (entity == null || "returned".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("returned");
|
||||||
|
entity.setCurrentNode("审核不通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class PaymentHandler implements IMkProcessBizHandler {
|
||||||
|
private final IPaymentApplicationService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "payment-application";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
PaymentApplication entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
|
||||||
|
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(node)) {
|
||||||
|
entity.setCurrentNode(node);
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(processor)) {
|
||||||
|
entity.setCurrentProcessor(processor);
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("reviewing");
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
PaymentApplication entity = service.getById(id);
|
||||||
|
if (entity == null || "approved".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("approved");
|
||||||
|
entity.setCurrentNode("审核通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
PaymentApplication entity = service.getById(id);
|
||||||
|
if (entity == null || "returned".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("returned");
|
||||||
|
entity.setCurrentNode("审核不通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+191
@@ -0,0 +1,191 @@
|
|||||||
|
package org.springblade.transport.mk;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.core.tool.utils.StringUtil;
|
||||||
|
import org.springblade.process.feign.IBusinessProcessClient;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公开页流程消息:当前节点立即查询,流程实例详情延迟 5 秒查询后同步业务状态。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MkProcessMessageService {
|
||||||
|
|
||||||
|
private static final long PROCESS_INFO_DELAY_SECONDS = 5L;
|
||||||
|
|
||||||
|
private final IBusinessProcessClient businessProcessClient;
|
||||||
|
private final List<IMkProcessBizHandler> handlers;
|
||||||
|
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2, runnable -> {
|
||||||
|
Thread thread = new Thread(runnable, "mk-process-info-" + THREAD_INDEX.incrementAndGet());
|
||||||
|
thread.setDaemon(true);
|
||||||
|
return thread;
|
||||||
|
});
|
||||||
|
|
||||||
|
private static final AtomicInteger THREAD_INDEX = new AtomicInteger();
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void shutdown() {
|
||||||
|
scheduler.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMkProcessBizHandler handler(String bizType) {
|
||||||
|
Map<String, IMkProcessBizHandler> mapping = handlers.stream()
|
||||||
|
.collect(Collectors.toMap(IMkProcessBizHandler::bizType, Function.identity(), (a, b) -> a));
|
||||||
|
IMkProcessBizHandler handler = mapping.get(bizType);
|
||||||
|
if (handler == null) {
|
||||||
|
throw new IllegalArgumentException("不支持的MK业务类型:" + bizType);
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleProcessMessage(String bizType, Map<String, Object> body) {
|
||||||
|
IMkProcessBizHandler handler = handler(bizType);
|
||||||
|
Map<String, Object> formValues = asMap(body == null ? null : body.get("formValues"));
|
||||||
|
String processId = firstText(formValues, "processId");
|
||||||
|
if (StringUtil.isBlank(processId) && body != null) {
|
||||||
|
processId = firstText(body, "processId");
|
||||||
|
}
|
||||||
|
String loginName = firstText(formValues, "mkLoginName", "loginName");
|
||||||
|
if (StringUtil.isBlank(processId)) {
|
||||||
|
log.warn("公开页流程消息未找到 processId,跳过查询当前节点 bizType={}", bizType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String bizIdText = firstText(asMap(body == null ? null : body.get("formData")), "id", "formInstanceId");
|
||||||
|
queryCurrentNodes(bizType, processId, loginName);
|
||||||
|
scheduleProcessInfo(handler, bizType, processId, loginName, bizIdText, formValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryCurrentNodes(String bizType, String processId, String loginName) {
|
||||||
|
try {
|
||||||
|
FR<Object> result = businessProcessClient.getCurrentNodes(processId, loginName);
|
||||||
|
Object nodeData = result == null ? null : result.getData();
|
||||||
|
log.info("公开页流程消息当前节点详情 bizType={} processId={} loginName={} result={}",
|
||||||
|
bizType, processId, loginName, JSON.toJSONString(nodeData));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("公开页查询当前节点失败 bizType={} processId={} loginName={}", bizType, processId, loginName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleProcessInfo(IMkProcessBizHandler handler, String bizType, String processId,
|
||||||
|
String loginName, String bizIdText, Map<String, Object> formValues) {
|
||||||
|
Map<String, Object> formValuesCopy = new HashMap<>(formValues == null ? Map.of() : formValues);
|
||||||
|
log.info("公开页将在{}秒后查询流程实例详情 bizType={} processId={}", PROCESS_INFO_DELAY_SECONDS, bizType, processId);
|
||||||
|
scheduler.schedule(
|
||||||
|
() -> queryProcessInfo(handler, bizType, processId, loginName, bizIdText, formValuesCopy),
|
||||||
|
PROCESS_INFO_DELAY_SECONDS,
|
||||||
|
TimeUnit.SECONDS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryProcessInfo(IMkProcessBizHandler handler, String bizType, String processId,
|
||||||
|
String loginName, String bizIdText, Map<String, Object> formValues) {
|
||||||
|
try {
|
||||||
|
FR<Object> processInfoResult = businessProcessClient.getProcessInfo(processId, loginName);
|
||||||
|
Object processInfo = processInfoResult == null ? null : processInfoResult.getData();
|
||||||
|
log.info("公开页流程消息流程实例详情 bizType={} processId={} loginName={} result={}",
|
||||||
|
bizType, processId, loginName, JSON.toJSONString(processInfo));
|
||||||
|
if (isProcessFinished(processInfo)) {
|
||||||
|
applyProcessResult(handler, bizType, bizIdText, processId, formValues, true);
|
||||||
|
} else if (isProcessRejected(processInfo)) {
|
||||||
|
applyProcessResult(handler, bizType, bizIdText, processId, formValues, false);
|
||||||
|
} else if (StringUtil.isNotBlank(bizIdText)) {
|
||||||
|
try {
|
||||||
|
handler.syncFromProcessInfo(Long.valueOf(bizIdText), processInfo);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("公开页流程消息业务id格式不正确 bizType={} id={}", bizType, bizIdText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("公开页查询流程实例详情失败 bizType={} processId={} loginName={}", bizType, processId, loginName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isProcessFinished(Object processInfo) {
|
||||||
|
return "30".equals(firstText(asMap(processInfo), "fdProcessStatus"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isProcessRejected(Object processInfo) {
|
||||||
|
Map<String, Object> info = asMap(processInfo);
|
||||||
|
if (!"20".equals(firstText(info, "fdProcessStatus"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (hasItems(info.get("currentHandlers"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !hasItems(asMap(info.get("fdTaskInfo")).get("handlerInfos"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasItems(Object value) {
|
||||||
|
return value instanceof Collection<?> collection && !collection.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyProcessResult(IMkProcessBizHandler handler, String bizType, String bizIdText,
|
||||||
|
String processId, Map<String, Object> formValues, boolean approved) {
|
||||||
|
String action = approved ? "审核通过" : "审核驳回";
|
||||||
|
if (StringUtil.isBlank(bizIdText)) {
|
||||||
|
log.warn("流程{}但未找到业务id,跳过同步 bizType={} processId={}", action, bizType, processId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String processorName = firstText(formValues, "mkUserName", "mkLoginName");
|
||||||
|
Long bizId = Long.valueOf(bizIdText);
|
||||||
|
if (approved) {
|
||||||
|
handler.approveFromProcess(bizId, processorName);
|
||||||
|
} else {
|
||||||
|
handler.rejectFromProcess(bizId, processorName);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("流程{}但业务id格式不正确 bizType={} id={}", action, bizType, bizIdText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> asMap(Object value) {
|
||||||
|
if (!(value instanceof Map<?, ?> map)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
map.forEach((key, nested) -> {
|
||||||
|
if (key != null) {
|
||||||
|
result.put(String.valueOf(key), nested);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String firstText(Map<String, Object> source, String... keys) {
|
||||||
|
if (source == null || keys == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (String key : keys) {
|
||||||
|
Object value = source.get(key);
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String text = String.valueOf(value).trim();
|
||||||
|
if (StringUtil.isNotBlank(text) && !"null".equalsIgnoreCase(text)) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
package org.springblade.transport.mk;
|
||||||
|
|
||||||
|
import org.springblade.core.tool.jackson.JsonUtil;
|
||||||
|
import org.springblade.core.tool.utils.Func;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 MK 流程实例详情中的当前节点、当前处理人
|
||||||
|
*/
|
||||||
|
public final class MkProcessNodeHelper {
|
||||||
|
|
||||||
|
private MkProcessNodeHelper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String currentProcessor(Object processInfo) {
|
||||||
|
return joinDistinct(extractTexts(asMap(processInfo).get("currentHandlers"), "fdName", "name"), "、");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String currentNode(Object processInfo) {
|
||||||
|
Map<String, Object> taskInfo = asMap(asMap(processInfo).get("fdTaskInfo"));
|
||||||
|
return joinDistinct(extractTexts(taskInfo.get("handlerInfos"), "nodeName"), "、");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String text(String value, String fallback) {
|
||||||
|
return Func.isEmpty(value) ? fallback : value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> asMap(Object value) {
|
||||||
|
if (value instanceof Map<?, ?> map) {
|
||||||
|
Map<String, Object> result = new LinkedHashMap<>();
|
||||||
|
map.forEach((key, nested) -> {
|
||||||
|
if (key != null) {
|
||||||
|
result.put(String.valueOf(key), nested);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Map<String, Object> parsed = JsonUtil.toMap(JsonUtil.toJson(value));
|
||||||
|
return parsed == null ? Map.of() : parsed;
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> extractTexts(Object listObj, String... keys) {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
if (!(listObj instanceof Collection<?> collection) || keys == null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (Object item : collection) {
|
||||||
|
Map<String, Object> map = asMap(item);
|
||||||
|
for (String key : keys) {
|
||||||
|
String text = Func.toStr(map.get(key), "").trim();
|
||||||
|
if (Func.isNotEmpty(text)) {
|
||||||
|
result.add(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String joinDistinct(List<String> values, String delimiter) {
|
||||||
|
return values.stream().filter(Func::isNotEmpty).distinct().collect(Collectors.joining(delimiter));
|
||||||
|
}
|
||||||
|
}
|
||||||
+64
@@ -66,6 +66,23 @@ public interface ICustomerArchiveService extends BaseService<CustomerArchive> {
|
|||||||
*/
|
*/
|
||||||
CustomerArchiveVO detail(Long id);
|
CustomerArchiveVO detail(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公开查看详情(不校验登录态与数据权限)
|
||||||
|
*
|
||||||
|
* @param id 主键
|
||||||
|
* @return 客商档案详情
|
||||||
|
*/
|
||||||
|
CustomerArchiveVO publicDetail(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公开查看变更记录分页(不校验登录态与数据权限)
|
||||||
|
*
|
||||||
|
* @param page 分页参数
|
||||||
|
* @param customerId 客商ID
|
||||||
|
* @return 变更记录分页
|
||||||
|
*/
|
||||||
|
IPage<CustomerChangeRecordVO> publicChangeRecordPage(IPage<CustomerChangeRecordVO> page, Long customerId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增或修改客商档案
|
* 新增或修改客商档案
|
||||||
* <p>仅当 {@code customer.recordChange = true}(前端点「提交」)时写入变更记录;「保存」不落变更记录。</p>
|
* <p>仅当 {@code customer.recordChange = true}(前端点「提交」)时写入变更记录;「保存」不落变更记录。</p>
|
||||||
@@ -83,6 +100,53 @@ public interface ICustomerArchiveService extends BaseService<CustomerArchive> {
|
|||||||
*/
|
*/
|
||||||
boolean submitApproval(Long id);
|
boolean submitApproval(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 MK 当前节点同步客商当前节点、当前处理人和审批状态
|
||||||
|
*
|
||||||
|
* @param id 客商ID
|
||||||
|
* @param currentNode 当前节点
|
||||||
|
* @param currentProcessor 当前处理人
|
||||||
|
* @param approvalStatus 审批状态,可为空,为空时保持为审核中
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean syncProcessNode(Long id, String currentNode, String currentProcessor, String approvalStatus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 MK getCurrentNodes 返回结果同步客商当前节点
|
||||||
|
*
|
||||||
|
* @param id 客商ID
|
||||||
|
* @param currentNodes MK 当前节点详情
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean syncProcessNodeFromMk(Long id, Object currentNodes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 MK 流程实例详情回写当前节点、当前处理人
|
||||||
|
*
|
||||||
|
* @param id 客商ID
|
||||||
|
* @param processInfo MK getProcessInfo 返回数据
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean syncProcessNodeFromProcessInfo(Long id, Object processInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 流程结束(fdProcessStatus=30)时将客商置为审核通过
|
||||||
|
*
|
||||||
|
* @param id 客商ID
|
||||||
|
* @param processorName 当前处理人,可为空
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean approveFromProcess(Long id, String processorName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 流程状态为 20 时将客商置为审核驳回
|
||||||
|
*
|
||||||
|
* @param id 客商ID
|
||||||
|
* @param processorName 当前处理人,可为空
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean rejectFromProcess(Long id, String processorName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 撤回审批并恢复草稿状态
|
* 撤回审批并恢复草稿状态
|
||||||
*
|
*
|
||||||
|
|||||||
+20
@@ -28,6 +28,8 @@ import org.springblade.transport.excel.WaybillExcel;
|
|||||||
import org.springblade.transport.pojo.entity.Waybill;
|
import org.springblade.transport.pojo.entity.Waybill;
|
||||||
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
|
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
|
||||||
import org.springblade.transport.pojo.vo.LoadingManageVO;
|
import org.springblade.transport.pojo.vo.LoadingManageVO;
|
||||||
|
import org.springblade.transport.pojo.vo.WaybillLocateVO;
|
||||||
|
import org.springblade.transport.pojo.vo.WaybillTrackVO;
|
||||||
import org.springblade.transport.pojo.vo.WaybillPunchRecordsVO;
|
import org.springblade.transport.pojo.vo.WaybillPunchRecordsVO;
|
||||||
import org.springblade.transport.pojo.vo.WaybillVO;
|
import org.springblade.transport.pojo.vo.WaybillVO;
|
||||||
import org.springblade.transport.pojo.dto.WaybillMileageRequest;
|
import org.springblade.transport.pojo.dto.WaybillMileageRequest;
|
||||||
@@ -49,6 +51,24 @@ public interface IWaybillService extends BaseService<Waybill> {
|
|||||||
*/
|
*/
|
||||||
WaybillPunchRecordsVO listPunchRecords(Long waybillId);
|
WaybillPunchRecordsVO listPunchRecords(Long waybillId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运单车辆实时定位(按运单绑定车牌调用 LBS)
|
||||||
|
*
|
||||||
|
* @param id 运单ID
|
||||||
|
* @return 定位结果
|
||||||
|
*/
|
||||||
|
WaybillLocateVO locateVehicle(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运单历史轨迹回放(按运单绑定车牌 + 日期区间调用 LBS)
|
||||||
|
*
|
||||||
|
* @param id 运单ID
|
||||||
|
* @param startDate 开始日期 YYYY-MM-DD
|
||||||
|
* @param endDate 结束日期 YYYY-MM-DD
|
||||||
|
* @return 轨迹结果
|
||||||
|
*/
|
||||||
|
WaybillTrackVO trackVehicle(Long id, String startDate, String endDate);
|
||||||
|
|
||||||
Waybill syncDriverAcceptState(Waybill waybill);
|
Waybill syncDriverAcceptState(Waybill waybill);
|
||||||
boolean submit(Waybill waybill);
|
boolean submit(Waybill waybill);
|
||||||
boolean saveDraft(Waybill waybill);
|
boolean saveDraft(Waybill waybill);
|
||||||
|
|||||||
+182
@@ -0,0 +1,182 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
*/
|
||||||
|
package org.springblade.transport.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.core.tool.utils.StringUtil;
|
||||||
|
import org.springblade.process.feign.IBusinessProcessClient;
|
||||||
|
import org.springblade.transport.service.ICustomerArchiveService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客商公开页流程消息处理:当前节点立即查询,流程实例详情延迟查询。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CustomerArchivePublicProcessService {
|
||||||
|
|
||||||
|
private static final long PROCESS_INFO_DELAY_SECONDS = 5L;
|
||||||
|
|
||||||
|
private final ICustomerArchiveService customerArchiveService;
|
||||||
|
private final IBusinessProcessClient businessProcessClient;
|
||||||
|
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2, runnable -> {
|
||||||
|
Thread thread = new Thread(runnable, "customer-archive-process-info-" + THREAD_INDEX.incrementAndGet());
|
||||||
|
thread.setDaemon(true);
|
||||||
|
return thread;
|
||||||
|
});
|
||||||
|
|
||||||
|
private static final AtomicInteger THREAD_INDEX = new AtomicInteger();
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void shutdown() {
|
||||||
|
scheduler.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleProcessMessage(Map<String, Object> body) {
|
||||||
|
Map<String, Object> formValues = asMap(body == null ? null : body.get("formValues"));
|
||||||
|
String processId = firstText(formValues, "processId");
|
||||||
|
if (StringUtil.isBlank(processId) && body != null) {
|
||||||
|
processId = firstText(body, "processId");
|
||||||
|
}
|
||||||
|
String loginName = firstText(formValues, "mkLoginName", "loginName");
|
||||||
|
if (StringUtil.isBlank(processId)) {
|
||||||
|
log.warn("客商公开页流程消息未找到 processId,跳过查询当前节点");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String customerIdText = firstText(asMap(body == null ? null : body.get("formData")), "id");
|
||||||
|
queryCurrentNodes(processId, loginName);
|
||||||
|
scheduleProcessInfo(processId, loginName, customerIdText, formValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryCurrentNodes(String processId, String loginName) {
|
||||||
|
try {
|
||||||
|
FR<Object> result = businessProcessClient.getCurrentNodes(processId, loginName);
|
||||||
|
Object nodeData = result == null ? null : result.getData();
|
||||||
|
log.info("客商公开页流程消息当前节点详情 processId={} loginName={} result={}",
|
||||||
|
processId, loginName, JSON.toJSONString(nodeData));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("客商公开页查询当前节点失败 processId={} loginName={}", processId, loginName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleProcessInfo(String processId, String loginName, String customerIdText,
|
||||||
|
Map<String, Object> formValues) {
|
||||||
|
Map<String, Object> formValuesCopy = new HashMap<>(formValues == null ? Map.of() : formValues);
|
||||||
|
log.info("客商公开页将在{}秒后查询流程实例详情 processId={}", PROCESS_INFO_DELAY_SECONDS, processId);
|
||||||
|
scheduler.schedule(
|
||||||
|
() -> queryProcessInfo(processId, loginName, customerIdText, formValuesCopy),
|
||||||
|
PROCESS_INFO_DELAY_SECONDS,
|
||||||
|
TimeUnit.SECONDS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryProcessInfo(String processId, String loginName, String customerIdText,
|
||||||
|
Map<String, Object> formValues) {
|
||||||
|
try {
|
||||||
|
FR<Object> processInfoResult = businessProcessClient.getProcessInfo(processId, loginName);
|
||||||
|
Object processInfo = processInfoResult == null ? null : processInfoResult.getData();
|
||||||
|
log.info("客商公开页流程消息流程实例详情 processId={} loginName={} result={}",
|
||||||
|
processId, loginName, JSON.toJSONString(processInfo));
|
||||||
|
if (isProcessFinished(processInfo)) {
|
||||||
|
applyProcessResult(customerIdText, processId, formValues, true);
|
||||||
|
} else if (isProcessRejected(processInfo)) {
|
||||||
|
applyProcessResult(customerIdText, processId, formValues, false);
|
||||||
|
} else if (StringUtil.isNotBlank(customerIdText)) {
|
||||||
|
try {
|
||||||
|
customerArchiveService.syncProcessNodeFromProcessInfo(Long.valueOf(customerIdText), processInfo);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("客商公开页流程消息客商id格式不正确:{}", customerIdText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("客商公开页查询流程实例详情失败 processId={} loginName={}", processId, loginName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isProcessFinished(Object processInfo) {
|
||||||
|
return "30".equals(firstText(asMap(processInfo), "fdProcessStatus"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isProcessRejected(Object processInfo) {
|
||||||
|
Map<String, Object> info = asMap(processInfo);
|
||||||
|
if (!"20".equals(firstText(info, "fdProcessStatus"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (hasItems(info.get("currentHandlers"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !hasItems(asMap(info.get("fdTaskInfo")).get("handlerInfos"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasItems(Object value) {
|
||||||
|
return value instanceof Collection<?> collection && !collection.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyProcessResult(String customerIdText, String processId, Map<String, Object> formValues,
|
||||||
|
boolean approved) {
|
||||||
|
String action = approved ? "审核通过" : "审核驳回";
|
||||||
|
if (StringUtil.isBlank(customerIdText)) {
|
||||||
|
log.warn("流程{}但未找到客商id,跳过同步 processId={}", action, processId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String processorName = firstText(formValues, "mkUserName", "mkLoginName");
|
||||||
|
Long customerId = Long.valueOf(customerIdText);
|
||||||
|
if (approved) {
|
||||||
|
customerArchiveService.approveFromProcess(customerId, processorName);
|
||||||
|
} else {
|
||||||
|
customerArchiveService.rejectFromProcess(customerId, processorName);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("流程{}但客商id格式不正确:{}", action, customerIdText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> asMap(Object value) {
|
||||||
|
if (!(value instanceof Map<?, ?> map)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
map.forEach((key, nested) -> {
|
||||||
|
if (key != null) {
|
||||||
|
result.put(String.valueOf(key), nested);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String firstText(Map<String, Object> source, String... keys) {
|
||||||
|
if (source == null || keys == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (String key : keys) {
|
||||||
|
Object value = source.get(key);
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String text = String.valueOf(value).trim();
|
||||||
|
if (StringUtil.isNotBlank(text) && !"null".equalsIgnoreCase(text)) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+263
-24
@@ -29,9 +29,11 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
|||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
import org.springblade.core.tool.jackson.JsonUtil;
|
import org.springblade.core.tool.jackson.JsonUtil;
|
||||||
import org.springblade.core.tool.utils.BeanUtil;
|
import org.springblade.core.tool.utils.BeanUtil;
|
||||||
import org.springblade.core.tool.utils.Func;
|
import org.springblade.core.tool.utils.Func;
|
||||||
@@ -84,6 +86,7 @@ import java.math.RoundingMode;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -100,6 +103,7 @@ import java.util.stream.Collectors;
|
|||||||
*
|
*
|
||||||
* @author Chill
|
* @author Chill
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveMapper, CustomerArchive> implements ICustomerArchiveService {
|
public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveMapper, CustomerArchive> implements ICustomerArchiveService {
|
||||||
@@ -151,31 +155,28 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
|||||||
throw new ServiceException("客商ID不能为空");
|
throw new ServiceException("客商ID不能为空");
|
||||||
}
|
}
|
||||||
ensureCustomerAccessible(customerId);
|
ensureCustomerAccessible(customerId);
|
||||||
IPage<CustomerChangeRecord> recordPage = changeRecordMapper.selectPage(
|
return queryChangeRecordPage(page, customerId);
|
||||||
new Page<>(page.getCurrent(), page.getSize()),
|
}
|
||||||
Wrappers.<CustomerChangeRecord>lambdaQuery()
|
|
||||||
.eq(CustomerChangeRecord::getCustomerId, customerId)
|
@Override
|
||||||
.eq(CustomerChangeRecord::getIsDeleted, 0)
|
@TenantIgnore
|
||||||
.orderByDesc(CustomerChangeRecord::getChangeTime));
|
public IPage<CustomerChangeRecordVO> publicChangeRecordPage(IPage<CustomerChangeRecordVO> page, Long customerId) {
|
||||||
page.setTotal(recordPage.getTotal());
|
if (Func.isEmpty(customerId)) {
|
||||||
return page.setRecords(recordPage.getRecords().stream()
|
throw new ServiceException("客商ID不能为空");
|
||||||
.map(record -> Objects.requireNonNull(BeanUtil.copyProperties(record, CustomerChangeRecordVO.class)))
|
}
|
||||||
.toList());
|
getExistingCustomer(customerId);
|
||||||
|
return queryChangeRecordPage(page, customerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CustomerArchiveVO detail(Long id) {
|
public CustomerArchiveVO detail(Long id) {
|
||||||
if (Func.isEmpty(id)) {
|
return buildDetail(ensureCustomerAccessible(id));
|
||||||
throw new ServiceException("主键不能为空");
|
}
|
||||||
}
|
|
||||||
CustomerArchive customer = ensureCustomerAccessible(id);
|
@Override
|
||||||
CustomerArchiveVO detail = Objects.requireNonNull(BeanUtil.copyProperties(customer, CustomerArchiveVO.class));
|
@TenantIgnore
|
||||||
detail.setContacts(loadContacts(id));
|
public CustomerArchiveVO publicDetail(Long id) {
|
||||||
detail.setReceiptAccounts(loadReceiptAccounts(id));
|
return buildDetail(getExistingCustomer(id));
|
||||||
detail.setInvoices(loadInvoices(id));
|
|
||||||
detail.setScores(loadScores(id));
|
|
||||||
fillFundUseRisk(List.of(detail));
|
|
||||||
return detail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -216,12 +217,151 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
|||||||
CustomerArchive before = Objects.requireNonNull(BeanUtil.copyProperties(detail, CustomerArchive.class));
|
CustomerArchive before = Objects.requireNonNull(BeanUtil.copyProperties(detail, CustomerArchive.class));
|
||||||
CustomerArchive after = copyCustomer(before);
|
CustomerArchive after = copyCustomer(before);
|
||||||
after.setApprovalStatus(APPROVAL_REVIEWING);
|
after.setApprovalStatus(APPROVAL_REVIEWING);
|
||||||
after.setCurrentNode("客商准入审批");
|
if (Func.isEmpty(after.getCurrentNode()) || Objects.equals(after.getCurrentNode(), "草稿")) {
|
||||||
after.setCurrentProcessor("待处理");
|
after.setCurrentNode("客商准入审批");
|
||||||
|
after.setCurrentProcessor("待处理");
|
||||||
|
}
|
||||||
addChangeRecord(id, "提交客商准入审批", before, after);
|
addChangeRecord(id, "提交客商准入审批", before, after);
|
||||||
return updateById(after);
|
return updateById(after);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantIgnore
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean syncProcessNode(Long id, String currentNode, String currentProcessor, String approvalStatus) {
|
||||||
|
if (Func.isEmpty(id)) {
|
||||||
|
log.warn("同步客商当前节点失败,客商ID为空");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CustomerArchive customer = getById(id);
|
||||||
|
if (customer == null || Objects.equals(customer.getIsDeleted(), 1)) {
|
||||||
|
log.warn("同步客商当前节点失败,客商不存在 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String nextStatus = Func.isEmpty(approvalStatus) ? APPROVAL_REVIEWING : approvalStatus;
|
||||||
|
boolean updated = this.lambdaUpdate()
|
||||||
|
.eq(CustomerArchive::getId, id)
|
||||||
|
.set(Func.isNotEmpty(currentNode), CustomerArchive::getCurrentNode, currentNode)
|
||||||
|
.set(Func.isNotEmpty(currentProcessor), CustomerArchive::getCurrentProcessor, currentProcessor)
|
||||||
|
.set(Func.isNotEmpty(nextStatus), CustomerArchive::getApprovalStatus, nextStatus)
|
||||||
|
.update();
|
||||||
|
log.info("同步客商当前节点 id={} currentNode={} currentProcessor={} approvalStatus={} result={}",
|
||||||
|
id, currentNode, currentProcessor, nextStatus, updated);
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantIgnore
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean syncProcessNodeFromMk(Long id, Object currentNodes) {
|
||||||
|
if (Func.isEmpty(id) || currentNodes == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<Map<String, Object>> nodes = normalizeMkNodeList(currentNodes);
|
||||||
|
if (nodes.isEmpty()) {
|
||||||
|
log.warn("同步客商当前节点跳过,节点详情为空 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<String> nodeNames = new ArrayList<>();
|
||||||
|
List<String> handlerNames = new ArrayList<>();
|
||||||
|
for (Map<String, Object> node : nodes) {
|
||||||
|
String nodeName = Func.toStr(node.get("nodeName"), "").trim();
|
||||||
|
if (Func.isNotEmpty(nodeName)) {
|
||||||
|
nodeNames.add(nodeName);
|
||||||
|
}
|
||||||
|
Object handlers = node.get("nodeHandlers");
|
||||||
|
if (!(handlers instanceof Collection<?> handlerList)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Object handler : handlerList) {
|
||||||
|
Map<String, Object> handlerMap = asStringObjectMap(handler);
|
||||||
|
String handlerName = Func.toStr(handlerMap.get("handlerName"), "").trim();
|
||||||
|
if (Func.isNotEmpty(handlerName)) {
|
||||||
|
handlerNames.add(handlerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return syncProcessNode(id, joinDistinct(nodeNames), joinDistinct(handlerNames), APPROVAL_REVIEWING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantIgnore
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean syncProcessNodeFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
if (Func.isEmpty(id) || processInfo == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Map<String, Object> info = asStringObjectMap(processInfo);
|
||||||
|
if (info.isEmpty()) {
|
||||||
|
log.warn("同步客商当前节点跳过,流程实例详情为空 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String currentProcessor = joinDistinct(extractTexts(info.get("currentHandlers"), "fdName", "name"), "、");
|
||||||
|
Map<String, Object> taskInfo = asStringObjectMap(info.get("fdTaskInfo"));
|
||||||
|
String currentNode = joinDistinct(extractTexts(taskInfo.get("handlerInfos"), "nodeName"), "、");
|
||||||
|
if (Func.isEmpty(currentNode) && Func.isEmpty(currentProcessor)) {
|
||||||
|
log.warn("同步客商当前节点跳过,未解析到节点名称或处理人 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return syncProcessNode(id, currentNode, currentProcessor, APPROVAL_REVIEWING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantIgnore
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
if (Func.isEmpty(id)) {
|
||||||
|
log.warn("流程结束审核通过失败,客商ID为空");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CustomerArchive before = getById(id);
|
||||||
|
if (before == null || Objects.equals(before.getIsDeleted(), 1)) {
|
||||||
|
log.warn("流程结束审核通过失败,客商不存在 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Objects.equals(before.getApprovalStatus(), APPROVAL_APPROVED)) {
|
||||||
|
log.info("流程结束审核通过跳过,客商已是审核通过 id={}", id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
CustomerArchive after = copyCustomer(before);
|
||||||
|
after.setAccessType(ACCESS_FORMAL);
|
||||||
|
after.setApprovalStatus(APPROVAL_APPROVED);
|
||||||
|
after.setCurrentNode("审核通过");
|
||||||
|
after.setCurrentProcessor(Func.isEmpty(processorName) ? "系统" : processorName.trim());
|
||||||
|
after.setApprovedTime(LocalDateTime.now());
|
||||||
|
addChangeRecord(id, "客商准入审核通过", before, after);
|
||||||
|
boolean updated = updateById(after);
|
||||||
|
log.info("流程结束审核通过 id={} processor={} result={}", id, after.getCurrentProcessor(), updated);
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantIgnore
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
if (Func.isEmpty(id)) {
|
||||||
|
log.warn("流程审核驳回失败,客商ID为空");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CustomerArchive before = getById(id);
|
||||||
|
if (before == null || Objects.equals(before.getIsDeleted(), 1)) {
|
||||||
|
log.warn("流程审核驳回失败,客商不存在 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Objects.equals(before.getApprovalStatus(), APPROVAL_REJECTED)) {
|
||||||
|
log.info("流程审核驳回跳过,客商已是审核不通过 id={}", id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
CustomerArchive after = copyCustomer(before);
|
||||||
|
after.setApprovalStatus(APPROVAL_REJECTED);
|
||||||
|
after.setCurrentNode("审核不通过");
|
||||||
|
after.setCurrentProcessor(Func.isEmpty(processorName) ? "系统" : processorName.trim());
|
||||||
|
addChangeRecord(id, "客商准入审核不通过", before, after);
|
||||||
|
boolean updated = updateById(after);
|
||||||
|
log.info("流程审核驳回 id={} processor={} result={}", id, after.getCurrentProcessor(), updated);
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public boolean withdrawApproval(Long id) {
|
public boolean withdrawApproval(Long id) {
|
||||||
@@ -987,11 +1127,43 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
|||||||
return CUSTOMER_CODE_PREFIX + String.format("%06d", nextNumber);
|
return CUSTOMER_CODE_PREFIX + String.format("%06d", nextNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CustomerArchive ensureCustomerAccessible(Long id) {
|
private IPage<CustomerChangeRecordVO> queryChangeRecordPage(IPage<CustomerChangeRecordVO> page, Long customerId) {
|
||||||
|
IPage<CustomerChangeRecord> recordPage = changeRecordMapper.selectPage(
|
||||||
|
new Page<>(page.getCurrent(), page.getSize()),
|
||||||
|
Wrappers.<CustomerChangeRecord>lambdaQuery()
|
||||||
|
.eq(CustomerChangeRecord::getCustomerId, customerId)
|
||||||
|
.eq(CustomerChangeRecord::getIsDeleted, 0)
|
||||||
|
.orderByDesc(CustomerChangeRecord::getChangeTime));
|
||||||
|
page.setTotal(recordPage.getTotal());
|
||||||
|
return page.setRecords(recordPage.getRecords().stream()
|
||||||
|
.map(record -> Objects.requireNonNull(BeanUtil.copyProperties(record, CustomerChangeRecordVO.class)))
|
||||||
|
.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomerArchiveVO buildDetail(CustomerArchive customer) {
|
||||||
|
CustomerArchiveVO detail = Objects.requireNonNull(BeanUtil.copyProperties(customer, CustomerArchiveVO.class));
|
||||||
|
Long id = customer.getId();
|
||||||
|
detail.setContacts(loadContacts(id));
|
||||||
|
detail.setReceiptAccounts(loadReceiptAccounts(id));
|
||||||
|
detail.setInvoices(loadInvoices(id));
|
||||||
|
detail.setScores(loadScores(id));
|
||||||
|
fillFundUseRisk(List.of(detail));
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomerArchive getExistingCustomer(Long id) {
|
||||||
|
if (Func.isEmpty(id)) {
|
||||||
|
throw new ServiceException("主键不能为空");
|
||||||
|
}
|
||||||
CustomerArchive customer = getById(id);
|
CustomerArchive customer = getById(id);
|
||||||
if (Func.isEmpty(customer) || Objects.equals(customer.getIsDeleted(), 1)) {
|
if (Func.isEmpty(customer) || Objects.equals(customer.getIsDeleted(), 1)) {
|
||||||
throw new ServiceException("客商档案不存在");
|
throw new ServiceException("客商档案不存在");
|
||||||
}
|
}
|
||||||
|
return customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomerArchive ensureCustomerAccessible(Long id) {
|
||||||
|
CustomerArchive customer = getExistingCustomer(id);
|
||||||
if (baseMapper.selectCustomerPermissionCount(id, AuthUtil.getUserId()) == 0) {
|
if (baseMapper.selectCustomerPermissionCount(id, AuthUtil.getUserId()) == 0) {
|
||||||
throw new ServiceException("无权访问该客商档案");
|
throw new ServiceException("无权访问该客商档案");
|
||||||
}
|
}
|
||||||
@@ -1002,6 +1174,73 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
|||||||
return Objects.requireNonNull(BeanUtil.copyProperties(customer, CustomerArchive.class));
|
return Objects.requireNonNull(BeanUtil.copyProperties(customer, CustomerArchive.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private List<Map<String, Object>> normalizeMkNodeList(Object currentNodes) {
|
||||||
|
Object source = currentNodes;
|
||||||
|
if (source instanceof String text && Func.isNotEmpty(text.trim())) {
|
||||||
|
source = JsonUtil.parse(text, List.class);
|
||||||
|
}
|
||||||
|
if (source instanceof Collection<?> collection) {
|
||||||
|
List<Map<String, Object>> result = new ArrayList<>();
|
||||||
|
for (Object item : collection) {
|
||||||
|
Map<String, Object> map = asStringObjectMap(item);
|
||||||
|
if (!map.isEmpty()) {
|
||||||
|
result.add(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Map<String, Object> single = asStringObjectMap(source);
|
||||||
|
return single.isEmpty() ? List.of() : List.of(single);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> asStringObjectMap(Object value) {
|
||||||
|
if (value instanceof Map<?, ?> map) {
|
||||||
|
Map<String, Object> result = new LinkedHashMap<>();
|
||||||
|
map.forEach((key, nested) -> {
|
||||||
|
if (key != null) {
|
||||||
|
result.put(String.valueOf(key), nested);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Map<String, Object> parsed = JsonUtil.toMap(JsonUtil.toJson(value));
|
||||||
|
return parsed == null ? Map.of() : parsed;
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String joinDistinct(List<String> values) {
|
||||||
|
return joinDistinct(values, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String joinDistinct(List<String> values, String delimiter) {
|
||||||
|
return values.stream().filter(Func::isNotEmpty).distinct().collect(Collectors.joining(delimiter));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> extractTexts(Object listObj, String... keys) {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
if (!(listObj instanceof Collection<?> collection) || keys == null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (Object item : collection) {
|
||||||
|
Map<String, Object> map = asStringObjectMap(item);
|
||||||
|
for (String key : keys) {
|
||||||
|
String text = Func.toStr(map.get(key), "").trim();
|
||||||
|
if (Func.isNotEmpty(text)) {
|
||||||
|
result.add(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private void addChangeRecord(Long customerId, String content, CustomerArchive before, CustomerArchive after) {
|
private void addChangeRecord(Long customerId, String content, CustomerArchive before, CustomerArchive after) {
|
||||||
Map<String, Object> beforeSnapshot = customerSnapshot(before);
|
Map<String, Object> beforeSnapshot = customerSnapshot(before);
|
||||||
Map<String, Object> afterSnapshot = customerSnapshot(after);
|
Map<String, Object> afterSnapshot = customerSnapshot(after);
|
||||||
|
|||||||
+224
-3
@@ -25,6 +25,7 @@ package org.springblade.transport.service.impl;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||||
import org.springblade.core.tool.jackson.JsonUtil;
|
import org.springblade.core.tool.jackson.JsonUtil;
|
||||||
@@ -32,10 +33,10 @@ import org.springblade.core.tool.utils.BeanUtil;
|
|||||||
import org.springblade.core.tool.utils.Func;
|
import org.springblade.core.tool.utils.Func;
|
||||||
import org.springblade.system.cache.UserCache;
|
import org.springblade.system.cache.UserCache;
|
||||||
import org.springblade.system.pojo.entity.Dept;
|
import org.springblade.system.pojo.entity.Dept;
|
||||||
|
import org.springblade.thirdparty.lbs.feign.ILbsClient;
|
||||||
|
import org.springblade.thirdparty.lbs.pojo.dto.LbsLocateRequest;
|
||||||
|
import org.springblade.thirdparty.lbs.pojo.vo.LbsLocateResponse;
|
||||||
import org.springblade.transport.excel.WaybillExcel;
|
import org.springblade.transport.excel.WaybillExcel;
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillMapper;
|
import org.springblade.transport.mapper.WaybillMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -49,6 +50,8 @@ import org.springblade.transport.pojo.entity.WaybillNodePunch;
|
|||||||
import org.springblade.transport.pojo.dto.WaybillMileageRequest;
|
import org.springblade.transport.pojo.dto.WaybillMileageRequest;
|
||||||
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
|
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
|
||||||
import org.springblade.transport.pojo.vo.LoadingManageVO;
|
import org.springblade.transport.pojo.vo.LoadingManageVO;
|
||||||
|
import org.springblade.transport.pojo.vo.WaybillLocateVO;
|
||||||
|
import org.springblade.transport.pojo.vo.WaybillTrackVO;
|
||||||
import org.springblade.transport.pojo.vo.WaybillPunchPhotoVO;
|
import org.springblade.transport.pojo.vo.WaybillPunchPhotoVO;
|
||||||
import org.springblade.transport.pojo.vo.WaybillPunchRecordItemVO;
|
import org.springblade.transport.pojo.vo.WaybillPunchRecordItemVO;
|
||||||
import org.springblade.transport.pojo.vo.WaybillPunchRecordsVO;
|
import org.springblade.transport.pojo.vo.WaybillPunchRecordsVO;
|
||||||
@@ -67,7 +70,11 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@@ -111,6 +118,9 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
|||||||
@jakarta.annotation.Resource
|
@jakarta.annotation.Resource
|
||||||
private WaybillEnroutePunchMapper waybillEnroutePunchMapper;
|
private WaybillEnroutePunchMapper waybillEnroutePunchMapper;
|
||||||
|
|
||||||
|
@jakarta.annotation.Resource
|
||||||
|
private ILbsClient lbsClient;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IPage<WaybillVO> selectWaybillPage(IPage<Waybill> page, WaybillVO waybill) {
|
public IPage<WaybillVO> selectWaybillPage(IPage<Waybill> page, WaybillVO waybill) {
|
||||||
IPage<Waybill> entityPage = page(page, buildQuery(waybill));
|
IPage<Waybill> entityPage = page(page, buildQuery(waybill));
|
||||||
@@ -128,6 +138,217 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WaybillLocateVO locateVehicle(Long id) {
|
||||||
|
Waybill waybill = requireWaybillWithVehicleNo(id, "无法实时定位");
|
||||||
|
String vehicleNo = waybill.getVehicleNo().trim();
|
||||||
|
LbsLocateResponse response = invokeLbs(id, vehicleNo, new LbsLocateRequest(vehicleNo), false, "实时定位");
|
||||||
|
List<Map<String, Object>> pointMaps = extractLbsPointMaps(response);
|
||||||
|
if (pointMaps.isEmpty()) {
|
||||||
|
throw new ServiceException("暂无车辆实时定位数据");
|
||||||
|
}
|
||||||
|
return buildLocateVO(id, vehicleNo, pointMaps.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WaybillTrackVO trackVehicle(Long id, String startDate, String endDate) {
|
||||||
|
Waybill waybill = requireWaybillWithVehicleNo(id, "无法查询历史轨迹");
|
||||||
|
String vehicleNo = waybill.getVehicleNo().trim();
|
||||||
|
String normalizedStart = normalizeTrackDate(startDate, "开始日期");
|
||||||
|
String normalizedEnd = normalizeTrackDate(endDate, "结束日期");
|
||||||
|
if (LocalDate.parse(normalizedStart).isAfter(LocalDate.parse(normalizedEnd))) {
|
||||||
|
throw new ServiceException("开始日期不能晚于结束日期");
|
||||||
|
}
|
||||||
|
LbsLocateResponse response = invokeLbs(id, vehicleNo,
|
||||||
|
new LbsLocateRequest(vehicleNo, normalizedStart, normalizedEnd), true, "历史轨迹");
|
||||||
|
List<Map<String, Object>> pointMaps = extractLbsPointMaps(response);
|
||||||
|
WaybillTrackVO trackVO = new WaybillTrackVO();
|
||||||
|
trackVO.setWaybillId(id);
|
||||||
|
trackVO.setVehicleNo(vehicleNo);
|
||||||
|
trackVO.setStartDate(normalizedStart);
|
||||||
|
trackVO.setEndDate(normalizedEnd);
|
||||||
|
List<WaybillTrackVO.WaybillTrackPointVO> points = new ArrayList<>();
|
||||||
|
for (Map<String, Object> pointMap : pointMaps) {
|
||||||
|
WaybillTrackVO.WaybillTrackPointVO point = buildTrackPoint(vehicleNo, pointMap);
|
||||||
|
if (point.getLongitude() != null && point.getLatitude() != null) {
|
||||||
|
points.add(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trackVO.setPoints(points);
|
||||||
|
trackVO.setTotal(points.size());
|
||||||
|
return trackVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Waybill requireWaybillWithVehicleNo(Long id, String actionTip) {
|
||||||
|
if (id == null) {
|
||||||
|
throw new ServiceException("运单ID不能为空");
|
||||||
|
}
|
||||||
|
Waybill waybill = getById(id);
|
||||||
|
if (waybill == null || Objects.equals(waybill.getIsDeleted(), 1)) {
|
||||||
|
throw new ServiceException("运单不存在");
|
||||||
|
}
|
||||||
|
String vehicleNo = Func.toStr(waybill.getVehicleNo(), "").trim();
|
||||||
|
if (Func.isEmpty(vehicleNo)) {
|
||||||
|
throw new ServiceException("运单未绑定车牌号," + actionTip);
|
||||||
|
}
|
||||||
|
waybill.setVehicleNo(vehicleNo);
|
||||||
|
return waybill;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LbsLocateResponse invokeLbs(Long waybillId, String vehicleNo, LbsLocateRequest request,
|
||||||
|
boolean trackMode, String scene) {
|
||||||
|
LbsLocateResponse response;
|
||||||
|
try {
|
||||||
|
response = trackMode ? lbsClient.track(request) : lbsClient.locate(request);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.error("调用LBS{}失败 waybillId={}, vehicleNo={}", scene, waybillId, vehicleNo, exception);
|
||||||
|
throw new ServiceException("调用车辆" + scene + "接口失败");
|
||||||
|
}
|
||||||
|
if (response == null || !response.isSuccess()) {
|
||||||
|
String errorMessage = response == null ? "车辆" + scene + "无返回" : response.errorMessage();
|
||||||
|
throw new ServiceException(errorMessage);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeTrackDate(String dateText, String fieldName) {
|
||||||
|
if (Func.isEmpty(dateText)) {
|
||||||
|
throw new ServiceException(fieldName + "不能为空");
|
||||||
|
}
|
||||||
|
String normalized = dateText.trim();
|
||||||
|
try {
|
||||||
|
return LocalDate.parse(normalized, DateTimeFormatter.ISO_LOCAL_DATE).toString();
|
||||||
|
} catch (DateTimeParseException exception) {
|
||||||
|
throw new ServiceException(fieldName + "格式必须为YYYY-MM-DD");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提取 LBS 轨迹点:优先 list,其次 obj,再兼容 data / data.list / data.obj
|
||||||
|
*/
|
||||||
|
private List<Map<String, Object>> extractLbsPointMaps(LbsLocateResponse response) {
|
||||||
|
List<Map<String, Object>> pointMaps = new ArrayList<>();
|
||||||
|
if (response == null) {
|
||||||
|
return pointMaps;
|
||||||
|
}
|
||||||
|
appendLbsNodes(pointMaps, response.getList());
|
||||||
|
if (!pointMaps.isEmpty()) {
|
||||||
|
return pointMaps;
|
||||||
|
}
|
||||||
|
appendLbsNodes(pointMaps, response.getObj());
|
||||||
|
if (!pointMaps.isEmpty()) {
|
||||||
|
return pointMaps;
|
||||||
|
}
|
||||||
|
JsonNode dataNode = response.getData();
|
||||||
|
if (dataNode != null && !dataNode.isNull()) {
|
||||||
|
if (dataNode.isObject() && dataNode.has("list")) {
|
||||||
|
appendLbsNodes(pointMaps, dataNode.get("list"));
|
||||||
|
if (!pointMaps.isEmpty()) {
|
||||||
|
return pointMaps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dataNode.isObject() && dataNode.has("obj")) {
|
||||||
|
appendLbsNodes(pointMaps, dataNode.get("obj"));
|
||||||
|
if (!pointMaps.isEmpty()) {
|
||||||
|
return pointMaps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appendLbsNodes(pointMaps, dataNode);
|
||||||
|
}
|
||||||
|
return pointMaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendLbsNodes(List<Map<String, Object>> pointMaps, JsonNode node) {
|
||||||
|
if (node == null || node.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node.isArray()) {
|
||||||
|
for (JsonNode item : node) {
|
||||||
|
if (item != null && item.isObject()) {
|
||||||
|
pointMaps.add(JsonUtil.toMap(item.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node.isObject()) {
|
||||||
|
pointMaps.add(JsonUtil.toMap(node.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 LBS 单点数据归一化为实时定位结果
|
||||||
|
*/
|
||||||
|
private WaybillLocateVO buildLocateVO(Long waybillId, String vehicleNo, Map<String, Object> pointMap) {
|
||||||
|
WaybillLocateVO locateVO = new WaybillLocateVO();
|
||||||
|
locateVO.setWaybillId(waybillId);
|
||||||
|
locateVO.setVehicleNo(vehicleNo);
|
||||||
|
locateVO.setRawData(pointMap);
|
||||||
|
fillPointFields(locateVO, pointMap);
|
||||||
|
return locateVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WaybillTrackVO.WaybillTrackPointVO buildTrackPoint(String vehicleNo, Map<String, Object> pointMap) {
|
||||||
|
WaybillTrackVO.WaybillTrackPointVO point = new WaybillTrackVO.WaybillTrackPointVO();
|
||||||
|
point.setVehicleNo(vehicleNo);
|
||||||
|
fillPointFields(point, pointMap);
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillPointFields(WaybillLocateVO target, Map<String, Object> pointMap) {
|
||||||
|
target.setLongitude(firstDecimal(pointMap, "longitude", "lon", "lng", "x", "jd", "Longitude", "LON", "LNG", "JD", "X"));
|
||||||
|
target.setLatitude(firstDecimal(pointMap, "latitude", "lat", "y", "wd", "Latitude", "LAT", "WD", "Y"));
|
||||||
|
target.setAddress(firstText(pointMap, "address", "addr", "adr", "wz", "Address", "ADDR", "ADR"));
|
||||||
|
target.setLocateTime(firstText(pointMap, "utc", "locationTime", "pos_time", "locateTime", "gpsTime", "gpstime", "time", "gpszdsj", "GPSTime", "Time"));
|
||||||
|
target.setSpeed(firstText(pointMap, "spd", "speed", "v", "sd", "Speed", "SD", "V"));
|
||||||
|
target.setDirection(firstText(pointMap, "direct", "direction", "h", "fx", "Direction", "FX", "course", "H"));
|
||||||
|
String responseVehicleNo = firstText(pointMap, "vno", "cph", "vehicleNo", "plateNo", "CPH", "VNO");
|
||||||
|
if (Func.isNotEmpty(responseVehicleNo)) {
|
||||||
|
target.setVehicleNo(responseVehicleNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillPointFields(WaybillTrackVO.WaybillTrackPointVO target, Map<String, Object> pointMap) {
|
||||||
|
target.setLongitude(firstDecimal(pointMap, "longitude", "lon", "lng", "x", "jd", "Longitude", "LON", "LNG", "JD", "X"));
|
||||||
|
target.setLatitude(firstDecimal(pointMap, "latitude", "lat", "y", "wd", "Latitude", "LAT", "WD", "Y"));
|
||||||
|
target.setAddress(firstText(pointMap, "address", "addr", "adr", "wz", "Address", "ADDR", "ADR"));
|
||||||
|
target.setLocateTime(firstText(pointMap, "utc", "locationTime", "pos_time", "locateTime", "gpsTime", "gpstime", "time", "gpszdsj", "GPSTime", "Time"));
|
||||||
|
target.setSpeed(firstText(pointMap, "spd", "speed", "v", "sd", "Speed", "SD", "V"));
|
||||||
|
target.setDirection(firstText(pointMap, "direct", "direction", "h", "fx", "Direction", "FX", "course", "H"));
|
||||||
|
String responseVehicleNo = firstText(pointMap, "vno", "cph", "vehicleNo", "plateNo", "CPH", "VNO");
|
||||||
|
if (Func.isNotEmpty(responseVehicleNo)) {
|
||||||
|
target.setVehicleNo(responseVehicleNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal firstDecimal(Map<String, Object> rawData, String... keys) {
|
||||||
|
String text = firstText(rawData, keys);
|
||||||
|
if (Func.isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new BigDecimal(text.trim());
|
||||||
|
} catch (NumberFormatException exception) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String firstText(Map<String, Object> rawData, String... keys) {
|
||||||
|
if (rawData == null || rawData.isEmpty() || keys == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (String key : keys) {
|
||||||
|
Object value = rawData.get(key);
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String text = String.valueOf(value).trim();
|
||||||
|
if (Func.isNotEmpty(text) && !"null".equalsIgnoreCase(text)) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WaybillPunchRecordsVO listPunchRecords(Long waybillId) {
|
public WaybillPunchRecordsVO listPunchRecords(Long waybillId) {
|
||||||
WaybillPunchRecordsVO vo = new WaybillPunchRecordsVO();
|
WaybillPunchRecordsVO vo = new WaybillPunchRecordsVO();
|
||||||
|
|||||||
@@ -8,3 +8,11 @@ spring:
|
|||||||
url: ${blade.datasource.dev.url}
|
url: ${blade.datasource.dev.url}
|
||||||
username: ${blade.datasource.dev.username}
|
username: ${blade.datasource.dev.username}
|
||||||
password: ${blade.datasource.dev.password}
|
password: ${blade.datasource.dev.password}
|
||||||
|
|
||||||
|
# LBS 车辆实时定位(Authorization 与 OA 人员接口一致)
|
||||||
|
thirdParty:
|
||||||
|
lbs:
|
||||||
|
baseUrl: ${LBS_BASE_URL:http://172.16.204.83:38000}
|
||||||
|
locateUrl: ${LBS_LOCATE_URL:/gwzh/LBS/LBS_LOCATE}
|
||||||
|
trackUrl: ${LBS_TRACK_URL:/gwzh/LBS/LBS_TRACK}
|
||||||
|
authorization: ${LBS_AUTHORIZATION:${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}}}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springblade</groupId>
|
||||||
|
<artifactId>blade-third-party-api</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>blade-lbs-api</artifactId>
|
||||||
|
<name>${project.artifactId}</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springblade</groupId>
|
||||||
|
<artifactId>blade-core-tool</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.thirdparty.lbs.config;
|
||||||
|
|
||||||
|
import feign.Logger;
|
||||||
|
import feign.Request;
|
||||||
|
import org.springblade.thirdparty.lbs.interceptor.LbsRequestInterceptor;
|
||||||
|
import org.springframework.cloud.openfeign.clientconfig.FeignClientConfigurer;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LBS Feign 客户端配置。
|
||||||
|
* <p>
|
||||||
|
* 关闭父上下文继承,避免全局 BladeFeignRequestInterceptor 透传登录态请求头导致 gwzh 400。
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
public class LbsFeignClientConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FeignClientConfigurer feignClientConfigurer() {
|
||||||
|
return new FeignClientConfigurer() {
|
||||||
|
@Override
|
||||||
|
public boolean inheritParentConfiguration() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LbsRequestInterceptor requestInterceptor(LbsProperties lbsProperties) {
|
||||||
|
return new LbsRequestInterceptor(lbsProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Logger.Level feignLoggerLevel() {
|
||||||
|
return Logger.Level.FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Request.Options options() {
|
||||||
|
return new Request.Options(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.thirdparty.lbs.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LBS 配置
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "third-party.lbs")
|
||||||
|
public class LbsProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LBS 网关基础地址
|
||||||
|
*/
|
||||||
|
private String baseUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车辆实时定位路径
|
||||||
|
*/
|
||||||
|
private String locateUrl = "/gwzh/LBS/LBS_LOCATE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车辆历史轨迹路径
|
||||||
|
*/
|
||||||
|
private String trackUrl = "/gwzh/LBS/LBS_TRACK";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gwzh 网关 Authorization(Basic),与 OA 人员接口一致
|
||||||
|
*/
|
||||||
|
private String authorization;
|
||||||
|
}
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.thirdparty.lbs.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方 LBS 自动配置
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@EnableConfigurationProperties(LbsProperties.class)
|
||||||
|
@Configuration
|
||||||
|
public class ThirdPartyLbsAutoConfiguration {
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.thirdparty.lbs.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LBS 常量
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
public final class LbsConstant {
|
||||||
|
|
||||||
|
private LbsConstant() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功响应码(文档标注)
|
||||||
|
*/
|
||||||
|
public static final int SUCCESS_STATUS = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功响应码(字符串)
|
||||||
|
*/
|
||||||
|
public static final String SUCCESS_STATUS_TEXT = "200";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gwzh 常见成功码(与 OA 一致)
|
||||||
|
*/
|
||||||
|
public static final String SUCCESS_CODE = "1";
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.thirdparty.lbs.feign;
|
||||||
|
|
||||||
|
import org.springblade.thirdparty.lbs.config.LbsFeignClientConfig;
|
||||||
|
import org.springblade.thirdparty.lbs.pojo.dto.LbsLocateRequest;
|
||||||
|
import org.springblade.thirdparty.lbs.pojo.vo.LbsLocateResponse;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LBS 接口
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@FeignClient(name = "LBS", url = "${thirdParty.lbs.baseUrl}", configuration = LbsFeignClientConfig.class)
|
||||||
|
public interface ILbsClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车辆实时定位
|
||||||
|
*
|
||||||
|
* @param request 请求(cph=车牌号)
|
||||||
|
* @return 定位结果
|
||||||
|
*/
|
||||||
|
@PostMapping("${thirdParty.lbs.locateUrl:/gwzh/LBS/LBS_LOCATE}")
|
||||||
|
LbsLocateResponse locate(@RequestBody LbsLocateRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车辆历史轨迹
|
||||||
|
*
|
||||||
|
* @param request 请求(cph、start_date、end_date)
|
||||||
|
* @return 轨迹结果
|
||||||
|
*/
|
||||||
|
@PostMapping("${thirdParty.lbs.trackUrl:/gwzh/LBS/LBS_TRACK}")
|
||||||
|
LbsLocateResponse track(@RequestBody LbsLocateRequest request);
|
||||||
|
}
|
||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.thirdparty.lbs.interceptor;
|
||||||
|
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.tool.utils.StringUtil;
|
||||||
|
import org.springblade.thirdparty.lbs.config.LbsProperties;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LBS Feign 请求拦截器:仅发送 Authorization + Content-Type,与 OA 人员接口一致。
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LbsRequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
private static final String BASIC_PREFIX = "Basic ";
|
||||||
|
private static final String BEARER_PREFIX = "Bearer ";
|
||||||
|
private static final Set<String> KEEP_HEADERS = Set.of(
|
||||||
|
HttpHeaders.AUTHORIZATION.toLowerCase(Locale.ROOT),
|
||||||
|
HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ROOT)
|
||||||
|
);
|
||||||
|
|
||||||
|
private final LbsProperties lbsProperties;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate template) {
|
||||||
|
stripUnwantedHeaders(template);
|
||||||
|
template.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||||
|
|
||||||
|
String authorization = normalizeAuthorization(lbsProperties.getAuthorization());
|
||||||
|
if (StringUtil.isNotBlank(authorization)) {
|
||||||
|
template.header(HttpHeaders.AUTHORIZATION, authorization);
|
||||||
|
} else {
|
||||||
|
log.warn("LBS Feign 未配置 third-party.lbs.authorization,gwzh 网关可能拒绝请求");
|
||||||
|
}
|
||||||
|
|
||||||
|
logRequest(template);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logRequest(RequestTemplate template) {
|
||||||
|
String bodyText = "";
|
||||||
|
byte[] body = template.body();
|
||||||
|
if (body != null && body.length > 0) {
|
||||||
|
Charset charset = template.requestCharset() == null ? StandardCharsets.UTF_8 : template.requestCharset();
|
||||||
|
bodyText = new String(body, charset);
|
||||||
|
}
|
||||||
|
log.info("LBS Feign 请求 method={}, url={}{}{}, headers={}, body={}",
|
||||||
|
template.method(),
|
||||||
|
template.feignTarget() == null ? "" : template.feignTarget().url(),
|
||||||
|
template.path(),
|
||||||
|
template.queryLine() == null ? "" : template.queryLine(),
|
||||||
|
template.headers(),
|
||||||
|
bodyText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stripUnwantedHeaders(RequestTemplate template) {
|
||||||
|
Map<String, Collection<String>> headers = template.headers();
|
||||||
|
List<String> headerNames = new ArrayList<>(headers.keySet());
|
||||||
|
for (String headerName : headerNames) {
|
||||||
|
if (!KEEP_HEADERS.contains(headerName.toLowerCase(Locale.ROOT))) {
|
||||||
|
template.removeHeader(headerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeAuthorization(String authorization) {
|
||||||
|
if (StringUtil.isBlank(authorization)) {
|
||||||
|
return authorization;
|
||||||
|
}
|
||||||
|
if (StringUtil.startsWithIgnoreCase(authorization, BASIC_PREFIX)
|
||||||
|
|| StringUtil.startsWithIgnoreCase(authorization, BEARER_PREFIX)) {
|
||||||
|
return authorization;
|
||||||
|
}
|
||||||
|
return BASIC_PREFIX + authorization;
|
||||||
|
}
|
||||||
|
}
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.thirdparty.lbs.pojo.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LBS 定位/历史轨迹请求
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class LbsLocateRequest implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车牌号
|
||||||
|
*/
|
||||||
|
private String cph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始日期,格式 YYYY-MM-DD(历史轨迹)
|
||||||
|
*/
|
||||||
|
@JsonProperty("start_date")
|
||||||
|
private String startDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束日期,格式 YYYY-MM-DD(历史轨迹)
|
||||||
|
*/
|
||||||
|
@JsonProperty("end_date")
|
||||||
|
private String endDate;
|
||||||
|
|
||||||
|
public LbsLocateRequest(String cph) {
|
||||||
|
this.cph = cph;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LbsLocateRequest(String cph, String startDate, String endDate) {
|
||||||
|
this.cph = cph;
|
||||||
|
this.startDate = startDate;
|
||||||
|
this.endDate = endDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.thirdparty.lbs.pojo.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springblade.thirdparty.lbs.constant.LbsConstant;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LBS 定位/历史轨迹响应。
|
||||||
|
* <p>
|
||||||
|
* 实际网关返回示例:
|
||||||
|
* {@code {"code":200,"obj":{...},"list":null,"msg":"OK"}}
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class LbsLocateResponse implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应代码,200 为正确
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应代码(网关返回 200 或 "1")
|
||||||
|
*/
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提示信息
|
||||||
|
*/
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提示信息(兼容 message)
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单点定位对象
|
||||||
|
*/
|
||||||
|
private JsonNode obj;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 历史轨迹点列表
|
||||||
|
*/
|
||||||
|
private JsonNode list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容旧字段 data
|
||||||
|
*/
|
||||||
|
private JsonNode data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否成功
|
||||||
|
*/
|
||||||
|
public boolean isSuccess() {
|
||||||
|
if (status != null && (status == LbsConstant.SUCCESS_STATUS || status == 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (code == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String normalized = code.trim();
|
||||||
|
return LbsConstant.SUCCESS_STATUS_TEXT.equals(normalized)
|
||||||
|
|| LbsConstant.SUCCESS_CODE.equals(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误信息
|
||||||
|
*/
|
||||||
|
public String errorMessage() {
|
||||||
|
if (msg != null && !msg.isBlank() && !"OK".equalsIgnoreCase(msg) && !"Success".equalsIgnoreCase(msg)) {
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
if (message != null && !message.isBlank()
|
||||||
|
&& !"OK".equalsIgnoreCase(message) && !"Success".equalsIgnoreCase(message)) {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
return "LBS接口调用失败";
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
org.springblade.thirdparty.lbs.config.ThirdPartyLbsAutoConfiguration
|
||||||
Vendored
+9
@@ -65,6 +65,15 @@ public interface IMKClient {
|
|||||||
@PostMapping("${thirdParty.mk.getCurrentNodesUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}")
|
@PostMapping("${thirdParty.mk.getCurrentNodesUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}")
|
||||||
MKResultVO<List<MKNodeVO>> getCurrentNodes(@RequestBody MKCurrentNodesDTO param, @RequestParam("access_token") String accessToken);
|
MKResultVO<List<MKNodeVO>> getCurrentNodes(@RequestBody MKCurrentNodesDTO param, @RequestParam("access_token") String accessToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程实例详情
|
||||||
|
* @param param
|
||||||
|
* @param accessToken
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("${thirdParty.mk.getProcessInfoUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getProcessInfo}")
|
||||||
|
MKResultVO<Object> getProcessInfo(@RequestBody MKCurrentNodesDTO param, @RequestParam("access_token") String accessToken);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取节点处理人信息
|
* 获取节点处理人信息
|
||||||
* @param param
|
* @param param
|
||||||
|
|||||||
+6
@@ -1,6 +1,7 @@
|
|||||||
package org.springblade.thirdparty.mk.pojo.dto;
|
package org.springblade.thirdparty.mk.pojo.dto;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
@@ -44,4 +45,9 @@ public class MKProcessCreateDTO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
private Object tempVarData;
|
private Object tempVarData;
|
||||||
|
/**
|
||||||
|
* 业务类型,仅 ERP 内部使用,不传给 MK
|
||||||
|
*/
|
||||||
|
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||||
|
private String bizType;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -66,6 +66,14 @@ public interface IMKService {
|
|||||||
*/
|
*/
|
||||||
List<MKNodeVO> getCurrentNodes(String processInstanceId, String loginName);
|
List<MKNodeVO> getCurrentNodes(String processInstanceId, String loginName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程实例详情
|
||||||
|
* @param processInstanceId
|
||||||
|
* @param loginName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Object getProcessInfo(String processInstanceId, String loginName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取节点处理人信息
|
* 获取节点处理人信息
|
||||||
* @param processInstanceId
|
* @param processInstanceId
|
||||||
|
|||||||
+15
@@ -246,6 +246,21 @@ public class MKServiceImpl implements IMKService {
|
|||||||
return nodesResult.getData();
|
return nodesResult.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getProcessInfo(String processInstanceId, String loginName) {
|
||||||
|
String accessToken = getToken();
|
||||||
|
MKCurrentNodesDTO param = new MKCurrentNodesDTO();
|
||||||
|
param.setProcessInstanceId(processInstanceId);
|
||||||
|
param.setLoginName(loginName);
|
||||||
|
MKResultVO<Object> processInfoResult = client.getProcessInfo(param, accessToken);
|
||||||
|
log.info("调用mk接口 获取流程实例详情 :{}", JSONUtil.toJsonStr(processInfoResult));
|
||||||
|
if (processInfoResult == null || !processInfoResult.isSuccess()) {
|
||||||
|
log.error("调用mk接口 获取流程实例详情异常:{}", JSONUtil.toJsonStr(processInfoResult));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return processInfoResult.getData();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MKAllHandlerVO getNodeHandlers(String processInstanceId, String loginName, String nodeId) {
|
public MKAllHandlerVO getNodeHandlers(String processInstanceId, String loginName, String nodeId) {
|
||||||
String accessToken = getToken();
|
String accessToken = getToken();
|
||||||
|
|||||||
+28
-23
@@ -1,42 +1,47 @@
|
|||||||
package org.springblade.thirdparty.oa.config;
|
package org.springblade.thirdparty.oa.config;
|
||||||
|
|
||||||
|
import feign.Logger;
|
||||||
import feign.Request;
|
import feign.Request;
|
||||||
import feign.RequestInterceptor;
|
import org.springblade.thirdparty.oa.interceptor.OARequestInterceptor;
|
||||||
import jakarta.annotation.Resource;
|
import org.springframework.cloud.openfeign.clientconfig.FeignClientConfigurer;
|
||||||
import org.springblade.core.tool.utils.StringUtil;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* OA Feign 客户端配置。
|
||||||
|
* <p>
|
||||||
|
* 必须关闭父上下文继承,否则全局 {@code BladeFeignRequestInterceptor}
|
||||||
|
* 会把当前登录请求的 Host、Content-Length、Blade-Auth 等头再次写入,
|
||||||
|
* 导致 gwzh nginx 返回 400。
|
||||||
|
*
|
||||||
* @author bfhuange
|
* @author bfhuange
|
||||||
* @since 2024/12/18
|
* @since 2024/12/18
|
||||||
*/
|
*/
|
||||||
public class OAFeignClientConfig {
|
public class OAFeignClientConfig {
|
||||||
@Resource
|
|
||||||
OAProperties oaProperties;
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RequestInterceptor requestInterceptor() {
|
public FeignClientConfigurer feignClientConfigurer() {
|
||||||
return template -> {
|
return new FeignClientConfigurer() {
|
||||||
// 空实现屏蔽 全局拦截器 BladeFeignRequestInterceptor
|
@Override
|
||||||
template.header("Authorization", normalizeAuthorization(oaProperties.getAuthorization()));
|
public boolean inheritParentConfiguration() {
|
||||||
};
|
return false;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public OARequestInterceptor requestInterceptor(OAProperties oaProperties) {
|
||||||
|
return new OARequestInterceptor(oaProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Logger.Level feignLoggerLevel() {
|
||||||
|
return Logger.Level.FULL;
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Request.Options options() {
|
public Request.Options options() {
|
||||||
return new Request.Options(10, TimeUnit.SECONDS, 120, TimeUnit.SECONDS, true);
|
return new Request.Options(10, TimeUnit.SECONDS, 120, TimeUnit.SECONDS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String normalizeAuthorization(String authorization) {
|
|
||||||
if (StringUtil.isBlank(authorization)) {
|
|
||||||
return authorization;
|
|
||||||
}
|
|
||||||
if (StringUtil.startsWithIgnoreCase(authorization, "Basic ")
|
|
||||||
|| StringUtil.startsWithIgnoreCase(authorization, "Bearer ")) {
|
|
||||||
return authorization;
|
|
||||||
}
|
|
||||||
return "Basic " + authorization;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ public class OAProperties {
|
|||||||
private String baseUrl;
|
private String baseUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* authorization
|
* gwzh 网关 Authorization(Basic),与可用 curl 一致
|
||||||
*/
|
*/
|
||||||
private String authorization;
|
private String authorization;
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+2
-2
@@ -26,7 +26,7 @@ public interface IOAClient {
|
|||||||
* @param param
|
* @param param
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PostMapping("${thirdParty.oa.queryCompanyPageUrl:/api/hrm/resful/getHrmsubcompanyWithPage}")
|
@PostMapping("${thirdParty.oa.queryCompanyPageUrl:/gwzh/OA/OA_GET_COMPANY_LIST}")
|
||||||
OAResponse<OACompanyResponse> queryCompanyPage(@RequestBody OASearch<OACompanySearch> param);
|
OAResponse<OACompanyResponse> queryCompanyPage(@RequestBody OASearch<OACompanySearch> param);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,7 +34,7 @@ public interface IOAClient {
|
|||||||
* @param param
|
* @param param
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PostMapping("${thirdParty.oa.queryDepartmentPage:/api/hrm/resful/getHrmdepartmentWithPage}")
|
@PostMapping("${thirdParty.oa.queryDepartmentPageUrl:/gwzh/OA/OA_GET_DEPARTMENT_LIST}")
|
||||||
OAResponse<OADepartmentResponse> queryDepartmentPage(@RequestBody OASearch<OADepartmentSearch> param);
|
OAResponse<OADepartmentResponse> queryDepartmentPage(@RequestBody OASearch<OADepartmentSearch> param);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
|
* obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license
|
||||||
|
* from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party
|
||||||
|
* without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
|
* from this software for such purposes. Copyright of this software
|
||||||
|
* remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software
|
||||||
|
* must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.thirdparty.oa.interceptor;
|
||||||
|
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.tool.utils.StringUtil;
|
||||||
|
import org.springblade.thirdparty.oa.config.OAProperties;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OA Feign 请求拦截器。
|
||||||
|
* <p>
|
||||||
|
* 对齐可用 curl:仅发送 Authorization + Content-Type。
|
||||||
|
* 配合 {@code FeignClientConfigurer#inheritParentConfiguration()=false},
|
||||||
|
* 避免全局 BladeFeignRequestInterceptor 透传登录请求头。
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class OARequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
private static final String BASIC_PREFIX = "Basic ";
|
||||||
|
private static final String BEARER_PREFIX = "Bearer ";
|
||||||
|
private static final Set<String> KEEP_HEADERS = Set.of(
|
||||||
|
HttpHeaders.AUTHORIZATION.toLowerCase(Locale.ROOT),
|
||||||
|
HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ROOT)
|
||||||
|
);
|
||||||
|
|
||||||
|
private final OAProperties oaProperties;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate template) {
|
||||||
|
stripUnwantedHeaders(template);
|
||||||
|
template.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||||
|
|
||||||
|
String authorization = normalizeAuthorization(oaProperties.getAuthorization());
|
||||||
|
if (StringUtil.isNotBlank(authorization)) {
|
||||||
|
template.header(HttpHeaders.AUTHORIZATION, authorization);
|
||||||
|
} else {
|
||||||
|
log.warn("OA Feign 未配置 third-party.oa.authorization,gwzh 网关可能拒绝请求");
|
||||||
|
}
|
||||||
|
|
||||||
|
logRequest(template);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印 OA Feign 最终发出的请求头与 body,便于对照 curl。
|
||||||
|
*/
|
||||||
|
private void logRequest(RequestTemplate template) {
|
||||||
|
String bodyText = "";
|
||||||
|
byte[] body = template.body();
|
||||||
|
if (body != null && body.length > 0) {
|
||||||
|
Charset charset = template.requestCharset() == null ? StandardCharsets.UTF_8 : template.requestCharset();
|
||||||
|
bodyText = new String(body, charset);
|
||||||
|
}
|
||||||
|
log.info("OA Feign 请求 method={}, url={}{}{}, headers={}, body={}",
|
||||||
|
template.method(),
|
||||||
|
template.feignTarget() == null ? "" : template.feignTarget().url(),
|
||||||
|
template.path(),
|
||||||
|
template.queryLine() == null ? "" : template.queryLine(),
|
||||||
|
template.headers(),
|
||||||
|
bodyText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只保留 Authorization / Content-Type,其余全部移除。
|
||||||
|
*/
|
||||||
|
private void stripUnwantedHeaders(RequestTemplate template) {
|
||||||
|
Map<String, Collection<String>> headers = template.headers();
|
||||||
|
List<String> headerNames = new ArrayList<>(headers.keySet());
|
||||||
|
for (String headerName : headerNames) {
|
||||||
|
if (!KEEP_HEADERS.contains(headerName.toLowerCase(Locale.ROOT))) {
|
||||||
|
template.removeHeader(headerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeAuthorization(String authorization) {
|
||||||
|
if (StringUtil.isBlank(authorization)) {
|
||||||
|
return authorization;
|
||||||
|
}
|
||||||
|
if (StringUtil.startsWithIgnoreCase(authorization, BASIC_PREFIX)
|
||||||
|
|| StringUtil.startsWithIgnoreCase(authorization, BEARER_PREFIX)) {
|
||||||
|
return authorization;
|
||||||
|
}
|
||||||
|
return BASIC_PREFIX + authorization;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
<name>${project.artifactId}</name>
|
<name>${project.artifactId}</name>
|
||||||
<modules>
|
<modules>
|
||||||
<module>blade-oa-api</module>
|
<module>blade-oa-api</module>
|
||||||
|
<module>blade-lbs-api</module>
|
||||||
<module>blade-mk-api</module>
|
<module>blade-mk-api</module>
|
||||||
<module>blade-wps-api</module>
|
<module>blade-wps-api</module>
|
||||||
<module>blade-ocr-api</module>
|
<module>blade-ocr-api</module>
|
||||||
|
|||||||
@@ -86,8 +86,17 @@ thirdParty:
|
|||||||
baseUrl: http://127.0.0.1:8080
|
baseUrl: http://127.0.0.1:8080
|
||||||
oa:
|
oa:
|
||||||
# OA开放接口地址
|
# OA开放接口地址
|
||||||
baseUrl: http://127.0.0.1:8080
|
baseUrl: http://172.16.204.83:38000
|
||||||
|
queryCompanyPageUrl: /gwzh/OA/OA_GET_COMPANY_LIST
|
||||||
|
queryDepartmentPageUrl: /gwzh/OA/OA_GET_DEPARTMENT_LIST
|
||||||
queryPersonPageUrl: /gwzh/OA/OA_GET_USER_LIST
|
queryPersonPageUrl: /gwzh/OA/OA_GET_USER_LIST
|
||||||
|
authorization: ${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}}
|
||||||
|
lbs:
|
||||||
|
# LBS 网关地址(车辆实时定位)
|
||||||
|
baseUrl: http://172.16.204.83:38000
|
||||||
|
locateUrl: /gwzh/LBS/LBS_LOCATE
|
||||||
|
trackUrl: /gwzh/LBS/LBS_TRACK
|
||||||
|
authorization: ${LBS_AUTHORIZATION:${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}}}
|
||||||
track:
|
track:
|
||||||
# 轨迹开放接口地址
|
# 轨迹开放接口地址
|
||||||
baseUrl: http://127.0.0.1:8080
|
baseUrl: http://127.0.0.1:8080
|
||||||
@@ -109,6 +118,7 @@ thirdParty:
|
|||||||
processExecuteUrl: ${MK_PROCESS_EXECUTE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/execute}
|
processExecuteUrl: ${MK_PROCESS_EXECUTE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/execute}
|
||||||
processDeleteUrl: ${MK_PROCESS_DELETE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/delete}
|
processDeleteUrl: ${MK_PROCESS_DELETE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/delete}
|
||||||
getCurrentNodesUrl: ${MK_CURRENT_NODES_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}
|
getCurrentNodesUrl: ${MK_CURRENT_NODES_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}
|
||||||
|
getProcessInfoUrl: ${MK_PROCESS_INFO_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getProcessInfo}
|
||||||
getNodeHandlersUrl: ${MK_NODE_HANDLERS_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getNodeHandlerInfos}
|
getNodeHandlersUrl: ${MK_NODE_HANDLERS_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getNodeHandlerInfos}
|
||||||
getManualNodeUrl: ${MK_MANUAL_NODE_URL:/openapi/sys-lbpm/sysLbpmTemplate/openSupport/getManualNode}
|
getManualNodeUrl: ${MK_MANUAL_NODE_URL:/openapi/sys-lbpm/sysLbpmTemplate/openSupport/getManualNode}
|
||||||
pushOrgDeptUrl: ${MK_PUSH_ORG_DEPT_URL:/openapi/sys-org/v2/push/orgDept}
|
pushOrgDeptUrl: ${MK_PUSH_ORG_DEPT_URL:/openapi/sys-org/v2/push/orgDept}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ blade:
|
|||||||
##将docker脚本部署的redis服务映射为宿主机ip
|
##将docker脚本部署的redis服务映射为宿主机ip
|
||||||
##生产环境推荐使用阿里云高可用redis服务并设置密码
|
##生产环境推荐使用阿里云高可用redis服务并设置密码
|
||||||
address: redis://172.16.203.228:6379
|
address: redis://172.16.203.228:6379
|
||||||
|
password: ${spring.data.redis.password:}
|
||||||
#通用开发生产环境数据库地址(特殊情况可在对应的子工程里配置覆盖)
|
#通用开发生产环境数据库地址(特殊情况可在对应的子工程里配置覆盖)
|
||||||
datasource:
|
datasource:
|
||||||
prod:
|
prod:
|
||||||
@@ -58,8 +59,17 @@ thirdParty:
|
|||||||
baseUrl: http://127.0.0.1:8080
|
baseUrl: http://127.0.0.1:8080
|
||||||
oa:
|
oa:
|
||||||
# OA开放接口地址
|
# OA开放接口地址
|
||||||
baseUrl: http://127.0.0.1:8080
|
baseUrl: http://172.16.204.83:38000
|
||||||
|
queryCompanyPageUrl: /gwzh/OA/OA_GET_COMPANY_LIST
|
||||||
|
queryDepartmentPageUrl: /gwzh/OA/OA_GET_DEPARTMENT_LIST
|
||||||
queryPersonPageUrl: /gwzh/OA/OA_GET_USER_LIST
|
queryPersonPageUrl: /gwzh/OA/OA_GET_USER_LIST
|
||||||
|
authorization: ${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}}
|
||||||
|
lbs:
|
||||||
|
# LBS 网关地址(车辆实时定位)
|
||||||
|
baseUrl: http://172.16.204.83:38000
|
||||||
|
locateUrl: /gwzh/LBS/LBS_LOCATE
|
||||||
|
trackUrl: /gwzh/LBS/LBS_TRACK
|
||||||
|
authorization: ${LBS_AUTHORIZATION:${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}}}
|
||||||
track:
|
track:
|
||||||
# 轨迹开放接口地址
|
# 轨迹开放接口地址
|
||||||
baseUrl: http://127.0.0.1:8080
|
baseUrl: http://127.0.0.1:8080
|
||||||
@@ -81,6 +91,7 @@ thirdParty:
|
|||||||
processExecuteUrl: ${MK_PROCESS_EXECUTE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/execute}
|
processExecuteUrl: ${MK_PROCESS_EXECUTE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/execute}
|
||||||
processDeleteUrl: ${MK_PROCESS_DELETE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/delete}
|
processDeleteUrl: ${MK_PROCESS_DELETE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/delete}
|
||||||
getCurrentNodesUrl: ${MK_CURRENT_NODES_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}
|
getCurrentNodesUrl: ${MK_CURRENT_NODES_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}
|
||||||
|
getProcessInfoUrl: ${MK_PROCESS_INFO_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getProcessInfo}
|
||||||
getNodeHandlersUrl: ${MK_NODE_HANDLERS_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getNodeHandlerInfos}
|
getNodeHandlersUrl: ${MK_NODE_HANDLERS_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getNodeHandlerInfos}
|
||||||
getManualNodeUrl: ${MK_MANUAL_NODE_URL:/openapi/sys-lbpm/sysLbpmTemplate/openSupport/getManualNode}
|
getManualNodeUrl: ${MK_MANUAL_NODE_URL:/openapi/sys-lbpm/sysLbpmTemplate/openSupport/getManualNode}
|
||||||
pushOrgDeptUrl: ${MK_PUSH_ORG_DEPT_URL:/openapi/sys-org/v2/push/orgDept}
|
pushOrgDeptUrl: ${MK_PUSH_ORG_DEPT_URL:/openapi/sys-org/v2/push/orgDept}
|
||||||
|
|||||||
@@ -216,6 +216,16 @@ blade:
|
|||||||
# 退出登录:允许无令牌/令牌失效时也能调用(服务端对无用户直接返回成功)
|
# 退出登录:允许无令牌/令牌失效时也能调用(服务端对无用户直接返回成功)
|
||||||
- /oauth/logout/**
|
- /oauth/logout/**
|
||||||
- /blade-auth/oauth/logout/**
|
- /blade-auth/oauth/logout/**
|
||||||
|
- /blade-transport/customer-archive/public/**
|
||||||
|
- /customer-archive/public/**
|
||||||
|
- /blade-transport/mk-process/public/**
|
||||||
|
- /mk-process/public/**
|
||||||
|
- /blade-openapi/openApi/mk/process/commonCallback
|
||||||
|
- /openApi/mk/process/commonCallback
|
||||||
|
- /feign/client/businessProcess/getCurrentNodes
|
||||||
|
- /feign/client/businessProcess/getProcessInfo
|
||||||
|
- /feign/client/customerArchive/syncProcessNode
|
||||||
|
- /feign/client/mkProcess/**
|
||||||
#授权认证配置
|
#授权认证配置
|
||||||
auth:
|
auth:
|
||||||
- method: ALL
|
- method: ALL
|
||||||
|
|||||||
@@ -10,8 +10,17 @@ thirdParty:
|
|||||||
baseUrl: ${WPS_BASE_URL:http://127.0.0.1:8080}
|
baseUrl: ${WPS_BASE_URL:http://127.0.0.1:8080}
|
||||||
oa:
|
oa:
|
||||||
# OA开放接口地址
|
# OA开放接口地址
|
||||||
baseUrl: ${OA_BASE_URL:http://127.0.0.1:8080}
|
baseUrl: ${OA_BASE_URL:http://172.16.204.83:38000}
|
||||||
|
queryCompanyPageUrl: ${OA_QUERY_COMPANY_PAGE_URL:/gwzh/OA/OA_GET_COMPANY_LIST}
|
||||||
|
queryDepartmentPageUrl: ${OA_QUERY_DEPARTMENT_PAGE_URL:/gwzh/OA/OA_GET_DEPARTMENT_LIST}
|
||||||
queryPersonPageUrl: ${OA_QUERY_PERSON_PAGE_URL:/gwzh/OA/OA_GET_USER_LIST}
|
queryPersonPageUrl: ${OA_QUERY_PERSON_PAGE_URL:/gwzh/OA/OA_GET_USER_LIST}
|
||||||
|
authorization: ${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:}}
|
||||||
|
lbs:
|
||||||
|
# LBS 网关地址(车辆实时定位)
|
||||||
|
baseUrl: ${LBS_BASE_URL:${OA_BASE_URL:http://172.16.204.83:38000}}
|
||||||
|
locateUrl: ${LBS_LOCATE_URL:/gwzh/LBS/LBS_LOCATE}
|
||||||
|
trackUrl: ${LBS_TRACK_URL:/gwzh/LBS/LBS_TRACK}
|
||||||
|
authorization: ${LBS_AUTHORIZATION:${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:}}}
|
||||||
track:
|
track:
|
||||||
# 轨迹开放接口地址
|
# 轨迹开放接口地址
|
||||||
baseUrl: ${TRACK_BASE_URL:http://127.0.0.1:8080}
|
baseUrl: ${TRACK_BASE_URL:http://127.0.0.1:8080}
|
||||||
|
|||||||
@@ -1757,6 +1757,7 @@ INSERT INTO `blade_menu` (`id`, `parent_id`, `code`, `name`, `alias`, `path`, `s
|
|||||||
DROP TABLE IF EXISTS `blade_measurement_unit`;
|
DROP TABLE IF EXISTS `blade_measurement_unit`;
|
||||||
CREATE TABLE `blade_measurement_unit` (
|
CREATE TABLE `blade_measurement_unit` (
|
||||||
`id` bigint NOT NULL COMMENT '主键',
|
`id` bigint NOT NULL COMMENT '主键',
|
||||||
|
`unit_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量单位编码',
|
||||||
`unit_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量单位',
|
`unit_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量单位',
|
||||||
`dimension` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量维度',
|
`dimension` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量维度',
|
||||||
`remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
|
`remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
|
||||||
@@ -1768,6 +1769,7 @@ CREATE TABLE `blade_measurement_unit` (
|
|||||||
`status` int NULL DEFAULT 1 COMMENT '状态',
|
`status` int NULL DEFAULT 1 COMMENT '状态',
|
||||||
`is_deleted` int NULL DEFAULT 0 COMMENT '是否已删除',
|
`is_deleted` int NULL DEFAULT 0 COMMENT '是否已删除',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE INDEX `uk_measurement_unit_code`(`unit_code`) USING BTREE,
|
||||||
UNIQUE INDEX `uk_measurement_unit_name`(`unit_name`) USING BTREE,
|
UNIQUE INDEX `uk_measurement_unit_name`(`unit_name`) USING BTREE,
|
||||||
INDEX `idx_measurement_unit_dimension`(`dimension`) USING BTREE,
|
INDEX `idx_measurement_unit_dimension`(`dimension`) USING BTREE,
|
||||||
INDEX `idx_measurement_unit_status`(`status`) USING BTREE
|
INDEX `idx_measurement_unit_status`(`status`) USING BTREE
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
DROP TABLE IF EXISTS `blade_measurement_unit`;
|
DROP TABLE IF EXISTS `blade_measurement_unit`;
|
||||||
CREATE TABLE `blade_measurement_unit` (
|
CREATE TABLE `blade_measurement_unit` (
|
||||||
`id` bigint NOT NULL COMMENT '主键',
|
`id` bigint NOT NULL COMMENT '主键',
|
||||||
|
`unit_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量单位编码',
|
||||||
`unit_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量单位',
|
`unit_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量单位',
|
||||||
`dimension` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量维度',
|
`dimension` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量维度',
|
||||||
`remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
|
`remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
|
||||||
@@ -15,6 +16,7 @@ CREATE TABLE `blade_measurement_unit` (
|
|||||||
`status` int NULL DEFAULT 1 COMMENT '状态',
|
`status` int NULL DEFAULT 1 COMMENT '状态',
|
||||||
`is_deleted` int NULL DEFAULT 0 COMMENT '是否已删除',
|
`is_deleted` int NULL DEFAULT 0 COMMENT '是否已删除',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE INDEX `uk_measurement_unit_code`(`unit_code`) USING BTREE,
|
||||||
UNIQUE INDEX `uk_measurement_unit_name`(`unit_name`) USING BTREE,
|
UNIQUE INDEX `uk_measurement_unit_name`(`unit_name`) USING BTREE,
|
||||||
INDEX `idx_measurement_unit_dimension`(`dimension`) USING BTREE,
|
INDEX `idx_measurement_unit_dimension`(`dimension`) USING BTREE,
|
||||||
INDEX `idx_measurement_unit_status`(`status`) USING BTREE
|
INDEX `idx_measurement_unit_status`(`status`) USING BTREE
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
-- 计量单位新增计量单位编码
|
||||||
|
ALTER TABLE `blade_measurement_unit`
|
||||||
|
ADD COLUMN `unit_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '计量单位编码' AFTER `id`;
|
||||||
|
|
||||||
|
UPDATE `blade_measurement_unit`
|
||||||
|
SET `unit_code` = CONCAT('MU', `id`)
|
||||||
|
WHERE `unit_code` IS NULL OR `unit_code` = '';
|
||||||
|
|
||||||
|
ALTER TABLE `blade_measurement_unit`
|
||||||
|
MODIFY COLUMN `unit_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '计量单位编码',
|
||||||
|
ADD UNIQUE INDEX `uk_measurement_unit_code`(`unit_code`) USING BTREE;
|
||||||
@@ -124,6 +124,11 @@
|
|||||||
<artifactId>blade-oa-api</artifactId>
|
<artifactId>blade-oa-api</artifactId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springblade</groupId>
|
||||||
|
<artifactId>blade-lbs-api</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springblade</groupId>
|
<groupId>org.springblade</groupId>
|
||||||
<artifactId>blade-open-api</artifactId>
|
<artifactId>blade-open-api</artifactId>
|
||||||
|
|||||||
Reference in New Issue
Block a user