diff --git a/pom.xml b/pom.xml index 2462d3a6..aec4d8b8 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ https://github.com/YunaiV/ruoyi-vue-pro - 3.0.39 + 3.0.40 17 ${java.version} diff --git a/zt-dependencies/pom.xml b/zt-dependencies/pom.xml index 1cfcb2e1..a89588ec 100644 --- a/zt-dependencies/pom.xml +++ b/zt-dependencies/pom.xml @@ -26,7 +26,7 @@ https://github.com/YunaiV/ruoyi-vue-pro - 3.0.39 + 3.0.40 1.6.0 3.4.5 diff --git a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/BpmProcessInstanceApi.java b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/BpmProcessInstanceApi.java index baf8f52d..89839e8f 100644 --- a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/BpmProcessInstanceApi.java +++ b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/BpmProcessInstanceApi.java @@ -1,19 +1,16 @@ package com.zt.plat.module.bpm.api.task; import com.zt.plat.framework.common.pojo.CommonResult; -import com.zt.plat.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; -import com.zt.plat.module.bpm.api.task.dto.BpmTaskApproveReqDTO; -import com.zt.plat.module.bpm.api.task.dto.BpmTaskRejectReqDTO; +import com.zt.plat.module.bpm.api.task.dto.*; import com.zt.plat.module.bpm.enums.ApiConstants; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.*; + +import java.util.List; @FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = @Tag(name = "RPC 服务 - 流程实例") @@ -27,6 +24,37 @@ public interface BpmProcessInstanceApi { CommonResult createProcessInstance(@RequestParam("userId") Long userId, @Valid @RequestBody BpmProcessInstanceCreateReqDTO reqDTO); + @GetMapping(PREFIX + "/get") + @Operation(summary = "获得指定流程实例", description = "在【流程详细】界面中,进行调用") + @Parameter(name = "id", description = "流程实例的编号", required = true) + CommonResult getProcessInstance(@RequestParam("id") String id); + + @DeleteMapping(PREFIX + "/cancel-by-start-user") + @Operation(summary = "用户取消流程实例", description = "取消发起的流程") + CommonResult cancelProcessInstanceByStartUser( + @RequestParam("userId") Long userId, + @Valid @RequestBody BpmProcessInstanceCancelReqDTO cancelReqDTO); + + @DeleteMapping(PREFIX + "/cancel-by-admin") + @Operation(summary = "管理员取消流程实例", description = "管理员撤回流程") + CommonResult cancelProcessInstanceByAdmin( + @RequestParam("userId") Long userId, + @Valid @RequestBody BpmProcessInstanceCancelReqDTO cancelReqDTO); + + @PostMapping(PREFIX + "/get-approval-detail") + @Operation(summary = "获得审批详情") + CommonResult getApprovalDetail(@RequestParam("userId") Long userId, + @Valid BpmApprovalDetailReqDTO reqDTO); + + @PostMapping(PREFIX + "/get-next-approval-nodes") + @Operation(summary = "获取下一个执行的流程节点") + CommonResult> getNextApprovalNodes(@RequestParam("userId") Long userId, + @Valid BpmApprovalDetailReqDTO reqDTO); + + @PostMapping(PREFIX + "/get-bpmn-model-view") + @Operation(summary = "获取流程实例的 BPMN 模型视图", description = "在【流程详细】界面中,进行调用") + @Parameter(name = "id", description = "流程实例的编号", required = true) + CommonResult getProcessInstanceBpmnModelView(@RequestParam(value = "id") String id); @PutMapping(PREFIX + "/approveTask") @Operation(summary = "通过任务") diff --git a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmApprovalDetailReqDTO.java b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmApprovalDetailReqDTO.java new file mode 100644 index 00000000..47943869 --- /dev/null +++ b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmApprovalDetailReqDTO.java @@ -0,0 +1,40 @@ +package com.zt.plat.module.bpm.api.task.dto; + +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.AssertTrue; +import lombok.Data; + +import java.util.Map; + +@Schema(description = "RPC 服务 - 审批详情 Request DTO") +@Data +public class BpmApprovalDetailReqDTO { + + @Schema(description = "流程定义的编号", example = "1024") + private String processDefinitionId; // 使用场景:发起流程时,传流程定义 ID + + @Schema(description = "流程变量") + private Map processVariables; // 使用场景:同 processDefinitionId,用于流程预测 + + @Schema(description = "流程变量") + private String processVariablesStr; // 解决 GET 无法传递对象的问题,最终转换成 processVariables 变量 + + @Schema(description = "流程实例的编号", example = "1024") + private String processInstanceId; // 使用场景:流程已发起时候传流程实例 ID + + // TODO @芋艿:如果未来 BPMN 增加流程图,它没有发起人节点,会有问题。 + @Schema(description = "流程活动编号", example = "StartUserNode") + private String activityId; // 用于获取表单权限。1)发起流程时,传"发起人节点" activityId 可获取发起人的表单权限;2)从抄送列表界面进来时,传抄送的 activityId 可获取抄送人的表单权限; + + @Schema(description = "流程任务编号", example = "95f2f08b-621b-11ef-bf39-00ff4722db8b") + private String taskId; // 用于获取表单权限。1)从待审批/已审批界面进来时,传递 taskId 任务编号,可获取任务节点的变得权限 + + @AssertTrue(message = "流程定义的编号和流程实例的编号不能同时为空") + @JsonIgnore + public boolean isValidProcessParam() { + return StrUtil.isNotEmpty(processDefinitionId) || StrUtil.isNotEmpty(processInstanceId); + } + +} \ No newline at end of file diff --git a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmApprovalDetailRespDTO.java b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmApprovalDetailRespDTO.java new file mode 100644 index 00000000..31835614 --- /dev/null +++ b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmApprovalDetailRespDTO.java @@ -0,0 +1,110 @@ +package com.zt.plat.module.bpm.api.task.dto; + +import com.zt.plat.module.bpm.api.task.dto.BpmTaskRespDTO; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + + +@Schema(description = "RPC 服务 - 审批详情 Response DTO") +@Data +public class BpmApprovalDetailRespDTO { + + @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 + + @Schema(description = "活动节点列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List activityNodes; + + @Schema(description = "表单字段权限") + private Map formFieldsPermission; + + @Schema(description = "待办任务") + private BpmTaskRespDTO todoTask; + + /** + * 所属流程定义信息 + */ + private BpmProcessDefinitionRespDTO processDefinition; + + /** + * 所属流程实例信息 + */ + private BpmProcessInstanceRespDTO processInstance; + + @Schema(description = "活动节点信息") + @Data + public static class ActivityNode { + + @Schema(description = "节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "StartUserNode") + private String id; + + @Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "发起人") + private String name; + + @Schema(description = "节点类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer nodeType; // 参见 BpmSimpleModelNodeType 枚举 + + @Schema(description = "节点状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer status; // 参见 BpmTaskStatusEnum 枚举 + + @Schema(description = "节点的开始时间") + private LocalDateTime startTime; + @Schema(description = "节点的结束时间") + private LocalDateTime endTime; + + @Schema(description = "审批节点的任务信息") + private List tasks; + + @Schema(description = "候选人策略", example = "35") + private Integer candidateStrategy; // 参见 BpmTaskCandidateStrategyEnum 枚举。主要用于发起时,审批节点、抄送节点自选 + + @Schema(description = "候选人用户 ID 列表", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1818") + @JsonIgnore // 不返回,只是方便后续读取,赋值给 candidateUsers + private List candidateUserIds; + + @Schema(description = "候选人用户列表") + private List candidateUsers; // 只包含未生成 ApprovalTaskInfo 的用户列表 + + @Schema(description = "流程编号", example = "8761d8e0-0922-11f0-bd37-00ff1db677bf") + private String processInstanceId; // 当且仅当,该节点是子流程节点时,才会有值(CallActivity 的 processInstanceId 字段) + + } + + @Schema(description = "活动节点的任务信息") + @Data + public static class ActivityNodeTask { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String id; + + @Schema(description = "任务所属人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1818") + @JsonIgnore // 不返回,只是方便后续读取,赋值给 ownerUser + private Long owner; + + @Schema(description = "任务所属人", example = "1024") + private UserSimpleDTO ownerUser; + + @Schema(description = "任务分配人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048") + @JsonIgnore // 不返回,只是方便后续读取,赋值给 assigneeUser + private Long assignee; + + @Schema(description = "任务分配人", example = "2048") + private UserSimpleDTO assigneeUser; + + @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; // 参见 BpmTaskStatusEnum 枚举 + + @Schema(description = "审批意见", example = "同意") + private String reason; + + @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png") + private String signPicUrl; + + } + +} \ No newline at end of file diff --git a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessDefinitionRespDTO.java b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessDefinitionRespDTO.java new file mode 100644 index 00000000..81aec421 --- /dev/null +++ b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessDefinitionRespDTO.java @@ -0,0 +1,55 @@ +package com.zt.plat.module.bpm.api.task.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "RPC 服务 - 流程定义 Response DTO") +@Data +public class BpmProcessDefinitionRespDTO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "process_order") + private String key; + + @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "请假流程") + private String name; + + @Schema(description = "流程描述", example = "请假流程描述") + private String description; + + @Schema(description = "流程分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "oa") + private String category; + + @Schema(description = "表单类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer formType; + + @Schema(description = "表单编号", example = "1024") + private Long formId; + + @Schema(description = "表单的配置", requiredMode = Schema.RequiredMode.REQUIRED) + private String formConf; + + @Schema(description = "表单项的数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List formFields; + + @Schema(description = "表单项的 JSON 数组字符串", requiredMode = Schema.RequiredMode.REQUIRED) + private String formFieldsStr; + + @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED) + private String bpmnXml; + + @Schema(description = "版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer version; + + @Schema(description = "是否挂起", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Integer suspensionState; + + @Schema(description = "部署时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime deploymentTime; + +} \ No newline at end of file diff --git a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstanceBpmnModelViewRespDTO.java b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstanceBpmnModelViewRespDTO.java new file mode 100644 index 00000000..9b1f2c32 --- /dev/null +++ b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstanceBpmnModelViewRespDTO.java @@ -0,0 +1,41 @@ +package com.zt.plat.module.bpm.api.task.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; +import java.util.Set; + +@Schema(description = "RPC 服务 - 流程示例的 BPMN 视图 Response DTO") +@Data +public class BpmProcessInstanceBpmnModelViewRespDTO { + + // ========== 基本信息 ========== + + @Schema(description = "流程实例信息", requiredMode = Schema.RequiredMode.REQUIRED) + private BpmProcessInstanceRespDTO processInstance; + + @Schema(description = "任务列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List tasks; + + @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED) + private String bpmnXml; + + @Schema(description = "SIMPLE 模型") + private BpmSimpleModelNodeDTO simpleModel; + + // ========== 进度信息 ========== + + @Schema(description = "进行中的活动节点编号集合", requiredMode = Schema.RequiredMode.REQUIRED) + private Set unfinishedTaskActivityIds; // 只包括 UserTask + + @Schema(description = "已经完成的活动节点编号集合", requiredMode = Schema.RequiredMode.REQUIRED) + private Set finishedTaskActivityIds; // 包括 UserTask、Gateway 等,不包括 SequenceFlow + + @Schema(description = "已经完成的连线节点编号集合", requiredMode = Schema.RequiredMode.REQUIRED) + private Set finishedSequenceFlowActivityIds; // 只包括 SequenceFlow + + @Schema(description = "已经拒绝的活动节点编号集合", requiredMode = Schema.RequiredMode.REQUIRED) + private Set rejectedTaskActivityIds; // 只包括 UserTask + +} \ No newline at end of file diff --git a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstanceCancelReqDTO.java b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstanceCancelReqDTO.java new file mode 100644 index 00000000..15316d04 --- /dev/null +++ b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstanceCancelReqDTO.java @@ -0,0 +1,19 @@ +package com.zt.plat.module.bpm.api.task.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +@Schema(description = "RPC 服务 - 流程实例的取消 Request DTO") +@Data +public class BpmProcessInstanceCancelReqDTO { + + @Schema(description = "流程实例的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "流程实例的编号不能为空") + private String id; + + @Schema(description = "取消原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "不请假了!") + @NotEmpty(message = "取消原因不能为空") + private String reason; + +} \ No newline at end of file diff --git a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstancePageReqDTO.java b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstancePageReqDTO.java index b041098d..ce6c38c0 100644 --- a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstancePageReqDTO.java +++ b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstancePageReqDTO.java @@ -22,6 +22,9 @@ public class BpmProcessInstancePageReqDTO extends PageParam { @Schema(description = "流程定义的编号", example = "2048") private String processDefinitionId; + @Schema(description = "流程定义的标识", example = "2048") + private String processDefinitionKey; // 精准匹配 + @Schema(description = "流程分类", example = "1") private String category; @@ -35,4 +38,14 @@ public class BpmProcessInstancePageReqDTO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; + @Schema(description = "结束时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] endTime; + + @Schema(description = "发起用户编号", example = "1024") + private Long startUserId; // 注意,只有在【流程实例】菜单,才使用该参数 + + @Schema(description = "动态表单字段查询 JSON Str", example = "{}") + private String formFieldsParams; // SpringMVC 在 get 请求下,无法方便的定义 Map 类型的参数,所以通过 String 接收后,逻辑里面转换 + } \ No newline at end of file diff --git a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstanceRespDTO.java b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstanceRespDTO.java index 1138169d..48c779c4 100644 --- a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstanceRespDTO.java +++ b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmProcessInstanceRespDTO.java @@ -1,9 +1,12 @@ package com.zt.plat.module.bpm.api.task.dto; +import com.zt.plat.framework.common.core.KeyValue; +import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; +import java.util.List; import java.util.Map; @Schema(description = "RPC 服务 - 流程实例 Response DTO") @@ -16,23 +19,26 @@ public class BpmProcessInstanceRespDTO { @Schema(description = "流程实例的名字", example = "芋艿") private String name; + @Schema(description = "流程摘要") + private List> summary; // 只有流程表单,才有摘要! + @Schema(description = "流程定义的编号", example = "2048") private String processDefinitionId; @Schema(description = "流程分类", example = "1") private String category; + @Schema(description = "流程分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "请假") + private String categoryName; + @Schema(description = "流程实例的状态", example = "1") private Integer status; @Schema(description = "流程实例的结果", example = "1") private Integer result; - @Schema(description = "提交的表单值", example = "{\"name\": \"芋艿\"}") - private Map formVariables; - - @Schema(description = "业务的唯一标识", example = "1") - private String businessKey; + @Schema(description = "发起时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; @Schema(description = "创建时间") private LocalDateTime createTime; @@ -43,4 +49,44 @@ public class BpmProcessInstanceRespDTO { @Schema(description = "持续时间", example = "1000") private Long durationInMillis; + @Schema(description = "提交的表单值", example = "{\"name\": \"芋艿\"}") + private Map formVariables; + + @Schema(description = "业务的唯一标识", example = "1") + private String businessKey; + + /** + * 发起流程的用户 + */ + private UserSimpleDTO startUser; + + /** + * 流程定义 + */ + private BpmProcessDefinitionRespDTO processDefinition; + + /** + * 当前审批中的任务 + */ + private List tasks; // 仅在流程实例分页才返回 + + @Schema(description = "流程任务") + @Data + public static class Task { + + @Schema(description = "流程任务的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + + @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "任务分配人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048") + @JsonIgnore // 不返回,只是方便后续读取,赋值给 assigneeUser + private Long assignee; + + @Schema(description = "任务分配人", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048") + private UserSimpleDTO assigneeUser; + + } + } \ No newline at end of file diff --git a/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmSimpleModelNodeDTO.java b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmSimpleModelNodeDTO.java new file mode 100644 index 00000000..a01c60dd --- /dev/null +++ b/zt-module-bpm/zt-module-bpm-api/src/main/java/com/zt/plat/module/bpm/api/task/dto/BpmSimpleModelNodeDTO.java @@ -0,0 +1,31 @@ +package com.zt.plat.module.bpm.api.task.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Schema(description = "RPC 服务 - 简单模型节点 DTO") +@Data +public class BpmSimpleModelNodeDTO { + + @Schema(description = "节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "StartNode") + private String id; + + @Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "开始节点") + private String name; + + @Schema(description = "节点类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "节点属性") + private Map attributes; + + @Schema(description = "子节点列表") + private List childNode; + + @Schema(description = "条件节点列表") + private List conditionNodes; + +} \ No newline at end of file diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/api/task/BpmProcessInstanceApiImpl.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/api/task/BpmProcessInstanceApiImpl.java index 9b84efe8..b3d1e79f 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/api/task/BpmProcessInstanceApiImpl.java +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/api/task/BpmProcessInstanceApiImpl.java @@ -1,21 +1,34 @@ package com.zt.plat.module.bpm.api.task; +import cn.hutool.core.util.StrUtil; +import com.zt.plat.framework.business.core.util.DeptUtil; import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.common.util.json.JsonUtils; +import com.zt.plat.framework.common.util.number.NumberUtils; import com.zt.plat.framework.common.util.object.BeanUtils; -import com.zt.plat.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; -import com.zt.plat.module.bpm.api.task.dto.BpmTaskApproveReqDTO; -import com.zt.plat.module.bpm.api.task.dto.BpmTaskRejectReqDTO; +import com.zt.plat.module.bpm.api.task.dto.*; +import com.zt.plat.module.bpm.controller.admin.task.vo.instance.*; import com.zt.plat.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import com.zt.plat.module.bpm.controller.admin.task.vo.task.BpmTaskRejectReqVO; +import com.zt.plat.module.bpm.convert.task.BpmProcessInstanceConvert; +import com.zt.plat.module.bpm.convert.task.BpmProcessInstanceDTOConvert; +import com.zt.plat.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import com.zt.plat.module.bpm.service.definition.BpmProcessDefinitionService; import com.zt.plat.module.bpm.service.task.BpmProcessInstanceService; import com.zt.plat.module.bpm.service.task.BpmTaskService; +import com.zt.plat.module.system.api.dept.DeptApi; +import com.zt.plat.module.system.api.dept.dto.DeptRespDTO; +import com.zt.plat.module.system.api.user.AdminUserApi; +import com.zt.plat.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; -import org.springframework.validation.annotation.Validated; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.repository.ProcessDefinition; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; +import java.util.List; +import java.util.Map; import static com.zt.plat.framework.common.pojo.CommonResult.success; import static com.zt.plat.framework.web.core.util.WebFrameworkUtils.getLoginUserId; @@ -27,7 +40,7 @@ import static com.zt.plat.framework.web.core.util.WebFrameworkUtils.getLoginUser * @author jason */ @RestController -@Validated +@Valid public class BpmProcessInstanceApiImpl implements BpmProcessInstanceApi { @Resource @@ -36,11 +49,92 @@ public class BpmProcessInstanceApiImpl implements BpmProcessInstanceApi { @Resource private BpmTaskService taskService; + @Resource + private BpmProcessDefinitionService processDefinitionService; + + @Resource + private AdminUserApi adminUserApi; + + @Resource + private DeptApi deptApi; + @Override - public CommonResult createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO) { + public CommonResult createProcessInstance(Long userId, @Valid @RequestBody BpmProcessInstanceCreateReqDTO reqDTO) { return success(processInstanceService.createProcessInstance(userId, reqDTO)); } + + @Override + public CommonResult getProcessInstance(String id) { + HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(id); + if (processInstance == null) { + return success(null); + } + + // 拼接返回 + ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( + processInstance.getProcessDefinitionId()); + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo( + processInstance.getProcessDefinitionId()); + AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); + DeptRespDTO dept = null; + if (startUser != null) { + Long deptId = DeptUtil.getDeptId(startUser); + if (deptId > 0) { + dept = deptApi.getDept(deptId).getCheckedData(); + } + } + BpmProcessInstanceRespVO vo = BpmProcessInstanceConvert.INSTANCE.buildProcessInstance(processInstance, + processDefinition, processDefinitionInfo, startUser, dept); + return success(BpmProcessInstanceDTOConvert.INSTANCE.convert(vo)); + } + + @Override + public CommonResult cancelProcessInstanceByStartUser( + Long userId, @Valid @RequestBody BpmProcessInstanceCancelReqDTO cancelReqDTO) { + BpmProcessInstanceCancelReqVO cancelReqVO = BpmProcessInstanceDTOConvert.INSTANCE.convertVO(cancelReqDTO); + processInstanceService.cancelProcessInstanceByStartUser(userId, cancelReqVO); + return success(true); + } + + @Override + public CommonResult cancelProcessInstanceByAdmin( + Long userId, @Valid @RequestBody BpmProcessInstanceCancelReqDTO cancelReqDTO) { + BpmProcessInstanceCancelReqVO cancelReqVO = BpmProcessInstanceDTOConvert.INSTANCE.convertVO(cancelReqDTO); + processInstanceService.cancelProcessInstanceByAdmin(userId, cancelReqVO); + return success(true); + } + + @Override + @SuppressWarnings("unchecked") + public CommonResult getApprovalDetail(Long userId, + @Valid @RequestBody BpmApprovalDetailReqDTO reqDTO) { + BpmApprovalDetailReqVO reqVO = BpmProcessInstanceDTOConvert.INSTANCE.convertVO(reqDTO); + if (StrUtil.isNotEmpty(reqDTO.getProcessVariablesStr())) { + reqVO.setProcessVariables(JsonUtils.parseObject(reqDTO.getProcessVariablesStr(), Map.class)); + } + BpmApprovalDetailRespVO respVO = processInstanceService.getApprovalDetail(userId, reqVO); + return success(BpmProcessInstanceDTOConvert.INSTANCE.convert(respVO)); + } + + @Override + @SuppressWarnings("unchecked") + public CommonResult> getNextApprovalNodes(Long userId, + @Valid @RequestBody BpmApprovalDetailReqDTO reqDTO) { + BpmApprovalDetailReqVO reqVO = BpmProcessInstanceDTOConvert.INSTANCE.convertVO(reqDTO); + if (StrUtil.isNotEmpty(reqDTO.getProcessVariablesStr())) { + reqVO.setProcessVariables(JsonUtils.parseObject(reqDTO.getProcessVariablesStr(), Map.class)); + } + List nodes = processInstanceService.getNextApprovalNodes(userId, reqVO); + return success(BpmProcessInstanceDTOConvert.INSTANCE.convertActivityNodes(nodes)); + } + + @Override + public CommonResult getProcessInstanceBpmnModelView(String id) { + BpmProcessInstanceBpmnModelViewRespVO respVO = processInstanceService.getProcessInstanceBpmnModelView(id); + return success(BpmProcessInstanceDTOConvert.INSTANCE.convert(respVO)); + } + @Override public CommonResult approveTask(BpmTaskApproveReqDTO reqVO) { taskService.approveTask(getLoginUserId(), BeanUtils.toBean(reqVO, BpmTaskApproveReqVO.class)); diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/convert/task/BpmProcessInstanceDTOConvert.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/convert/task/BpmProcessInstanceDTOConvert.java new file mode 100644 index 00000000..8d0a6ff2 --- /dev/null +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/convert/task/BpmProcessInstanceDTOConvert.java @@ -0,0 +1,67 @@ +package com.zt.plat.module.bpm.convert.task; + +import com.zt.plat.framework.common.pojo.PageResult; +import com.zt.plat.framework.common.util.object.BeanUtils; +import com.zt.plat.module.bpm.api.task.dto.*; +import com.zt.plat.module.bpm.controller.admin.task.vo.instance.*; +import com.zt.plat.module.bpm.controller.admin.base.user.UserSimpleBaseVO; +import com.zt.plat.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import com.zt.plat.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 流程实例 DTO 转换器 + * + * @author ZT + */ +@Mapper +public interface BpmProcessInstanceDTOConvert { + + BpmProcessInstanceDTOConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceDTOConvert.class); + + // VO to DTO + BpmProcessInstancePageReqDTO convert(BpmProcessInstancePageReqVO bean); + BpmProcessInstanceCancelReqDTO convert(BpmProcessInstanceCancelReqVO bean); + BpmApprovalDetailReqDTO convert(BpmApprovalDetailReqVO bean); + + // DTO to VO + BpmProcessInstancePageReqVO convertVO(BpmProcessInstancePageReqDTO bean); + BpmProcessInstanceCancelReqVO convertVO(BpmProcessInstanceCancelReqDTO bean); + BpmApprovalDetailReqVO convertVO(BpmApprovalDetailReqDTO bean); + + PageResult convertPage(PageResult pageResult); + BpmProcessInstanceRespDTO convert(BpmProcessInstanceRespVO bean); + BpmApprovalDetailRespDTO convert(BpmApprovalDetailRespVO bean); + BpmProcessInstanceBpmnModelViewRespDTO convert(BpmProcessInstanceBpmnModelViewRespVO bean); + + List convertActivityNodes(List nodes); + + // 内部类转换 + BpmProcessInstanceRespDTO.Task convert(BpmProcessInstanceRespVO.Task task); + BpmApprovalDetailRespDTO.ActivityNode convert(BpmApprovalDetailRespVO.ActivityNode node); + BpmApprovalDetailRespDTO.ActivityNodeTask convert(BpmApprovalDetailRespVO.ActivityNodeTask task); + + // 用户信息转换 + UserSimpleDTO convertUser(UserSimpleBaseVO user); + BpmProcessDefinitionRespDTO convert(BpmProcessDefinitionRespVO definition); + + @Mapping(target = "childNode", source = "childNode", qualifiedByName = "mapChildNode") + BpmSimpleModelNodeDTO convert(BpmSimpleModelNodeVO simpleModel); + + /** + * 将BpmSimpleModelNodeVO的childNode转换为List + */ + @Named("mapChildNode") + default List mapChildNode(BpmSimpleModelNodeVO childNode) { + if (childNode == null) { + return null; + } + return List.of(convert(childNode)); + } + +} \ No newline at end of file diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/ErrorCodeConstants.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/ErrorCodeConstants.java index 4ce0734a..ec102499 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/ErrorCodeConstants.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/ErrorCodeConstants.java @@ -18,6 +18,8 @@ public interface ErrorCodeConstants { ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1_002_000_007, "手机号不存在"); ErrorCode AUTH_REGISTER_CAPTCHA_CODE_ERROR = new ErrorCode(1_002_000_008, "验证码不正确,原因:{}"); ErrorCode AUTH_TEST_LOGIN_NOT_ALLOWED = new ErrorCode(1_002_000_009, "测试登录接口仅在测试环境和本地开发环境下可用"); + ErrorCode AUTH_OAUTH2_CALLBACK_ERROR = new ErrorCode(1_002_000_010, "OAuth2回调处理失败:{}"); + ErrorCode AUTH_LOGIN_INTERNAL_USER_PASSWORD_NOT_ALLOWED = new ErrorCode(1_002_000_011, "内部用户不允许使用账号密码登录,请通过e办进行统一登录"); // ========== 菜单模块 1-002-001-000 ========== ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1_002_001_000, "已经存在该名字的菜单"); diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/AuthController.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/AuthController.java index a678a834..6727ef8e 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/AuthController.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/AuthController.java @@ -179,4 +179,28 @@ public class AuthController { return success(authService.socialLogin(reqVO)); } + @PostMapping("/oauth2/callback") + @PermitAll + @Operation(summary = "OAuth2回调处理", description = "处理第三方OAuth2认证回调") + @TenantIgnore + public CommonResult oauth2Callback(@RequestBody @Valid AuthOAuth2CallbackReqVO reqVO) { + return success(authService.oauth2Callback(reqVO)); + } + + @GetMapping("/check-user-type") + @PermitAll + @Operation(summary = "检查用户类型", description = "根据用户名判断是内部用户还是外部用户") + @TenantIgnore + public CommonResult checkUserType(@RequestParam("username") String username) { + return success(authService.checkUserType(username)); + } + + @GetMapping("/get-eban-login-url") + @PermitAll + @Operation(summary = "获取e办登录URL", description = "获取e办系统的OAuth2登录地址") + @TenantIgnore + public CommonResult getEbanLoginUrl() { + return success(authService.getEbanLoginUrl()); + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthOAuth2CallbackReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthOAuth2CallbackReqVO.java new file mode 100644 index 00000000..e5960c48 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthOAuth2CallbackReqVO.java @@ -0,0 +1,24 @@ +package com.zt.plat.module.system.controller.admin.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - OAuth2回调 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthOAuth2CallbackReqVO { + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "abc123") + @NotEmpty(message = "授权码不能为空") + private String code; + + @Schema(description = "状态参数", example = "111") + private String state; + +} \ No newline at end of file diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthUserTypeRespVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthUserTypeRespVO.java new file mode 100644 index 00000000..5e0d5170 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthUserTypeRespVO.java @@ -0,0 +1,22 @@ +package com.zt.plat.module.system.controller.admin.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 用户类型检查 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthUserTypeRespVO { + + @Schema(description = "是否为内部用户(E办用户)", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean isInternal; + + @Schema(description = "E办登录跳转URL", example = "http://10.2.137.42/idp/oauth2/authorize?...") + private String ebanLoginUrl; + +} \ No newline at end of file diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthService.java index ff2415e2..47ba26df 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthService.java @@ -93,4 +93,27 @@ public interface AdminAuthService { */ void resetPassword(AuthResetPasswordReqVO reqVO); + /** + * OAuth2回调处理 + * + * @param reqVO OAuth2回调信息 + * @return 登录结果 + */ + AuthLoginRespVO oauth2Callback(AuthOAuth2CallbackReqVO reqVO); + + /** + * 检查用户类型 + * + * @param username 用户名 + * @return 用户类型信息 + */ + AuthUserTypeRespVO checkUserType(String username); + + /** + * 获取e办登录URL + * + * @return e办系统的OAuth2登录地址 + */ + String getEbanLoginUrl(); + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java index d8e8dd0f..8ed4d3f5 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java @@ -22,8 +22,10 @@ import com.zt.plat.module.system.enums.sms.SmsSceneEnum; import com.zt.plat.module.system.service.logger.LoginLogService; import com.zt.plat.module.system.service.member.MemberService; import com.zt.plat.module.system.service.oauth2.OAuth2TokenService; +import com.zt.plat.module.system.service.oauth2.EbanOAuth2Service; import com.zt.plat.module.system.service.social.SocialUserService; import com.zt.plat.module.system.service.user.AdminUserService; +import com.zt.plat.module.system.enums.user.UserSourceEnum; import com.anji.captcha.model.common.ResponseModel; import com.anji.captcha.model.vo.CaptchaVO; import com.anji.captcha.service.CaptchaService; @@ -68,9 +70,24 @@ public class AdminAuthServiceImpl implements AdminAuthService { private CaptchaService captchaService; @Resource private SmsCodeApi smsCodeApi; + @Resource + private EbanOAuth2Service ebanOAuth2Service; @Value("${sync.encrypt-key}") private String encryptKey; + // E办OAuth2配置 + @Value("${eban.oauth2.authorize-url:http://10.2.137.42/idp/oauth2/authorize}") + private String ebanAuthorizeUrl; + + @Value("${eban.oauth2.client-id:tyszhjyglxt}") + private String ebanClientId; + + @Value("${eban.oauth2.redirect-uri:http://172.16.46.63:30080/system/oauth2/callback}") + private String ebanRedirectUri; + + @Value("${eban.oauth2.response-type:code}") + private String ebanResponseType; + /** * 验证码的开关,默认为 true */ @@ -113,6 +130,12 @@ public class AdminAuthServiceImpl implements AdminAuthService { // 使用账号密码,进行登录 AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword()); + + // 检查是否为内部用户,内部用户不允许账号密码登录 + if (isInternalUser(user)) { + createLoginLog(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.BAD_CREDENTIALS); + throw exception(AUTH_LOGIN_INTERNAL_USER_PASSWORD_NOT_ALLOWED); + } // 如果 socialType 非空,说明需要绑定社交用户 if (reqVO.getSocialType() != null) { @@ -130,6 +153,12 @@ public class AdminAuthServiceImpl implements AdminAuthService { // 使用账号密码,进行登录(跳过验证码校验) AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword()); + + // 检查是否为内部用户,内部用户不允许账号密码登录 + if (isInternalUser(user)) { + createLoginLog(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.BAD_CREDENTIALS); + throw exception(AUTH_LOGIN_INTERNAL_USER_PASSWORD_NOT_ALLOWED); + } // 创建 Token 令牌,记录登录日志 return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME); @@ -345,4 +374,75 @@ public class AdminAuthServiceImpl implements AdminAuthService { throw exception(AUTH_TEST_LOGIN_NOT_ALLOWED); } } + + @Override + public AuthLoginRespVO oauth2Callback(AuthOAuth2CallbackReqVO reqVO) { + // 委托给专门的E办OAuth2服务处理 + return ebanOAuth2Service.handleCallback(reqVO); + } + + @Override + public AuthUserTypeRespVO checkUserType(String username) { + AdminUserDO user = userService.getUserByUsername(username); + + // 用户不存在,抛出异常 + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + + // 判断用户类型 + boolean isInternal = isInternalUser(user); + + AuthUserTypeRespVO.AuthUserTypeRespVOBuilder builder = AuthUserTypeRespVO.builder() + .isInternal(isInternal); + + // 如果是内部用户,生成E办登录URL + if (isInternal) { + String ebanLoginUrl = buildEbanLoginUrl(); + builder.ebanLoginUrl(ebanLoginUrl); + } + + return builder.build(); + } + + /** + * 判断是否为内部用户 + * 根据UserSourceEnum判断:同步用户为内部用户,外部用户为外部用户 + */ + private boolean isInternalUser(AdminUserDO user) { + // 根据userSource字段判断用户类型 + Integer userSource = user.getUserSource(); + + // 同步用户(SYNC = 2)为内部用户,需要使用E办登录 + if (userSource != null && userSource.equals(UserSourceEnum.SYNC.getSource())) { + return true; + } + + // 外部用户(EXTERNAL = 1)或其他情况为外部用户,使用账号密码登录 + return false; + } + + /** + * 根据部门ID获取部门名称 + */ + private String getDeptName(Long deptId) { + // 这里需要调用部门服务获取部门信息 + // 暂时返回null,实际项目中需要实现 + return null; + } + + /** + * 构建E办登录URL + */ + private String buildEbanLoginUrl() { + String state = "login_" + System.currentTimeMillis(); + + return String.format("%s?client_id=%s&redirect_uri=%s&response_type=%s&state=%s", + ebanAuthorizeUrl, ebanClientId, ebanRedirectUri, ebanResponseType, state); + } + + @Override + public String getEbanLoginUrl() { + return buildEbanLoginUrl(); + } } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanOAuth2Service.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanOAuth2Service.java new file mode 100644 index 00000000..59e99350 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanOAuth2Service.java @@ -0,0 +1,71 @@ +package com.zt.plat.module.system.service.oauth2; + +import com.zt.plat.module.system.controller.admin.auth.vo.AuthOAuth2CallbackReqVO; +import com.zt.plat.module.system.controller.admin.auth.vo.AuthLoginRespVO; + +/** + * E办OAuth2服务接口 + * + * @author ZT + */ +public interface EbanOAuth2Service { + + /** + * 处理E办OAuth2回调 + * + * @param reqVO OAuth2回调请求 + * @return 登录结果 + */ + AuthLoginRespVO handleCallback(AuthOAuth2CallbackReqVO reqVO); + + /** + * 通过授权码获取用户信息 + * + * @param code 授权码 + * @param state 状态参数 + * @return 用户信息 + */ + EbanUserInfo getUserInfo(String code, String state); + + /** + * E办用户信息 + */ + class EbanUserInfo { + private String username; + private String realName; + private String email; + private String mobile; + private String deptName; + private EbanOAuth2ServiceImpl.EbanTokenInfo tokenInfo; // 添加Token信息 + + // 构造函数 + public EbanUserInfo() {} + + public EbanUserInfo(String username, String realName, String email, String mobile, String deptName) { + this.username = username; + this.realName = realName; + this.email = email; + this.mobile = mobile; + this.deptName = deptName; + } + + // getter和setter方法 + public String getUsername() { return username; } + public void setUsername(String username) { this.username = username; } + + public String getRealName() { return realName; } + public void setRealName(String realName) { this.realName = realName; } + + public String getEmail() { return email; } + public void setEmail(String email) { this.email = email; } + + public String getMobile() { return mobile; } + public void setMobile(String mobile) { this.mobile = mobile; } + + public String getDeptName() { return deptName; } + public void setDeptName(String deptName) { this.deptName = deptName; } + + public EbanOAuth2ServiceImpl.EbanTokenInfo getTokenInfo() { return tokenInfo; } + public void setTokenInfo(EbanOAuth2ServiceImpl.EbanTokenInfo tokenInfo) { this.tokenInfo = tokenInfo; } + } +} \ No newline at end of file diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanOAuth2ServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanOAuth2ServiceImpl.java new file mode 100644 index 00000000..5adb6768 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanOAuth2ServiceImpl.java @@ -0,0 +1,341 @@ +package com.zt.plat.module.system.service.oauth2; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.zt.plat.framework.common.enums.CommonStatusEnum; +import com.zt.plat.module.system.controller.admin.auth.vo.AuthOAuth2CallbackReqVO; +import com.zt.plat.module.system.controller.admin.auth.vo.AuthLoginRespVO; +import com.zt.plat.module.system.convert.auth.AuthConvert; +import com.zt.plat.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.zt.plat.module.system.dal.dataobject.user.AdminUserDO; +import com.zt.plat.module.system.enums.logger.LoginLogTypeEnum; +import com.zt.plat.module.system.enums.logger.LoginResultEnum; +import com.zt.plat.module.system.enums.oauth2.OAuth2ClientConstants; +import com.zt.plat.module.system.service.logger.LoginLogService; +import com.zt.plat.module.system.service.user.AdminUserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.zt.plat.framework.common.util.servlet.ServletUtils.getClientIP; +import static com.zt.plat.module.system.enums.ErrorCodeConstants.*; + +/** + * E办OAuth2服务实现类 + * + * @author ZT + */ +@Service +@Slf4j +public class EbanOAuth2ServiceImpl implements EbanOAuth2Service { + + @Resource + private AdminUserService userService; + + @Resource + private LoginLogService loginLogService; + + @Resource + private OAuth2TokenService oauth2TokenService; + + @Resource + private EbanTokenService ebanTokenService; + + @Value("${eban.oauth2.auth-server.base-url:http://10.2.137.42/idp/oauth2}") + private String authServerBaseUrl; + + @Value("${eban.oauth2.auth-server.client-id:tyszhjyglxt}") + private String clientId; + + @Value("${eban.oauth2.auth-server.client-secret:}") + private String clientSecret; + + @Value("${eban.oauth2.user-info.url:http://10.2.137.42/idp/oauth2/getUserInfo}") + private String userInfoUrl; + + @Value("${eban.oauth2.token.url:http://10.2.137.42/idp/oauth2/getToken}") + private String tokenUrl; + + @Override + public AuthLoginRespVO handleCallback(AuthOAuth2CallbackReqVO reqVO) { + log.info("处理E办OAuth2回调: code={}, state={}", reqVO.getCode(), reqVO.getState()); + + try { + // 1. 通过授权码获取用户信息 + EbanUserInfo userInfo = getUserInfo(reqVO.getCode(), reqVO.getState()); + if (userInfo == null || StrUtil.isBlank(userInfo.getUsername())) { + throw exception(AUTH_LOGIN_BAD_CREDENTIALS); + } + + // 2. 根据用户名查找系统用户 + AdminUserDO user = userService.getUserByUsername(userInfo.getUsername()); + if (user == null) { + // 用户不存在,记录登录失败日志 + createLoginLog(null, userInfo.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL, LoginResultEnum.BAD_CREDENTIALS); + throw exception(USER_NOT_EXISTS); + } + + // 3. 校验用户状态 + if (CommonStatusEnum.isDisable(user.getStatus())) { + createLoginLog(user.getId(), userInfo.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL, LoginResultEnum.USER_DISABLED); + throw exception(AUTH_LOGIN_USER_DISABLED); + } + + // 4. 保存E办token到现有OAuth2表中 + try { + EbanTokenInfo tokenInfo = userInfo.getTokenInfo(); + if (tokenInfo != null) { + // 将用户信息转换为JSON字符串 + JSONObject ebanUserInfoJson = new JSONObject(); + ebanUserInfoJson.put("username", userInfo.getUsername()); + ebanUserInfoJson.put("realName", userInfo.getRealName()); + ebanUserInfoJson.put("email", userInfo.getEmail()); + ebanUserInfoJson.put("mobile", userInfo.getMobile()); + ebanUserInfoJson.put("deptName", userInfo.getDeptName()); + + ebanTokenService.createEbanToken( + user.getId(), // 使用用户ID + tokenInfo.getAccessToken(), + tokenInfo.getRefreshToken(), + tokenInfo.getExpiresIn(), + tokenInfo.getUid(), + ebanUserInfoJson.toString() + ); + log.info("成功保存E办token到OAuth2表,用户ID: {}, 用户名: {}, uid: {}", + user.getId(), userInfo.getUsername(), tokenInfo.getUid()); + } + } catch (Exception e) { + log.error("保存E办token失败,用户: " + userInfo.getUsername(), e); + // 保存token失败不影响登录流程,继续执行 + } + + // 5. 创建Token令牌,记录登录日志 + return createTokenAfterLoginSuccess(user.getId(), userInfo.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL); + + } catch (Exception e) { + log.error("E办OAuth2回调处理失败", e); + if (e.getMessage().contains("USER_NOT_EXISTS") || e.getMessage().contains("AUTH_LOGIN_USER_DISABLED")) { + throw e; // 重新抛出业务异常 + } + throw exception(AUTH_LOGIN_BAD_CREDENTIALS); + } + } + + @Override + public EbanUserInfo getUserInfo(String code, String state) { + try { + // 1. 使用授权码换取access_token + EbanTokenInfo tokenInfo = exchangeAccessToken(code, state); + if (tokenInfo == null || StrUtil.isBlank(tokenInfo.getAccessToken())) { + log.error("获取access_token失败"); + return null; + } + + // 2. 使用access_token获取用户信息 + EbanUserInfo userInfo = fetchUserInfo(tokenInfo.getAccessToken()); + if (userInfo != null) { + // 将Token信息保存到用户信息中,以便后续使用 + userInfo.setTokenInfo(tokenInfo); + } + + return userInfo; + + } catch (Exception e) { + log.error("获取E办用户信息失败", e); + return null; + } + } + + /** + * E办Token信息 + */ + public static class EbanTokenInfo { + private String accessToken; + private String refreshToken; + private Integer expiresIn; + private String uid; + private String createDate; + + // 构造函数和getter/setter方法 + public EbanTokenInfo() {} + + public EbanTokenInfo(String accessToken, String refreshToken, Integer expiresIn, String uid, String createDate) { + this.accessToken = accessToken; + this.refreshToken = refreshToken; + this.expiresIn = expiresIn; + this.uid = uid; + this.createDate = createDate; + } + + public String getAccessToken() { return accessToken; } + public void setAccessToken(String accessToken) { this.accessToken = accessToken; } + + public String getRefreshToken() { return refreshToken; } + public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } + + public Integer getExpiresIn() { return expiresIn; } + public void setExpiresIn(Integer expiresIn) { this.expiresIn = expiresIn; } + + public String getUid() { return uid; } + public void setUid(String uid) { this.uid = uid; } + + public String getCreateDate() { return createDate; } + public void setCreateDate(String createDate) { this.createDate = createDate; } + } + + /** + * 使用授权码换取access_token + */ + private EbanTokenInfo exchangeAccessToken(String code, String state) { + try { + // 根据e办API规范构建请求参数 + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("client_secret", clientSecret); + params.put("code", code); + params.put("grant_type", "authorization_code"); + + log.info("请求e办获取token,参数: client_id={}, code={}", clientId, code); + + HttpResponse response = HttpRequest.post(tokenUrl) + .form(params) + .timeout(10000) + .execute(); + + if (!response.isOk()) { + log.error("获取access_token失败,HTTP状态码: {}, 响应: {}", response.getStatus(), response.body()); + return null; + } + + JSONObject jsonResponse = JSONUtil.parseObj(response.body()); + + // 检查是否有错误码 + if (jsonResponse.containsKey("errcode")) { + log.error("获取access_token失败,错误码: {}, 错误信息: {}", + jsonResponse.getStr("errcode"), jsonResponse.getStr("msg")); + return null; + } + + String accessToken = jsonResponse.getStr("access_token"); + String refreshToken = jsonResponse.getStr("refresh_token"); + Integer expiresIn = jsonResponse.getInt("expires_in"); + String uid = jsonResponse.getStr("uid"); + String createDate = jsonResponse.getStr("createDate"); + + log.info("成功获取access_token,uid: {}, expires_in: {}", uid, expiresIn); + + return new EbanTokenInfo(accessToken, refreshToken, expiresIn, uid, createDate); + + } catch (Exception e) { + log.error("调用e办token接口异常", e); + return null; + } + } + + /** + * 使用access_token获取用户信息 + */ + private EbanUserInfo fetchUserInfo(String accessToken) { + try { + // 根据e办API规范构建请求参数 + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("access_token", accessToken); + + log.info("请求e办获取用户信息,client_id: {}", clientId); + + HttpResponse response = HttpRequest.get(userInfoUrl) + .form(params) + .timeout(10000) + .execute(); + + if (!response.isOk()) { + log.error("获取用户信息失败,HTTP状态码: {}, 响应: {}", response.getStatus(), response.body()); + return null; + } + + JSONObject userJson = JSONUtil.parseObj(response.body()); + + // 检查是否有错误码 + if (userJson.containsKey("errcode")) { + log.error("获取用户信息失败,错误码: {}, 错误信息: {}", + userJson.getStr("errcode"), userJson.getStr("msg")); + return null; + } + + // 解析用户信息(根据e办系统的实际返回格式调整) + EbanUserInfo userInfo = new EbanUserInfo(); + + // 根据API文档,主要字段是loginName和spRoleList + String loginName = userJson.getStr("loginName"); + if (StrUtil.isBlank(loginName)) { + log.error("用户信息中缺少loginName字段"); + return null; + } + + userInfo.setUsername(loginName); // 使用loginName作为用户名 + + // 如果有spRoleList,可以取第一个作为真实姓名或其他用途 + if (userJson.containsKey("spRoleList")) { + Object spRoleListObj = userJson.get("spRoleList"); + if (spRoleListObj instanceof java.util.List) { + @SuppressWarnings("unchecked") + java.util.List spRoleList = (java.util.List) spRoleListObj; + if (!spRoleList.isEmpty()) { + userInfo.setRealName(spRoleList.get(0)); + } + } + } + + // 其他可能的字段(根据实际e办返回的字段调整) + userInfo.setEmail(userJson.getStr("email")); + userInfo.setMobile(userJson.getStr("mobile")); + userInfo.setDeptName(userJson.getStr("deptName")); + + log.info("成功获取用户信息: username={}, realName={}", userInfo.getUsername(), userInfo.getRealName()); + + return userInfo; + + } catch (Exception e) { + log.error("调用e办用户信息接口异常", e); + return null; + } + } + + /** + * 创建登录日志 + */ + private void createLoginLog(Long userId, String username, LoginLogTypeEnum logType, LoginResultEnum loginResult) { + // 这里可以复用AdminAuthServiceImpl中的createLoginLog逻辑 + // 为了简化,这里省略实现 + log.info("创建登录日志: userId={}, username={}, logType={}, result={}", + userId, username, logType, loginResult); + } + + /** + * 登录成功后创建Token + */ + private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) { + // 插入登陆日志 + createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS); + + // 创建访问令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken( + userId, + com.zt.plat.framework.common.enums.UserTypeEnum.ADMIN.getValue(), + OAuth2ClientConstants.CLIENT_ID_DEFAULT, + null + ); + + // 构建返回结果 + return AuthConvert.INSTANCE.convert(accessTokenDO); + } +} \ No newline at end of file diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanTokenService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanTokenService.java new file mode 100644 index 00000000..9e1c77a8 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanTokenService.java @@ -0,0 +1,65 @@ +package com.zt.plat.module.system.service.oauth2; + +import com.zt.plat.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.zt.plat.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO; + +/** + * E办Token管理服务接口(基于现有OAuth2 Token体系) + * + * @author ZT + */ +public interface EbanTokenService { + + /** + * 创建E办Token信息到现有OAuth2表中 + * + * @param userId 系统用户ID + * @param accessToken E办访问令牌 + * @param refreshToken E办刷新令牌 + * @param expiresIn 过期时间(秒) + * @param uid E办用户唯一标识 + * @param userInfo E办用户信息(JSON格式) + * @return OAuth2AccessTokenDO + */ + OAuth2AccessTokenDO createEbanToken(Long userId, String accessToken, String refreshToken, + Integer expiresIn, String uid, String userInfo); + + /** + * 根据用户ID获取E办Token + * + * @param userId 系统用户ID + * @return OAuth2AccessTokenDO + */ + OAuth2AccessTokenDO getEbanTokenByUserId(Long userId); + + /** + * 刷新E办Token + * + * @param userId 系统用户ID + * @return 是否刷新成功 + */ + boolean refreshEbanToken(Long userId); + + /** + * 删除E办Token + * + * @param userId 系统用户ID + */ + void deleteEbanToken(Long userId); + + /** + * 检查E办Token是否有效 + * + * @param userId 系统用户ID + * @return 是否有效 + */ + boolean isEbanTokenValid(Long userId); + + /** + * 根据access_token获取E办Token信息 + * + * @param accessToken 访问令牌 + * @return OAuth2AccessTokenDO + */ + OAuth2AccessTokenDO getEbanTokenByAccessToken(String accessToken); +} \ No newline at end of file diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanTokenServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanTokenServiceImpl.java new file mode 100644 index 00000000..a77dbc03 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/EbanTokenServiceImpl.java @@ -0,0 +1,97 @@ +package com.zt.plat.module.system.service.oauth2; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.zt.plat.framework.common.enums.UserTypeEnum; +import com.zt.plat.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.zt.plat.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * E办Token管理服务实现类(基于现有OAuth2 Token体系) + * + * @author ZT + */ +@Service +@Slf4j +public class EbanTokenServiceImpl implements EbanTokenService { + + @Resource + private OAuth2TokenService oauth2TokenService; + + @Value("${eban.oauth2.auth-server.client-id:tyszhjyglxt}") + private String clientId; + + @Value("${eban.oauth2.auth-server.client-secret:}") + private String clientSecret; + + @Value("${eban.oauth2.token.refresh-url:http://10.2.137.42/idp/oauth2/refreshToken}") + private String refreshTokenUrl; + + @Value("${eban.oauth2.token.check-url:http://10.2.137.42/idp/oauth2/checkTokenValid}") + private String checkTokenUrl; + + private static final String EBAN_CLIENT_ID = "eban-oauth2-client"; + private static final String EBAN_SCOPES = "user:read"; + + @Override + public OAuth2AccessTokenDO createEbanToken(Long userId, String accessToken, String refreshToken, + Integer expiresIn, String uid, String userInfo) { + try { + // 使用现有的OAuth2TokenService创建token + // 由于原方法签名不匹配,我们先简单实现 + OAuth2AccessTokenDO token = oauth2TokenService.createAccessToken( + userId, + UserTypeEnum.ADMIN.getValue(), + EBAN_CLIENT_ID, + java.util.Arrays.asList(EBAN_SCOPES) + ); + + log.info("成功创建E办Token: userId={}, uid={}", userId, uid); + return token; + + } catch (Exception e) { + log.error("创建E办Token失败: userId=" + userId + ", uid=" + uid, e); + throw new RuntimeException("创建E办Token失败", e); + } + } + + @Override + public OAuth2AccessTokenDO getEbanTokenByUserId(Long userId) { + // 暂时返回null,需要根据实际的OAuth2TokenService方法实现 + return null; + } + + @Override + public OAuth2AccessTokenDO getEbanTokenByAccessToken(String accessToken) { + return oauth2TokenService.getAccessToken(accessToken); + } + + @Override + public boolean refreshEbanToken(Long userId) { + // 暂时简单实现 + return false; + } + + @Override + public void deleteEbanToken(Long userId) { + // 暂时简单实现 + log.info("删除E办Token: userId={}", userId); + } + + @Override + public boolean isEbanTokenValid(Long userId) { + // 暂时简单实现 + return false; + } +} \ No newline at end of file diff --git a/zt-module-system/zt-module-system-server/src/main/resources/application.yaml b/zt-module-system/zt-module-system-server/src/main/resources/application.yaml index 30c43aa0..8f994a92 100644 --- a/zt-module-system/zt-module-system-server/src/main/resources/application.yaml +++ b/zt-module-system/zt-module-system-server/src/main/resources/application.yaml @@ -203,6 +203,25 @@ zt: begin-code: 9999 # 这里配置 9999 的原因是,测试方便。 end-code: 9999 # 这里配置 9999 的原因是,测试方便。 + +# E办OAuth2配置文件 +eban: + oauth2: + # E办OAuth2服务端配置 + auth-server: + base-url: http://10.2.137.42/idp/oauth2 + client-id: tyszhjyglxt + client-secret: your_client_secret_here # 需要从e办系统获取 + callback-uri: http://172.16.46.63:30080/system/oauth2/callback + + # 用户信息获取配置 + user-info: + url: http://10.2.137.42/idp/oauth2/getUserInfo + + # 令牌交换配置 + token: + url: http://10.2.137.42/idp/oauth2/getToken + debug: false sync: diff --git a/zt-module-template/zt-module-template-server/src/main/java/com/zt/plat/module/template/controller/admin/contract/DemoContractController.java b/zt-module-template/zt-module-template-server/src/main/java/com/zt/plat/module/template/controller/admin/contract/DemoContractController.java index 66be3f09..3ed03993 100644 --- a/zt-module-template/zt-module-template-server/src/main/java/com/zt/plat/module/template/controller/admin/contract/DemoContractController.java +++ b/zt-module-template/zt-module-template-server/src/main/java/com/zt/plat/module/template/controller/admin/contract/DemoContractController.java @@ -11,11 +11,12 @@ import com.zt.plat.framework.common.pojo.PageResult; import com.zt.plat.framework.common.pojo.vo.BatchDeleteReqVO; import com.zt.plat.framework.common.util.object.BeanUtils; import com.zt.plat.framework.excel.core.util.ExcelUtils; +import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils; import com.zt.plat.module.bpm.api.task.BpmProcessInstanceApi; import com.zt.plat.module.bpm.api.task.BpmTaskApi; +import com.zt.plat.module.bpm.api.task.dto.BpmApprovalDetailReqDTO; import com.zt.plat.module.infra.api.businessfile.BusinessFileApi; import com.zt.plat.module.infra.api.file.FileApi; -import com.zt.plat.module.infra.api.file.dto.FileCreateReqDTO; import com.zt.plat.module.infra.api.file.dto.FileRespDTO; import com.zt.plat.module.system.api.dept.DeptApi; import com.zt.plat.module.template.controller.admin.contract.vo.DemoContractPageReqVO; @@ -116,12 +117,10 @@ public class DemoContractController extends AbstractFileUploadController impleme public CommonResult> getDemoContractPage(@Valid DemoContractPageReqVO pageReqVO) { CommonResult file = fileApi.getFile(1968928810422521857L); - FileCreateReqDTO createReqDTO = new FileCreateReqDTO(); - createReqDTO.setContent(file.getCheckedData().getContent()); - createReqDTO.setType(file.getCheckedData().getType()); - createReqDTO.setName(file.getCheckedData().getName()); - createReqDTO.setDirectory(file.getCheckedData().getDirectory()); - CommonResult fileWithReturn = fileApi.createFileWithReturn(createReqDTO); + BpmApprovalDetailReqDTO reqDTO = new BpmApprovalDetailReqDTO(); + reqDTO.setProcessInstanceId("acccfcf2-99b9-11f0-8536-e8808862e505"); + reqDTO.setTaskId("8ba1838e-99ba-11f0-8536-e8808862e505"); + bpmInsApi.getApprovalDetail(SecurityFrameworkUtils.getLoginUserId(), reqDTO); Long id = IdWorker.getId(); System.out.println("Generated ID: " + id); PageResult pageResult = demoContractService.getDemoContractPage(pageReqVO); diff --git a/zt-server/src/main/resources/application.yaml b/zt-server/src/main/resources/application.yaml index 6bfeee85..e83a106a 100644 --- a/zt-server/src/main/resources/application.yaml +++ b/zt-server/src/main/resources/application.yaml @@ -346,6 +346,22 @@ zt: key: pLXUGAwK5305 customer: E77DF18BE109F454A5CD319E44BF5177 +# E办OAuth2配置文件 +eban: + oauth2: + # E办OAuth2登录配置 + authorize-url: http://10.2.137.42/idp/oauth2/authorize + client-id: tyszhjyglxt + client-secret: your_client_secret_here # 需要从e办系统获取 + redirect-uri: http://172.16.46.63:30080/system/oauth2/callback + response-type: code + + # 用户信息获取URL + user-info-url: http://10.2.137.42/idp/oauth2/getUserInfo + + # 令牌交换URL + token-url: http://10.2.137.42/idp/oauth2/getToken + debug: false # OnlyOffice 配置 @@ -356,4 +372,5 @@ onlyoffice: # 插件配置 TODO 芋艿:【IOT】需要处理下 pf4j: - pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录 \ No newline at end of file + pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录 +