Compare commits
210 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 525c73b478 | |||
| 66d348e67e | |||
| 4d22bba723 | |||
| ecdd054c12 | |||
| a45dd82be6 | |||
| f5415dd354 | |||
| 191b137add | |||
| 94b9a0848c | |||
| 34d4cdea1e | |||
| a7dc35862a | |||
| 05e7ad4563 | |||
| f9ab24fcea | |||
|
|
4ef1046798 | ||
|
|
b85c2ac097 | ||
|
|
bdb8add5b1 | ||
|
|
3b1c1b3ba8 | ||
|
|
9dce16923c | ||
|
|
694b2a3660 | ||
|
|
1e4d9dcca5 | ||
|
|
2b62c09a2f | ||
|
|
6bf313d78a | ||
|
|
2f59638b7c | ||
|
|
bd4b2c9a2b | ||
|
|
e322a62002 | ||
|
|
a6837d6b6f | ||
|
|
8b7a79b8d0 | ||
|
|
a1e3867171 | ||
|
|
5b769faf6e | ||
|
|
e7357ed208 | ||
|
|
b94ca42ca0 | ||
|
|
ea37189820 | ||
|
|
88b9e8e148 | ||
| 5e0204cd73 | |||
|
|
5a9ac44892 | ||
| cef429d4ab | |||
|
|
93b9236b19 | ||
| 7d53d2ad71 | |||
|
|
45b68217f3 | ||
|
|
16bcecb62b | ||
| 68f7da71d2 | |||
| fa1acf573d | |||
| 168a8e7d4e | |||
| 98f560dc77 | |||
| dc44245550 | |||
| e6cb590f6a | |||
| f7451d083f | |||
| 493910d2a3 | |||
| 4afdcf1f1f | |||
| 7d85b3ebdd | |||
| 0905bb396d | |||
| 43be1fc801 | |||
| 4cbc6eb390 | |||
| f755316a47 | |||
| cf3618ae67 | |||
| de05615d81 | |||
| e264b5b59b | |||
| 2bd392b424 | |||
| 279d066b3b | |||
| e048ae86cd | |||
| 90ec6ec83e | |||
| dffb17fae6 | |||
| 6b83bc655b | |||
| 783d441a8d | |||
| 5172810fa5 | |||
| 74a12dcd28 | |||
|
|
d189c3f675 | ||
|
|
e99de0c2a2 | ||
| e9b65279c1 | |||
| 8c7e609328 | |||
| e882f8dc4e | |||
| 34b665fe3c | |||
| 753e68a55d | |||
| edd4c57a7a | |||
| 7eaefd0958 | |||
|
|
e0871671c6 | ||
| f59b795e22 | |||
| c9fd0ad4d5 | |||
| 57111fcab4 | |||
| c3f8898ae0 | |||
| 283a492930 | |||
| 6fa1b0df00 | |||
| 357d7e0a03 | |||
| 4d68482016 | |||
| 12d6b5c466 | |||
| 0fe847a211 | |||
| a5d577d36c | |||
| 8e628d9769 | |||
| 141151acc3 | |||
| 7809349857 | |||
| 43a686f07d | |||
| 013fb302c0 | |||
| e2d73eead8 | |||
| 75842bcb96 | |||
| b8c0405795 | |||
| ff03caea22 | |||
| 0c53b57a9c | |||
| 333de1e1af | |||
| c9acc9cad8 | |||
| 4694ed6280 | |||
| f1d93a4d0f | |||
| e6d260a05b | |||
| 37d6c117fb | |||
| 530a8f6206 | |||
| bab94f4807 | |||
| 4833b4b85e | |||
| ce0630f831 | |||
| 464e94f368 | |||
| d2e82a4f6b | |||
| 9b1f366e05 | |||
| 6b39b5e413 | |||
| 42999bedae | |||
| 43702038f5 | |||
| b20861ee56 | |||
| 9f05c76d32 | |||
| 25ef7e9f58 | |||
| 4f7f75bde2 | |||
| ac18aa7bd9 | |||
| 8cfb698553 | |||
| b52408571d | |||
| d45aeec5bb | |||
| 4085563ceb | |||
| cd3ee2f46a | |||
| 97b5f9d1d2 | |||
| edf617cb6b | |||
| 5c3a483a41 | |||
| 6a23d85806 | |||
| 3e57c49e2c | |||
| c6380658d1 | |||
| 6cd2bf9da8 | |||
| f4f97fdbf3 | |||
| 127a692b7a | |||
| 91e81a9a78 | |||
| 62aec2b9ee | |||
| 9b2d95cdde | |||
| 2d25ff475d | |||
| 956c7d1314 | |||
| 86f9d925c8 | |||
| 8722e5baea | |||
| ccf56781fc | |||
| 3a755e0d90 | |||
| 9d7507ef9f | |||
| b72909449b | |||
| 3988c3bb60 | |||
| 9841f9aa98 | |||
| 98ec67641f | |||
| 1800d98711 | |||
| 8af2839cef | |||
| 48cbd02164 | |||
| e2802ec78e | |||
| 496eef6b5c | |||
| 33897ac687 | |||
| a662e6fab7 | |||
| 0e0eb5a0a6 | |||
| c26659c364 | |||
| 744b8f19ac | |||
| 91d263bc10 | |||
| 50c423d7d2 | |||
| 388de9eb52 | |||
| cdbe89c05a | |||
| 936833b73e | |||
| 1f54f82c34 | |||
| 4c9d91e154 | |||
| 5c47507f83 | |||
| 58ad7dfe8b | |||
| 95bd47f4a5 | |||
| bb57f7eb92 | |||
| 5ef2d94adc | |||
| 06301087d5 | |||
|
|
8d97f6ffc3 | ||
| 50ae5ed25b | |||
| a0244b7dca | |||
| d69b467faf | |||
| c7bff3bf34 | |||
| 5298b5f320 | |||
| ba95e4850f | |||
| 0161cddf03 | |||
| c6c62f2f85 | |||
| 1070085454 | |||
| 3b771aa153 | |||
| edaeb9101c | |||
| a37fc25db5 | |||
| a422f44c69 | |||
| 7479f983f2 | |||
| ad1efc673a | |||
| 7ac49ca863 | |||
| 1e4d9e2ea9 | |||
| 4d1193d333 | |||
| 565e6d320d | |||
| c8238ba1ba | |||
|
|
38e44b94f4 | ||
| 5187af00cd | |||
| 7ea678832f | |||
| 0a1be99b3e | |||
| f461d17d2c | |||
| 678e19c3a6 | |||
| 10f7c59425 | |||
| fb790b724f | |||
| 07e45bd76a | |||
| 23b9ccd7c3 | |||
| c24ff9bc03 | |||
| f13dd940da | |||
| 03148df3d3 | |||
| c1c801f813 | |||
| 432a69f4b2 | |||
| 7291b2736e | |||
|
|
fc1d953d29 | ||
|
|
5fc23db9ea | ||
| ed6cea9ef1 | |||
| 8a8eb29af4 | |||
| 8c7a5e478f |
@ -17,11 +17,13 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCre
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceVariablesUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverReadStatusDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ProcessDocQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskButtonSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo;
|
||||
import cn.axzo.workflow.common.model.request.form.instance.FormVariablesUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO;
|
||||
@ -180,6 +182,17 @@ public interface ProcessInstanceApi {
|
||||
CommonResponse<Map<String, Object>> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
|
||||
@Nullable @RequestParam(required = false) String tenantId);
|
||||
|
||||
/**
|
||||
* 更新流程实例中的业务自定义变量集合
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "更新流程实例中的业务自定义变量集合")
|
||||
@PostMapping("/api/process/instance/biz/custom/variables/update")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> updateProcessBizCustomVariables(@Validated @RequestBody BpmnProcessInstanceVariablesUpdateDTO dto);
|
||||
|
||||
/**
|
||||
* 查询所有的审批流
|
||||
*
|
||||
@ -358,4 +371,15 @@ public interface ProcessInstanceApi {
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<List<ExtProcessLogVO>> getProcessLogByInstanceIdAndPersonId(@Validated @RequestBody LogApproveSearchDTO dto);
|
||||
|
||||
/**
|
||||
* 获取流程实例的条件字段信息,仅用于同意抽屉展示
|
||||
*
|
||||
* @param processInstanceId
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "获取流程实例的条件字段信息, 仅用于同意抽屉展示")
|
||||
@GetMapping("/api/process/instance/conditions")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<List<ConditionPermissionMetaInfo>> getConditions(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId);
|
||||
}
|
||||
|
||||
@ -46,7 +46,6 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
|
||||
*/
|
||||
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
|
||||
@WorkflowEngineFeignClient
|
||||
@Manageable
|
||||
public interface ProcessModelApi {
|
||||
|
||||
/**
|
||||
@ -57,6 +56,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "流程模型列表")
|
||||
@GetMapping("/api/process/model/page")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<BpmPageResult<BpmnModelDetailVO>> page(@Validated @RequestBody BpmnModelSearchDTO dto);
|
||||
|
||||
@ -66,6 +66,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "创建流程模型")
|
||||
@PostMapping("/api/process/model/create")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<String> create(@Validated @RequestBody BpmnModelCreateDTO dto);
|
||||
|
||||
@ -74,6 +75,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "通过模型ID查询指定流程模型")
|
||||
@GetMapping("/api/process/model/get")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<BpmnModelDetailVO> getById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId,
|
||||
@RequestParam(required = false) String tenantId);
|
||||
@ -83,6 +85,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "通过模型KEY查询指定流程模型")
|
||||
@GetMapping("/api/process/model/getByKey")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<BpmnModelDetailVO> getByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey,
|
||||
@NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId);
|
||||
@ -96,6 +99,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "获取指定模型的扩展属性")
|
||||
@GetMapping("/api/process/model/ext")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<BpmnModelExtVO> getModelExt(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId);
|
||||
|
||||
@ -104,6 +108,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "更新流程模型")
|
||||
@PutMapping("/api/process/model/update")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<String> update(@RequestBody BpmnModelUpdateDTO dto);
|
||||
|
||||
@ -115,6 +120,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "通过模型 ID 部署流程模型")
|
||||
@PostMapping("/api/process/model/deploy")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<String> deployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId,
|
||||
@RequestParam(required = false, defaultValue = "") String modelTenantId,
|
||||
@ -127,6 +133,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "通过模型 KEY 部署流程模型")
|
||||
@PostMapping("/api/process/model/deployByKey")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<String> deployByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey,
|
||||
@NotBlank(message = "租户不能为空") @RequestParam(required = false) String modelTenantId,
|
||||
@ -142,6 +149,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "通过模型 ID 取消部署流程模型")
|
||||
@PostMapping("/api/process/model/undeploy")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Void> unDeployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId,
|
||||
@RequestParam(required = false, defaultValue = "") String tenantId,
|
||||
@ -152,6 +160,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "删除指定模型 ID 的流程模型")
|
||||
@DeleteMapping("/api/process/model/delete")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Void> deleteById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam String processModelId,
|
||||
@RequestParam(required = false, defaultValue = "") String tenantId);
|
||||
@ -165,6 +174,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "删除指定模型 KEY 的流程模型")
|
||||
@DeleteMapping("/api/process/model/deleteByKey")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Void> deleteByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam String processModelKey,
|
||||
@RequestParam(required = false, defaultValue = "") String tenantId);
|
||||
@ -179,6 +189,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "修改模型状态")
|
||||
@PostMapping("/api/process/model/changeStatus")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> changeStatus(@NotBlank(message = "模型 ID 不能为空") @RequestParam String modelId,
|
||||
@NotNull(message = "状态不能为空") @RequestParam Integer status,
|
||||
@ -194,6 +205,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "修改模型打印开关状态")
|
||||
@PostMapping("/api/process/model/print/changeStatus")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> changePrintStatus(@NotBlank(message = "模型 ID 不能为空") @RequestParam String modelId,
|
||||
@NotNull(message = "状态不能为空") @RequestParam Integer status,
|
||||
@ -206,6 +218,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "查询流程模型使用的分类列表")
|
||||
@GetMapping("/api/process/model/category/ids")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<List<String>> getModelCategoryList();
|
||||
|
||||
@ -216,6 +229,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "查询模型的租户集合")
|
||||
@GetMapping("/api/process/model/tenant/ids")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<List<String>> getModelTenantIds();
|
||||
|
||||
@ -227,6 +241,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "获取打印模板配置内容")
|
||||
@PostMapping("/api/process/model/print/template/config/query")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<PrintModelDTO> getPrintTemplateConfig(@Validated @RequestBody PrintTemplateConfigQueryDTO dto);
|
||||
|
||||
@ -238,6 +253,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "代运营重置打印模板")
|
||||
@PostMapping(value = "/api/process/model/print/template/config/reset")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> resetPrintTemplateConfig(@Validated @RequestBody RestPrintTemplateConfigDTO dto);
|
||||
|
||||
@ -249,6 +265,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "搜索文档列表")
|
||||
@PostMapping(value = "/api/process/model/doc/page")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<BpmPageResult<DocBaseVO>> docPage(@Validated @RequestBody DocSearchDTO dto);
|
||||
|
||||
@ -259,6 +276,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "获取指定 docIds 文档列表")
|
||||
@PostMapping(value = "/api/process/model/doc/ids")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<List<DocBaseVO>> docByIds(@Validated @RequestBody DocByIdDTO dto);
|
||||
|
||||
@ -281,6 +299,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "获取关联 HiPrint 类型文档模板内容")
|
||||
@PostMapping(value = "/api/process/model/hi-print/content/get")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<String> getHiPrintContent(@RequestParam String fileRelationId);
|
||||
|
||||
@ -291,6 +310,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "添加关联文档")
|
||||
@PutMapping(value = "/api/process/model/doc/create")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> createDoc(@Validated @RequestBody DocCreateDTO dto);
|
||||
|
||||
@ -301,6 +321,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "修改关联文档")
|
||||
@PostMapping(value = "/api/process/model/doc/update")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> updateDoc(@Validated @RequestBody DocUpdateDTO dto);
|
||||
|
||||
@ -312,6 +333,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "克隆关联文档")
|
||||
@PostMapping(value = "/api/process/model/doc/clone")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> cloneDoc(@RequestParam("id") Long docId);
|
||||
|
||||
@ -322,6 +344,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "删除指定文档")
|
||||
@DeleteMapping(value = "/api/process/model/doc/delete")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> deleteDoc(@RequestParam("id") Long docId);
|
||||
|
||||
@ -333,6 +356,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "关联文档配置排序")
|
||||
@PostMapping(value = "/api/process/model/doc/order")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> orderDoc(@Validated @RequestBody DocOrderDTO dto);
|
||||
|
||||
@ -344,6 +368,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "重置关联文档配置")
|
||||
@PostMapping(value = "/api/process/model/doc/reset")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> resetDoc(@Validated @RequestBody DocResetDTO dto);
|
||||
|
||||
@ -355,6 +380,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "设置关联文档的停启用状态")
|
||||
@PostMapping(value = "/api/process/model/doc/status")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> statusDoc(@Validated @RequestBody DocStatusDTO dto);
|
||||
|
||||
@ -365,6 +391,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "设置关联文档的必选状态")
|
||||
@PostMapping(value = "/api/process/model/doc/require")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> requireDoc(@Validated @RequestBody DocStatusDTO dto);
|
||||
|
||||
@ -375,6 +402,7 @@ public interface ProcessModelApi {
|
||||
*/
|
||||
@Operation(summary = "特殊的查询设置过关联过文档的工作台 ID 集合")
|
||||
@PostMapping(value = "/api/process/model/has/docs/tenantId")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<List<Long>> hasFilesTenantIds(@Validated @RequestBody DocTenantQueryDTO dto);
|
||||
}
|
||||
|
||||
@ -4,8 +4,13 @@ import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient;
|
||||
import cn.axzo.workflow.common.annotation.InvokeMode;
|
||||
import cn.axzo.workflow.common.annotation.Manageable;
|
||||
import cn.axzo.workflow.common.model.dto.print.PrintFieldDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.print.Print4ProcessLogDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.print.PrintFieldQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.print.PrintProcessLogPdfDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.print.PrintTemplateConfigUpsertDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.print.QueryProcessLogPdfDTO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.PrintData4LogVO;
|
||||
import cn.axzo.workflow.common.model.response.print.ProcessLogPdfResultDTO;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -66,7 +71,7 @@ public interface PrintAdminApi {
|
||||
* 获取指定流程下用于替换打印的相关变量
|
||||
*
|
||||
* @param processInstanceId
|
||||
* @return
|
||||
* @return 仅是 kv 集合,
|
||||
*/
|
||||
@Operation(summary = "获取指定流程下用于替换打印的相关变量")
|
||||
@GetMapping("/api/print/admin/field/variables")
|
||||
@ -74,4 +79,40 @@ public interface PrintAdminApi {
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Map<String, Object>> getPrintFieldVariables(@NotBlank(message = "流程实例不能为空") @RequestParam String processInstanceId,
|
||||
@RequestParam(required = false, defaultValue = "true") Boolean throwException);
|
||||
|
||||
/**
|
||||
* 获取用于打印审批日志公共模板的数据
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "获取用于打印审批日志公共模板的数据")
|
||||
@PostMapping("/api/print/admin/process/log/data/v2")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<PrintData4LogVO> getPrintDataForProcessLog(@Validated @RequestBody Print4ProcessLogDTO dto);
|
||||
|
||||
/**
|
||||
* 后端请求指定流程日志 PDF 文件生成, 实现是异步的。
|
||||
* <p>
|
||||
* 请使用 {@link PrintAdminApi#queryProcessLogPdfResult(QueryProcessLogPdfDTO)} 函数查询,
|
||||
* 或者使用 {@link cn.axzo.nanopart.doc.api.conversion.DocConversionApi#queryConvertResultByBiz(cn.axzo.nanopart.doc.api.conversion.req.QueryConversionTaskRequestV2)} 函数查询,该接口入参默认情况下应该为:bizCode:固定为"workflow-process-log", bizKey:为实例 ID+":"+访问人 personId
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "后端请求指定流程日志 PDF 文件生成")
|
||||
@PostMapping("/api/print/admin/process/log/pdf")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<String> createProcessLogPdf(@Validated @RequestBody PrintProcessLogPdfDTO dto);
|
||||
|
||||
/**
|
||||
* 后端查询指定审批日志 PDF 文件的生成结果
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "后端查询指定审批日志 PDF 文件的生成结果")
|
||||
@PostMapping("/api/print/admin/process/log/pdf/result")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<ProcessLogPdfResultDTO> queryProcessLogPdfResult(@Validated @RequestBody QueryProcessLogPdfDTO dto);
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ public enum BpmnTaskRespCode implements IModuleRespCode {
|
||||
REMIND_TASK_TOO_MANY("027", "催办任务数据异常"),
|
||||
PROCESS_SET_ASSIGNEE_PARAM_ERROR("028", "当前审批业务审批人模型中 NodeId 必传(topNodeId/nodeId均可), 触发 ID: 【{}】"),
|
||||
TASK_OPERATION_PARAM_INVALID("029", "流程实例 ID 与任务 ID 必须二选一"),
|
||||
COOPERATION_NOT_EXIST_WITH_NODE("030", "查询审批人时,组织不存在"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
@ -21,6 +21,8 @@ public enum ConvertorRespCode implements IModuleRespCode {
|
||||
CONVERTOR_OPERATION_NUMBER_TYPE_ERROR("006", "条件节点(数字)运算符【{}】暂不支持"),
|
||||
CONVERTOR_OPERATION_RADIO_TYPE_ERROR("007", "条件节点(单选)运算符【{}】暂不支持"),
|
||||
CONVERTOR_OPERATION_CHECKBOX_TYPE_ERROR("008", "条件节点(复选)运算符【{}】暂不支持"),
|
||||
CREATE_BPMN_USER_TASK_ERROR("009", "创建 UserTask 失败, 不支持的节点模式【{}】"),
|
||||
CREATE_BPMN_PRE_SIGN_ERROR("010", "创建前加签节点失败,原因:【{}】"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
@ -23,6 +23,8 @@ public enum FormInstanceRespCode implements IModuleRespCode {
|
||||
FORM_DATA_PARSE_ERROR_BY_IMAGE("008", "表单图片组件的数据解析异常"),
|
||||
FORM_DATA_PARSE_ERROR_BY_CUSTOM_COMPONENT("009", "表单自定义组件的数据解析异常"),
|
||||
FORM_DATA_PARSE_ERROR_BY_AMOUNT("010", "表单金额组件的数据解析异常"),
|
||||
FORM_DATA_PARSE_ERROR_BY_CHECKBOX("011", "表单复选框组件的数据解析异常"),
|
||||
FORM_DATA_PARSE_ERROR_BY_RADIO("012", "表单单选框组件的数据解析异常"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
@ -22,7 +22,8 @@ public enum OtherRespCode implements IModuleRespCode {
|
||||
ASYNC_JOB_EXECUTION_ERROR("007", "获取指定实例 ID【{}】的锁失败"),
|
||||
ILLEGAL_PARAM_ERROR("008", "非法的参数:【{}】"),
|
||||
MESSAGE_IM_EVENT_BUILD_ERROR("009", "不能使用 createEvent 函数创建`IM 消息`的事件, 请调用 createIMEvent 函数"),
|
||||
ASSIGNEE_NODE_ID_NOT_EXISTS("010", "【{}】 nodeId 不存在, 请检查参数是否正确")
|
||||
ASSIGNEE_NODE_ID_NOT_EXISTS("010", "【{}】 nodeId 不存在, 请检查参数是否正确"),
|
||||
CANT_GENERATE_PROCESS_LOG_PDF("011", "流程未处于终态不能用默认参数创建,请自行添加 BizCode和 BizKey"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
@ -42,9 +42,12 @@ public interface BpmnConstants {
|
||||
@Deprecated
|
||||
String OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT = "[_ASSIGNEE_INFO_SNAPSHOT_]";
|
||||
String INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT = "[_ACTIVITY_INFO_SNAPSHOT_]";
|
||||
String INTERNAL_ACTIVITY_FORWARD_COUNTERSIGN = "[_FORWARD_COUNTERSIGN_]";
|
||||
String INTERNAL_ACTIVITY_BACK_COUNTERSIGN = "[_BACK_COUNTERSIGN_]";
|
||||
String BIZ_NODE_ALTER = "[_BIZ_NODE_ALTER_]";
|
||||
String INITIATOR_SPECIFY = "[_INITIATOR_SPECIFY_]";
|
||||
String SIGNATURE_COLLECTION = "[_SIGNATURE_COLLECTION_]";
|
||||
String COUNTERSIGN_COUNT = "[_COUNTERSIGN_COUNT_]";
|
||||
String PROCESS_PREFIX = "Flowable";
|
||||
@Deprecated
|
||||
String OLD_TASK_ASSIGNEE_SKIP_FLAT = "taskSkip";
|
||||
@ -114,6 +117,9 @@ public interface BpmnConstants {
|
||||
String CONFIG_ACTIVITY_SIGNATURE = "signature";
|
||||
String CONFIG_FIELD_META = "field";
|
||||
String CONFIG_FIELD_PERMISSION = "fieldPermission";
|
||||
String CONFIG_CONDITION_PERMISSION = "conditionPermission";
|
||||
String CONFIG_FIELD_OPTIONS = "options";
|
||||
@Deprecated
|
||||
String CONFIG_FIELD_OPTION = "option";
|
||||
String CONFIG_NODE_TYPE = "nodeType";
|
||||
String CONFIG_BUTTON_TYPE_INITIATOR = "initiator";
|
||||
@ -123,6 +129,7 @@ public interface BpmnConstants {
|
||||
String CONFIG_SIGN_TYPE = "signType";
|
||||
String CONFIG_AREA_FILTER_ENABLE = "areaFilterEnable";
|
||||
String CONFIG_SPECIALTY_FILTER_ENABLE = "specialtyFilterEnable";
|
||||
String CONFIG_ONLY_IN_PROJECT_ENABLE = "onlyInProjectEnable";
|
||||
String ELEMENT_ATTRIBUTE_NAME = "name";
|
||||
String ELEMENT_ATTRIBUTE_VALUE = "value";
|
||||
String ELEMENT_ATTRIBUTE_DESC = "desc";
|
||||
@ -155,6 +162,7 @@ public interface BpmnConstants {
|
||||
String NUMBER_OF_INSTANCES = "nrOfInstances";
|
||||
String MULTI_INSTANCE_LOOP_COUNTER = "loopCounter";
|
||||
String TASK_COMPLETE_OPERATION_TYPE = "_TASK_COMPLETE_TYPE";
|
||||
String TASK_LOG_NODE_HAS_BEEN_HIDDEN = "_TASK_LOG_HIDDEN";
|
||||
String TASK_ATTACHMENTS_VAR_NAME = "TASK_ATTACHMENTS";
|
||||
|
||||
/**
|
||||
@ -249,6 +257,18 @@ public interface BpmnConstants {
|
||||
* 签署业务发起流程实例时,重新选择的文档tag 集合
|
||||
*/
|
||||
String SIGN_PROCESS_ENABLE_DOC_IDS = "[_SIGN_PROCESS_ENABLE_DOC_IDS_]";
|
||||
/**
|
||||
* 签署业务自定义业务传入的文档集合
|
||||
*/
|
||||
String SIGN_BIZ_CUSTOM_DOCS = "[_SIGN_BIZ_CUSTOM_DOCS_]";
|
||||
/**
|
||||
* 签署业务自定义文档的顺序位置类型
|
||||
*/
|
||||
String SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE = "[_SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE_]";
|
||||
/**
|
||||
* 签署业务,业务对所有文档顺序排序
|
||||
*/
|
||||
String SIGN_BIZ_BASED_FILE_TAG_ORDER = "[_SIGN_BIZ_BASED_FILE_TAG_ORDER_]";
|
||||
/**
|
||||
* 签署业务,基于业务自定义变量的传入
|
||||
*/
|
||||
@ -262,4 +282,12 @@ public interface BpmnConstants {
|
||||
* 提级审批变量标识
|
||||
*/
|
||||
String SUPPORT_UPGRADE_VARIABLE = "[_SUPPORT_UPGRADE_]";
|
||||
/**
|
||||
* 前加签节点 ID 片段
|
||||
*/
|
||||
String FORWARD_ACTIVITY_FRAGMENT = "[forward_sign]";
|
||||
/**
|
||||
* 后加签节点 ID 片段
|
||||
*/
|
||||
String BACK_ACTIVITY_FRAGMENT = "[back_sign]";
|
||||
}
|
||||
|
||||
@ -29,14 +29,20 @@ public interface VariableConstants {
|
||||
|
||||
//=============== 打印时的变量集合中 key 的命名 =================
|
||||
String VAR_PREFIX = "业务变量";
|
||||
String PRINT_VAR_PROCESS_NAME = "processName";
|
||||
String PRINT_VAR_PROCESS_NAME_DESC = "审批名称";
|
||||
String PRINT_VAR_PROCESS_DEFINITION_KEY = "processDefinitionKey";
|
||||
String PRINT_VAR_PROCESS_DEFINITION_KEY_DESC = "业务名称";
|
||||
String PRINT_VAR_PROCESS_BELONG_TENANT_ID = "tenantId";
|
||||
String PRINT_VAR_PROCESS_BELONG_TENANT_ID_DESC = "所属租户";
|
||||
String PRINT_VAR_PROCESS_INSTANCE_ID = "processInstanceId";
|
||||
String PRINT_VAR_PROCESS_INSTANCE_ID_DESC = "审批编号";
|
||||
String PRINT_VAR_PROCESS_START_TIME = "startTime";
|
||||
String PRINT_VAR_PROCESS_START_TIME_DESC = "发起时间";
|
||||
String PRINT_VAR_PROCESS_END_TIME = "endTime";
|
||||
String PRINT_VAR_PROCESS_END_TIME_DESC = "审批结束时间";
|
||||
String PRINT_VAR_PROCESS_RESULT = "processResult";
|
||||
String PRINT_VAR_PROCESS_RESULT_DESC = "审批结果";
|
||||
String PRINT_VAR_PROCESS_INITIATOR = "initiator";
|
||||
String PRINT_VAR_PROCESS_INITIATOR_DESC = "发起者";
|
||||
String PRINT_VAR_PROCESS_INITIATOR_NAME = "initiatorName";
|
||||
@ -45,12 +51,16 @@ public interface VariableConstants {
|
||||
String PRINT_VAR_PROCESS_INITIATOR_POSITION_DESC = "发起人岗位";
|
||||
String PRINT_VAR_PROCESS_INITIATOR_PHONE = "initiatorPhone";
|
||||
String PRINT_VAR_PROCESS_INITIATOR_PHONE_DESC = "发起人联系方式";
|
||||
String PRINT_VAR_PROCESS_INITIATOR_UNIT = "initiatorUnit";
|
||||
String PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC = "发起人单位";
|
||||
String PRINT_VAR_PROCESS_LOGS = "processLogs";
|
||||
String PRINT_VAR_PROCESS_LOGS_DESC = "审批日志";
|
||||
String PRINT_VAR_PROCESS_LOG_ACTIVITY_NODE_TYPE = "activityNodeType";
|
||||
String PRINT_VAR_PROCESS_LOG_ACTIVITY_NODE_TYPE_DESC = "节点类型";
|
||||
String PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME = "activityName";
|
||||
String PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME_DESC = "节点名称";
|
||||
String PRINT_VAR_PROCESS_LOG_APPROVER_NAME = "approverName";
|
||||
String PRINT_VAR_PROCESS_LOG_APPROVER_NAME_DESC = "审批人";
|
||||
String PRINT_VAR_PROCESS_LOG_APPROVER_NAME_DESC = "姓名";
|
||||
String PRINT_VAR_PROCESS_LOG_UNIT = "unit";
|
||||
String PRINT_VAR_PROCESS_LOG_UNIT_DESC = "单位";
|
||||
String PRINT_VAR_PROCESS_LOG_POSITION = "position";
|
||||
@ -61,4 +71,10 @@ public interface VariableConstants {
|
||||
String PRINT_VAR_PROCESS_LOG_OPERATION_TIME_DESC = "审批时间";
|
||||
String PRINT_VAR_PROCESS_LOG_SIGNATURE = "signature";
|
||||
String PRINT_VAR_PROCESS_LOG_SIGNATURE_DESC = "电子签名";
|
||||
String PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT = "activityResult";
|
||||
String PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT_DESC = "审批结果";
|
||||
String PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME = "activityOperationTime";
|
||||
String PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME_DESC = "日期";
|
||||
String PRINT_VAR_PROCESS_LOG_OPERATION = "operationDesc";
|
||||
String PRINT_VAR_PROCESS_LOG_OPERATION_DESC = "操作描述";
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ public enum BpmnFlowNodeMode {
|
||||
GENERAL("GENERAL", "普通节点"),
|
||||
OR("OR", "或签节点"),
|
||||
AND("AND", "会签节点"),
|
||||
SEQUENCE("SEQUENCE", "顺序节点"),
|
||||
EXCEPTIONAL("EXCEPTIONAL", "异常"),
|
||||
@JsonEnumDefaultValue
|
||||
UNKNOWN("UNKNOWN", "未知"),
|
||||
|
||||
@ -19,6 +19,7 @@ public enum BpmnProcessInstanceResultEnum {
|
||||
UPGRADED("UPGRADED", "已提级"),
|
||||
COMMENTED("COMMENTED", "已评论"),
|
||||
DELETED("DELETED", "已删除"),
|
||||
HIDDEN("HIDDEN", "已隐藏"),
|
||||
@JsonEnumDefaultValue
|
||||
UNKNOWN("UNKNOWN", "未知"),
|
||||
;
|
||||
|
||||
@ -46,6 +46,10 @@ public enum FormFieldTypeEnum {
|
||||
}),
|
||||
decimal("decimal", "小数", new TypeReference<Map<String, Object>>() {
|
||||
}),
|
||||
checkbox("checkbox", "复选框", new TypeReference<List<String>>() {
|
||||
}),
|
||||
radio("radio", "单选框", new TypeReference<String>() {
|
||||
})
|
||||
;
|
||||
|
||||
private final String type;
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
package cn.axzo.workflow.common.exception;
|
||||
|
||||
import cn.axzo.framework.domain.ServiceException;
|
||||
import cn.axzo.framework.domain.web.code.IRespCode;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 流程内部计算审批人的异常
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-11-03 10:11
|
||||
*/
|
||||
@Slf4j
|
||||
public class WorkflowApproverCalcException extends ServiceException {
|
||||
|
||||
private String code;
|
||||
|
||||
public WorkflowApproverCalcException(IRespCode code) {
|
||||
super(code.getMessage());
|
||||
this.code = code.getRespCode();
|
||||
}
|
||||
|
||||
public WorkflowApproverCalcException(IRespCode code, String... params) {
|
||||
super(doFormat(code.getCode(), code.getMessage(), params));
|
||||
this.code = code.getRespCode();
|
||||
}
|
||||
|
||||
public WorkflowApproverCalcException(IRespCode code, Throwable cause, String... params) {
|
||||
super(doFormat(code.getCode(), code.getMessage(), params), cause);
|
||||
this.code = code.getRespCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将错误编号对应的消息使用 params 进行格式化。
|
||||
*
|
||||
* @param code 错误编号
|
||||
* @param messagePattern 消息模版
|
||||
* @param params 参数
|
||||
* @return 格式化后的提示
|
||||
*/
|
||||
@VisibleForTesting
|
||||
private static String doFormat(String code, String messagePattern, Object... params) {
|
||||
StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
|
||||
int i = 0;
|
||||
int j;
|
||||
int l;
|
||||
for (l = 0; l < params.length; l++) {
|
||||
j = messagePattern.indexOf("{}", i);
|
||||
if (j == -1) {
|
||||
log.warn("[doFormat][参数过多:错误码({})|错误内容({})|参数({})", code, messagePattern, params);
|
||||
if (i == 0) {
|
||||
return messagePattern;
|
||||
} else {
|
||||
sbuf.append(messagePattern.substring(i));
|
||||
return sbuf.toString();
|
||||
}
|
||||
} else {
|
||||
sbuf.append(messagePattern, i, j);
|
||||
sbuf.append(params[l]);
|
||||
i = j + 2;
|
||||
}
|
||||
}
|
||||
if (messagePattern.indexOf("{}", i) != -1) {
|
||||
log.warn("[doFormat][参数过少:错误码({})|错误内容({})|参数({})", code, messagePattern, params);
|
||||
}
|
||||
sbuf.append(messagePattern.substring(i));
|
||||
return sbuf.toString();
|
||||
}
|
||||
}
|
||||
@ -40,6 +40,11 @@ public class CooperationOrgDTO implements Serializable {
|
||||
*/
|
||||
private List<String> includeSpecialtyCodes;
|
||||
|
||||
/**
|
||||
* 该参数仅应用于节点的高级设置中的"仅支持工程内人员参与审批”
|
||||
*/
|
||||
private List<Long> projectIds;
|
||||
|
||||
/**
|
||||
* 企业组织架构范围
|
||||
**/
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
package cn.axzo.workflow.common.model.dto;
|
||||
|
||||
import cn.axzo.workflow.common.enums.FileTypeEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 签署文件记录信息
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-04-03 11:21
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class CustomDocDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8709597975507074853L;
|
||||
/**
|
||||
* 该属性内部使用,无需赋值
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
@NotBlank(message = "业务自定义文件名称不能为空")
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* 文件的标签
|
||||
*/
|
||||
private String fileTag;
|
||||
|
||||
/**
|
||||
* 如果业务是使用在线文档,则一定会有 wps code,如果有则传入
|
||||
* <p>
|
||||
* wps 文件的标识,通过{@link cn.axzo.nanopart.doc.api.anonymous.DocAnonymousDatabaseApi#createFile(cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateFileRequest)} 接口创建文件后返回的 fileCode
|
||||
*/
|
||||
private String fileCode;
|
||||
/**
|
||||
* 不管是在线文件还是本地上传,必须包含 oss 地址的文件标识
|
||||
*/
|
||||
@NotBlank(message = "业务自定义文件的 oss key 不能为空")
|
||||
private String fileKey;
|
||||
|
||||
/**
|
||||
* 文件的类型,如果要替换变量,支持 docx 格式,doc 格式不支持。
|
||||
*/
|
||||
@NotNull(message = "业务自定义文件的类型不能为空")
|
||||
private FileTypeEnum fileType;
|
||||
|
||||
/**
|
||||
* 文件是否需要变量替换,默认不替换
|
||||
* <p>
|
||||
* 不建议无脑设置为 true,否则可能会影响性能
|
||||
*/
|
||||
private Boolean needReplaceVariables = false;
|
||||
|
||||
}
|
||||
@ -57,4 +57,9 @@ public class SignFileDTO implements Serializable {
|
||||
* 替换变量后的文件 fileKey
|
||||
*/
|
||||
private String fileKey;
|
||||
|
||||
/**
|
||||
* 是否需要替换变量
|
||||
*/
|
||||
private Boolean needReplaceVariables;
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -39,7 +40,11 @@ public class SignatureDTO implements Serializable {
|
||||
@Accessors(chain = true)
|
||||
public static class SignDetail implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
//审批人姓名
|
||||
private String approverName;
|
||||
private String signature;
|
||||
private String advice;
|
||||
private String result;
|
||||
private Date operationTime;
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ public class BpmnFieldOptionConf implements Serializable {
|
||||
* 选项的值
|
||||
*/
|
||||
@ApiModelProperty(value = "选项的值", example = "1")
|
||||
private String value;
|
||||
private Object value;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
@ -37,11 +37,11 @@ public class BpmnFieldOptionConf implements Serializable {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||
import cn.axzo.workflow.common.enums.CooperateShipTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.InitiatorSpecifiedRangeEnum;
|
||||
import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum;
|
||||
import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo;
|
||||
import cn.axzo.workflow.common.model.request.form.FormPermissionMetaInfo;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
@ -201,6 +202,12 @@ public class BpmnJsonNodeProperty {
|
||||
@ApiModelProperty(value = "表单字段权限控制")
|
||||
private List<FormPermissionMetaInfo> fieldPermission;
|
||||
|
||||
/**
|
||||
* 条件字段权限配置
|
||||
*/
|
||||
@ApiModelProperty(value = "条件字段权限控制")
|
||||
private List<ConditionPermissionMetaInfo> conditionPermission;
|
||||
|
||||
/**
|
||||
* 区域过滤开关
|
||||
*/
|
||||
@ -213,4 +220,9 @@ public class BpmnJsonNodeProperty {
|
||||
@ApiModelProperty(value = "专业过滤开关", notes = "true: 开启专业过滤, false: 关闭专业过滤")
|
||||
private Boolean specialtyFilterEnable;
|
||||
|
||||
/**
|
||||
* 工程内人员开关
|
||||
*/
|
||||
@ApiModelProperty(value = "仅工程内人员开关", notes = "true: 仅工程内人员, false: 非仅工程内人员")
|
||||
private Boolean onlyInProjectEnable;
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.print;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 获取内置公共模板打印数据的入参模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-30 10:43
|
||||
*/
|
||||
@ApiModel("获取内置公共模板打印数据的入参模型")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class Print4ProcessLogDTO {
|
||||
|
||||
/**
|
||||
* 流程实例 ID
|
||||
*/
|
||||
@ApiModelProperty(value = "流程实例 ID")
|
||||
@NotBlank(message = "流程实例 ID 不能为空")
|
||||
private String processInstanceId;
|
||||
|
||||
}
|
||||
@ -35,6 +35,11 @@ public class PrintFieldQueryDTO {
|
||||
@ApiModelProperty(value = "租户 ID")
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 是否过滤仅支持打印字段
|
||||
*/
|
||||
@ApiModelProperty(value = "是否过滤仅支持打印字段")
|
||||
private Boolean filterEnablePrint;
|
||||
/**
|
||||
* 是否抛出内部异常
|
||||
*/
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.print;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.validation.constraints.AssertTrue;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 请求审批日志转 pdf 的入参模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-31 17:15
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class PrintProcessLogPdfDTO {
|
||||
|
||||
/**
|
||||
* 审批实例 ID
|
||||
*/
|
||||
@ApiModelProperty(value = "审批实例 ID")
|
||||
@NotBlank(message = "审批实例 ID 不能为空")
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 实例日志访问者的personId
|
||||
*/
|
||||
@ApiModelProperty(value = "访问者的 PersonId")
|
||||
@NotBlank(message = "访问者的 personId 不能为空")
|
||||
private String personId;
|
||||
|
||||
/**
|
||||
* 自定义该审批日志的 bizCode
|
||||
* 可不传,默认值为: workflow-process-log
|
||||
*/
|
||||
private String bizCode;
|
||||
|
||||
/**
|
||||
* 自定义该审批日志的 bizKey
|
||||
* 可不传, 默认值为:{@link PrintProcessLogPdfDTO#processInstanceId}
|
||||
*/
|
||||
private String bizKey;
|
||||
|
||||
@AssertTrue(message = "bizKey和bizCode必须同时为空或同时不为空")
|
||||
public boolean isBizKeyAndCodeValid() {
|
||||
boolean hasBizCode = StringUtils.hasText(bizCode);
|
||||
boolean hasBizKey = StringUtils.hasText(bizKey);
|
||||
return hasBizCode == hasBizKey;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.print;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.validation.constraints.AssertTrue;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 查询审批日志转 pdf 的入参模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-31 17:15
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class QueryProcessLogPdfDTO {
|
||||
|
||||
/**
|
||||
* 审批实例 ID
|
||||
*/
|
||||
@ApiModelProperty(value = "审批实例 ID")
|
||||
@NotBlank(message = "审批实例 ID 不能为空")
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 访问人的 personId
|
||||
*/
|
||||
@ApiModelProperty(value = "对应生成时的访问人 personId")
|
||||
@NotBlank(message = "访问者的 personId 不能为空")
|
||||
private String personId;
|
||||
|
||||
/**
|
||||
* 自定义该审批日志的 bizCode
|
||||
* 可不传,默认值为: workflow-process-log
|
||||
*/
|
||||
private String bizCode;
|
||||
|
||||
/**
|
||||
* 自定义该审批日志的 bizKey
|
||||
* 可不传, 默认值为:{@link QueryProcessLogPdfDTO#processInstanceId}
|
||||
*/
|
||||
private String bizKey;
|
||||
|
||||
@AssertTrue(message = "bizKey和bizCode必须同时为空或同时不为空")
|
||||
public boolean isBizKeyAndCodeValid() {
|
||||
boolean hasBizCode = StringUtils.hasText(bizCode);
|
||||
boolean hasBizKey = StringUtils.hasText(bizKey);
|
||||
return hasBizCode == hasBizKey;
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,6 +2,7 @@ package cn.axzo.workflow.common.model.request.bpmn.process;
|
||||
|
||||
import cn.axzo.workflow.common.constant.BpmnConstants;
|
||||
import cn.axzo.workflow.common.model.dto.CooperationOrgDTO;
|
||||
import cn.axzo.workflow.common.model.dto.CustomDocDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
@ -10,6 +11,7 @@ import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
@ -120,6 +122,30 @@ public class BpmnProcessInstanceCreateDTO extends BpmnProcessInstanceCreateWithF
|
||||
@ApiModelProperty(value = "签署业务发起时,选择的文档")
|
||||
private List<Long> docIds;
|
||||
|
||||
/**
|
||||
* "签字业务"专用
|
||||
* <p>
|
||||
* 业务自定义的文档
|
||||
*/
|
||||
@ApiModelProperty(value = "业务自定义文档")
|
||||
private List<CustomDocDTO> customDocs;
|
||||
|
||||
/**
|
||||
* "签字业务"专用,自定义文档的顺序位置信息,在流程模板配置文档之前还是之后, 该属性与{@link BpmnProcessInstanceCreateDTO#basedFileTagOrder} 互斥
|
||||
* <p>
|
||||
* 可选值:first(之前)、last(之后), 如果为空,默认为 last
|
||||
*/
|
||||
@ApiModelProperty(value = "自定义文档顺序位置", notes = "可选值:first(之前)、last(之后), 如果为空,默认为 last")
|
||||
private String docAddOrderType = "last";
|
||||
|
||||
/**
|
||||
* "签字业务"专用, 该属性与{@link BpmnProcessInstanceCreateDTO#docAddOrderType} 互斥
|
||||
* <p>
|
||||
* 业务对所有文档的顺序覆盖,必须对全量文档进行设置
|
||||
*/
|
||||
@ApiModelProperty(value = "业务对所有文档的顺序覆盖")
|
||||
public List<String> basedFileTagOrder;
|
||||
|
||||
/**
|
||||
* 仅针对签署业务,设置审批完成后的最终签署人列表,该属性仅为透传,业务消费时,请从 MQ 广播事件中的 variables 中通过 key= {@link BpmnConstants#SIGNATORIES } 获取
|
||||
*/
|
||||
@ -132,4 +158,14 @@ public class BpmnProcessInstanceCreateDTO extends BpmnProcessInstanceCreateWithF
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<CustomDocDTO> getCustomDocs() {
|
||||
if (CollectionUtils.isEmpty(customDocs)) {
|
||||
return customDocs;
|
||||
}
|
||||
for (int i = 0; i < customDocs.size(); i++) {
|
||||
customDocs.get(i).setId(i - (i + 1L)); // 负数 ID,避免冲突
|
||||
}
|
||||
return customDocs;
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.process;
|
||||
|
||||
import cn.axzo.workflow.common.model.dto.UploadFieldDTO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@ -20,15 +19,7 @@ public class BpmnProcessInstanceCreateWithFormDTO {
|
||||
/**
|
||||
* 审批使用了表单,请一定注意传参
|
||||
* <p>
|
||||
* 图片类型和附件类型组件:请用 @see {@link UploadFieldDTO} 对象集合传入
|
||||
* <pre>
|
||||
* // form_image 为表单项的 key, value 为 UploadFileDTO 对象集合,如果前端使用了组件,一般建议回传所有属性;特殊情况下可以只传 fileUrl
|
||||
* "form_image": [{
|
||||
* "fileName": "",
|
||||
* "fileUrl": "http://gips2.baidu.com/it/u=195724436,3554684702&fm=3028&app=3028&f=JPEG&fmt=auto?w=1280&h=960",
|
||||
* "fileKey": 123
|
||||
* }]
|
||||
* </pre>
|
||||
* 请先查看{@see https://alidocs.dingtalk.com/i/nodes/ZgpG2NdyVXKy17o6fQ5nKGvMWMwvDqPk}文档,根据不同类型传不同的 value 对象
|
||||
*/
|
||||
@ApiModelProperty(value = "通过表单创建流程时传入的初始表单数据")
|
||||
private Map<String, Object> startFormVariables;
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.process;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 更新流程实例中变量集合的入参模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-24 10:56
|
||||
*/
|
||||
@ApiModel("更新流程实例中变量集合的入参模型")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class BpmnProcessInstanceVariablesUpdateDTO {
|
||||
|
||||
/**
|
||||
* 流程实例 ID
|
||||
*/
|
||||
@NotBlank(message = "流程实例 ID 不能为空")
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 业务管理中定义变量的入参, 如果 key 在创建时已存在,则进行覆盖更新,否则新增变量
|
||||
* <p>
|
||||
* 对应创建流程实例中的 {@link BpmnProcessInstanceCreateDTO#bizCustomVariables} 属性
|
||||
*/
|
||||
private Map<String, Object> bizCustomVariables;
|
||||
|
||||
}
|
||||
@ -16,6 +16,7 @@ import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 审批任务节点的入参模型
|
||||
@ -103,4 +104,11 @@ public class BpmnTaskAuditDTO {
|
||||
*/
|
||||
@Deprecated
|
||||
private String operationDesc;
|
||||
|
||||
/**
|
||||
* 更新或新增流程变量,
|
||||
* <p>
|
||||
* 如果不修改,则map 的 value 设置为 null,内部会自动过滤
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
}
|
||||
|
||||
@ -93,4 +93,10 @@ public class CategoryCreateDTO {
|
||||
@ApiModelProperty(value = "版本号")
|
||||
private Integer version;
|
||||
|
||||
/**
|
||||
* 自定替换未设置的变量为空串
|
||||
*/
|
||||
@ApiModelProperty(value = "是否自动替换变量为空串,默认false")
|
||||
private Boolean autoReplaceVariables;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,105 @@
|
||||
package cn.axzo.workflow.common.model.request.form;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 表单字段权限信息
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-11-07 11:09
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class ConditionPermissionMetaInfo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 条件标识
|
||||
*/
|
||||
private String conditionCode;
|
||||
|
||||
/**
|
||||
* 条件名称
|
||||
*/
|
||||
private String conditionName;
|
||||
|
||||
/**
|
||||
* 单选框
|
||||
* 条件类型(text/number/checkbox/radio)
|
||||
*/
|
||||
private String conditionType;
|
||||
/**
|
||||
* 可编辑必填
|
||||
*/
|
||||
@Builder.Default
|
||||
private Boolean required = false;
|
||||
|
||||
/**
|
||||
* 可编辑非必填
|
||||
*/
|
||||
@Builder.Default
|
||||
private Boolean editable = false;
|
||||
|
||||
/**
|
||||
* 只读
|
||||
*/
|
||||
@Builder.Default
|
||||
private Boolean readonly = true;
|
||||
|
||||
/**
|
||||
* 隐藏
|
||||
*/
|
||||
@Builder.Default
|
||||
private Boolean hidden = false;
|
||||
|
||||
/**
|
||||
* 前端回显字段,后端不做任何消费逻辑
|
||||
*/
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* 类型是单选复选时的选项值
|
||||
*/
|
||||
private String options;
|
||||
|
||||
|
||||
// 将对象的属性转换为对应的整数表示
|
||||
public int toBinary() {
|
||||
int binaryValue = 0;
|
||||
binaryValue |= (required ? 1 : 0) << 3;
|
||||
binaryValue |= (editable ? 1 : 0) << 2;
|
||||
binaryValue |= (readonly ? 1 : 0) << 1;
|
||||
binaryValue |= (hidden ? 1 : 0);
|
||||
return binaryValue;
|
||||
}
|
||||
|
||||
// 从整数表示还原出对象
|
||||
public static ConditionPermissionMetaInfo fromBinary(String conditionCode, String conditionName, String conditionType, int binaryValue) {
|
||||
boolean required = ((binaryValue >> 3) & 1) == 1;
|
||||
boolean editable = ((binaryValue >> 2) & 1) == 1;
|
||||
boolean readonly = ((binaryValue >> 1) & 1) == 1;
|
||||
boolean hidden = (binaryValue & 1) == 1;
|
||||
return new ConditionPermissionMetaInfo(conditionCode, conditionName, conditionType, required, editable, readonly, hidden, null, null);
|
||||
}
|
||||
|
||||
public ConditionPermissionMetaInfo toReadonly() {
|
||||
if (required || editable || readonly) {
|
||||
setRequired(false);
|
||||
setEditable(false);
|
||||
setReadonly(true);
|
||||
setHidden(false);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toBinaryString() {
|
||||
return String.format("%04d", Integer.parseInt(Integer.toBinaryString(toBinary()), 10));
|
||||
}
|
||||
}
|
||||
@ -22,7 +22,7 @@ import java.util.Map;
|
||||
public class FormFieldDTO {
|
||||
|
||||
/**
|
||||
* 字段类型, 如果是分组:FormContainer,其他表单组件:FormField
|
||||
* 字段类型, 如果是分组:FormContainer,单选复选组件:OptionFormField,其他表单组件:FormField,
|
||||
*/
|
||||
@ApiModelProperty(value = "表单字段类型")
|
||||
@NotBlank(message = "字段类型不能为空")
|
||||
@ -41,6 +41,9 @@ public class FormFieldDTO {
|
||||
* { label: "变洽签单", value: "changeSignatureOrder" },
|
||||
* { label: "通讯录", value: "contacts" },
|
||||
* { label: "金额", value: "amount" },
|
||||
* { label: "复选", value: "checkbox" },
|
||||
* { label: "单选", value: "radio" },
|
||||
*
|
||||
*/
|
||||
@ApiModelProperty(value = "前端的组件类型")
|
||||
private String type;
|
||||
@ -76,6 +79,14 @@ public class FormFieldDTO {
|
||||
@ApiModelProperty(value = "该表单字段的其他扩展属性,期望 JSON 格式")
|
||||
private Map<String, Object> params;
|
||||
|
||||
/**
|
||||
* 单选复选框的选项
|
||||
* <p>
|
||||
* {@see org.flowable.form.model.OptionFormField}
|
||||
*/
|
||||
@ApiModelProperty(value = "单选复选框的选项,配合 fieldType=OptionFormField 使用")
|
||||
private List<OptionDTO> options;
|
||||
|
||||
/**
|
||||
* 当 fieldType=FormContainer 时,这里的代表内部的集合
|
||||
*/
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
package cn.axzo.workflow.common.model.request.form.definition;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 单选复选框的选项入参模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-11-20 10:57
|
||||
*/
|
||||
@ApiModel("单选复选框的选项入参模型")
|
||||
@Data
|
||||
public class OptionDTO {
|
||||
/**
|
||||
* 选项 ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 选项名称
|
||||
*/
|
||||
private String name;
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package cn.axzo.workflow.common.model.response;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 审批日志项模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-30 14:22
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ProcessLogItemDTO {
|
||||
@Builder.Default
|
||||
private String label = "审批流程";
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
private String advice;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
@ApiModelProperty(value = "节点名称")
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 操作描述
|
||||
*/
|
||||
@ApiModelProperty(value = "操作描述")
|
||||
private String operationDesc;
|
||||
|
||||
/**
|
||||
* 图片列表
|
||||
*/
|
||||
@ApiModelProperty(value = "图片列表")
|
||||
private List<AttachmentDTO> imageList;
|
||||
/**
|
||||
* 附件列表
|
||||
*/
|
||||
@ApiModelProperty(value = "附件列表")
|
||||
private List<AttachmentDTO> fileList;
|
||||
/**
|
||||
* 手写签名地址
|
||||
*/
|
||||
@ApiModelProperty(value = "手写签名地址")
|
||||
private String signatureUrl;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
@ApiModelProperty(value = "操作时间")
|
||||
private String operationTime;
|
||||
|
||||
/**
|
||||
* 日志项结果,对应{@link BpmnProcessInstanceResultEnum#name()}
|
||||
*/
|
||||
@ApiModelProperty(value = "日志项结果")
|
||||
private String result;
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package cn.axzo.workflow.common.model.response;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 审批日志公共打印模板的字段项模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-30 10:38
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TableItemDTO {
|
||||
/**
|
||||
* 中文
|
||||
*/
|
||||
private String label;
|
||||
/**
|
||||
* 字段 code
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 字段类型
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
private Object value;
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package cn.axzo.workflow.common.model.response.bpmn.process;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.response.ProcessLogItemDTO;
|
||||
import cn.axzo.workflow.common.model.response.TableItemDTO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 新版的审批日志公共模板的数据响应模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-30 10:28
|
||||
*/
|
||||
@ApiModel("新版的审批日志公共模板的数据响应模型")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class PrintData4LogVO {
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String processName;
|
||||
/**
|
||||
* 发起租户名称
|
||||
*/
|
||||
private String tenantName;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private String createAt;
|
||||
/**
|
||||
* 审批状态
|
||||
*/
|
||||
private BpmnProcessInstanceResultEnum result;
|
||||
|
||||
/**
|
||||
* 系统变量表格项
|
||||
*/
|
||||
private List<TableItemDTO> systemVarItems;
|
||||
|
||||
/**
|
||||
* 审批日志表格项
|
||||
*/
|
||||
private List<ProcessLogItemDTO> logItems;
|
||||
}
|
||||
|
||||
@ -47,6 +47,9 @@ public class CategoryItemVO {
|
||||
@ApiModelProperty(value = "版本号")
|
||||
private Integer version;
|
||||
|
||||
@ApiModelProperty(value = "自定替换未设置的变量为空串")
|
||||
private Boolean autoReplaceVariables;
|
||||
|
||||
@ApiModelProperty(value = "更新时间")
|
||||
private Date updateAt;
|
||||
}
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
package cn.axzo.workflow.common.model.response.print;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 审批日志 PDF 查询结果相应模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-11-07 18:13
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ProcessLogPdfResultDTO {
|
||||
|
||||
/**
|
||||
* 转换状态
|
||||
* INIT("初始"),
|
||||
* <p>
|
||||
* CONVERTING("转换中"),
|
||||
* <p>
|
||||
* SUCCESS("转换完成"),
|
||||
* <p>
|
||||
* FAILED("转换失败");
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 转换成功后的oss fileKey
|
||||
*/
|
||||
private String pdfFileKey;
|
||||
}
|
||||
@ -1,8 +1,9 @@
|
||||
package cn.axzo.workflow.core.common.utils;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnCondition;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnCondition;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -20,7 +21,8 @@ import static cn.axzo.workflow.common.code.ConvertorRespCode.CONVERTOR_OPERATION
|
||||
* @since 2023/11/16 23:30
|
||||
*/
|
||||
public final class BpmnExpressionTranslator {
|
||||
private BpmnExpressionTranslator() {}
|
||||
private BpmnExpressionTranslator() {
|
||||
}
|
||||
|
||||
public static String translateString(BpmnCondition condition) {
|
||||
// ${var:contains('variableName', 'hello')};
|
||||
@ -88,7 +90,8 @@ public final class BpmnExpressionTranslator {
|
||||
"('" +
|
||||
condition.getCode() +
|
||||
"', " +
|
||||
condition.getDefaultValue() +
|
||||
(NumberUtils.isDigits(condition.getDefaultValue()) ? condition.getDefaultValue() : "'" + condition.getDefaultValue() + "'")
|
||||
+
|
||||
")";
|
||||
} else {
|
||||
throw new WorkflowEngineException(CONVERTOR_OPERATION_RADIO_TYPE_ERROR, condition.getOperator());
|
||||
|
||||
@ -90,7 +90,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_META;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_OPTION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_OPTIONS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NOTICE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_TYPE;
|
||||
@ -346,22 +346,10 @@ public final class BpmnJsonConverterUtil {
|
||||
field.addAttribute(fieldCode);
|
||||
|
||||
if (!CollectionUtils.isEmpty(i.getOptions())) {
|
||||
i.getOptions().forEach(j -> {
|
||||
ExtensionElement option = new ExtensionElement();
|
||||
option.setName(CONFIG_FIELD_OPTION);
|
||||
|
||||
ExtensionAttribute optionName = new ExtensionAttribute();
|
||||
optionName.setName(ELEMENT_ATTRIBUTE_NAME);
|
||||
optionName.setValue(j.getName());
|
||||
option.addAttribute(optionName);
|
||||
|
||||
ExtensionAttribute optionValue = new ExtensionAttribute();
|
||||
optionValue.setName(ELEMENT_ATTRIBUTE_VALUE);
|
||||
optionValue.setValue(j.getValue());
|
||||
option.addAttribute(optionValue);
|
||||
|
||||
field.addChildElement(option);
|
||||
});
|
||||
ExtensionAttribute fieldOptions = new ExtensionAttribute();
|
||||
fieldOptions.setName(CONFIG_FIELD_OPTIONS);
|
||||
fieldOptions.setValue(JSON.toJSONString(i.getOptions()));
|
||||
field.addAttribute(fieldOptions);
|
||||
}
|
||||
fieldConfigElement.addChildElement(field);
|
||||
});
|
||||
|
||||
@ -31,6 +31,7 @@ import cn.axzo.workflow.common.model.request.bpmn.BpmnSignConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnSignPendingProperty;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnSmsProperty;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnUpgradeApprovalConf;
|
||||
import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo;
|
||||
import cn.axzo.workflow.common.model.request.form.FormPermissionMetaInfo;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
@ -82,9 +83,11 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPIE
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY_OBJECT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY_SPECIFY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CONDITION_PERMISSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_META;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_OPTION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_OPTIONS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_PERMISSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_LEADER_RANGE_UNIT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_EXCLUDE_COOPERATE_TYPES;
|
||||
@ -93,6 +96,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SP
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_RANGE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NODE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NOTICE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_ONLY_IN_PROJECT_ENABLE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_LIMIT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_ORG_LIMIT;
|
||||
@ -430,15 +434,20 @@ public final class BpmnMetaParserHelper {
|
||||
conf.setName(i.getAttributeValue(null, ELEMENT_ATTRIBUTE_NAME));
|
||||
conf.setCode(i.getAttributeValue(null, ELEMENT_ATTRIBUTE_CODE));
|
||||
|
||||
List<BpmnFieldOptionConf> options = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(i.getChildElements())) {
|
||||
i.getChildElements().get(CONFIG_FIELD_OPTION).forEach(j -> {
|
||||
BpmnFieldOptionConf option = new BpmnFieldOptionConf();
|
||||
option.setName(j.getAttributeValue(null, ELEMENT_ATTRIBUTE_NAME));
|
||||
option.setValue(j.getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE));
|
||||
options.add(option);
|
||||
});
|
||||
conf.setOptions(options);
|
||||
String fieldOptionsJsonStr = i.getAttributeValue(null, CONFIG_FIELD_OPTIONS);
|
||||
if (StringUtils.hasText(fieldOptionsJsonStr)) {
|
||||
conf.setOptions(JSON.parseArray(fieldOptionsJsonStr, BpmnFieldOptionConf.class));
|
||||
} else {
|
||||
List<BpmnFieldOptionConf> options = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(i.getChildElements())) {
|
||||
i.getChildElements().get(CONFIG_FIELD_OPTION).forEach(j -> {
|
||||
BpmnFieldOptionConf option = new BpmnFieldOptionConf();
|
||||
option.setName(j.getAttributeValue(null, ELEMENT_ATTRIBUTE_NAME));
|
||||
option.setValue(j.getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE));
|
||||
options.add(option);
|
||||
});
|
||||
conf.setOptions(options);
|
||||
}
|
||||
}
|
||||
|
||||
fields.add(conf);
|
||||
@ -648,6 +657,10 @@ public final class BpmnMetaParserHelper {
|
||||
return defaultValid(flowElement, CONFIG_SPECIALTY_FILTER_ENABLE).map(element -> Boolean.valueOf(element.getAttributeValue(null, ELEMENT_ATTRIBUTE_CHECKED))).orElse(false);
|
||||
}
|
||||
|
||||
public static Boolean getOnlyInProjectEnable(FlowElement flowElement) {
|
||||
return defaultValid(flowElement, CONFIG_ONLY_IN_PROJECT_ENABLE).map(element -> Boolean.valueOf(element.getAttributeValue(null, ELEMENT_ATTRIBUTE_CHECKED))).orElse(false);
|
||||
}
|
||||
|
||||
private static Optional<ExtensionElement> defaultValid(FlowElement flowElement, String elementName) {
|
||||
if (Objects.isNull(flowElement)) {
|
||||
return Optional.empty();
|
||||
@ -692,6 +705,11 @@ public final class BpmnMetaParserHelper {
|
||||
}.getType()));
|
||||
}
|
||||
|
||||
public static Optional<List<ConditionPermissionMetaInfo>> getConditionPermissionConf(FlowElement flowElement) {
|
||||
return defaultValid(flowElement, CONFIG_CONDITION_PERMISSION).map(element -> JSON.parseObject(element.getElementText(), new TypeReference<List<ConditionPermissionMetaInfo>>() {
|
||||
}.getType()));
|
||||
}
|
||||
|
||||
public static Optional<ImmutableTable<String, String, Integer>> getFormFieldPermissionForCalc(FlowElement flowElement) {
|
||||
List<FormPermissionMetaInfo> fieldMetaInfos = getFormFieldPermissionConf(flowElement).orElse(new ArrayList<>());
|
||||
return getFormFieldPermissionForModel(fieldMetaInfos);
|
||||
|
||||
@ -2,6 +2,7 @@ package cn.axzo.workflow.core.conf;
|
||||
|
||||
import cn.axzo.workflow.core.common.utils.SpringContextUtils;
|
||||
import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory;
|
||||
import cn.axzo.workflow.core.engine.cfg.CustomDefaultInternalJobManager;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory;
|
||||
import cn.axzo.workflow.core.engine.formhandler.CustomFormFieldHandler;
|
||||
import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator;
|
||||
@ -26,6 +27,7 @@ import cn.axzo.workflow.core.engine.job.exception.handle.CustomAsyncJobLogClearT
|
||||
import cn.axzo.workflow.core.engine.job.exception.handle.CustomAsyncRunnableExceptionExceptionHandler;
|
||||
import cn.axzo.workflow.core.engine.persistence.CustomMybatisHistoricProcessInstanceDataManager;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessActivityService;
|
||||
import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService;
|
||||
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
|
||||
import cn.azxo.framework.common.constatns.Constants;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
@ -82,6 +84,7 @@ public class FlowableConfiguration {
|
||||
ObjectProvider<FlowableEventListener> listeners,
|
||||
CustomActivityBehaviorFactory customActivityBehaviorFactory,
|
||||
ExtAxHiTaskInstService extAxHiTaskInstService,
|
||||
ExtAxDynamicSignRecordService extAxDynamicSignRecordService,
|
||||
BpmnProcessActivityService bpmnProcessActivityService,
|
||||
List<JobProcessor> jobProcessors,
|
||||
NacosServiceManager nacosServiceManager,
|
||||
@ -109,7 +112,7 @@ public class FlowableConfiguration {
|
||||
configuration.addCustomJobHandler(new AsyncApproveTaskJobHandler());
|
||||
configuration.addCustomJobHandler(new AsyncBackTaskJobHandler());
|
||||
configuration.addCustomJobHandler(new AsyncCancelProcessInstanceJobHandler(extAxHiTaskInstService));
|
||||
configuration.addCustomJobHandler(new AsyncCountersignUserTaskJobHandler(extAxHiTaskInstService));
|
||||
configuration.addCustomJobHandler(new AsyncCountersignUserTaskJobHandler(extAxHiTaskInstService, extAxDynamicSignRecordService));
|
||||
configuration.addCustomJobHandler(new AsyncExtTaskInstJobHandler(extAxHiTaskInstService));
|
||||
configuration.addCustomJobHandler(new AsyncRejectTaskJobHandler(extAxHiTaskInstService));
|
||||
configuration.addCustomJobHandler(new AsyncTransferUserTaskJobHandler());
|
||||
@ -141,6 +144,7 @@ public class FlowableConfiguration {
|
||||
configuration.setFormFieldValidationEnabled(true);
|
||||
configuration.setFormFieldHandler(new CustomFormFieldHandler());
|
||||
configuration.setConfigurators(Lists.newArrayList(new CustomJobServiceConfiguration()));
|
||||
configuration.setInternalJobManager(new CustomDefaultInternalJobManager(configuration));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ import java.util.concurrent.TimeUnit;
|
||||
@Data
|
||||
@RefreshScope
|
||||
public class SupportRefreshProperties {
|
||||
|
||||
@Value("${workflow.apiLog.enable: false}")
|
||||
private Boolean apiLogEnable;
|
||||
|
||||
@ -108,4 +109,7 @@ public class SupportRefreshProperties {
|
||||
@Value("${workflow.ignoreMqAlterApplicationNames:}")
|
||||
private List<String> ignoreMqAlterApplicationNames;
|
||||
|
||||
@Value("${workflow.processLogHtmlUrl:https://taskflow-web.axzo.cn/#/document/log?processInstanceId=%s&personId=%s}")
|
||||
private String processLogHtmlUrl;
|
||||
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPIE
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY_OBJECT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY_SPECIFY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CONDITION_PERMISSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_PERMISSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_LEADER_RANGE_UNIT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_EXCLUDE_COOPERATE_TYPES;
|
||||
@ -68,6 +69,8 @@ public class ServiceTaskJsonConverter extends AbstractBpmnJsonConverter<ServiceT
|
||||
|
||||
// "表单权限设置"
|
||||
setFormFieldExtensionElement(node, serviceTask);
|
||||
// "条件权限设置"
|
||||
setConditionExtensionElement(node, serviceTask);
|
||||
return serviceTask;
|
||||
}
|
||||
|
||||
@ -399,6 +402,17 @@ public class ServiceTaskJsonConverter extends AbstractBpmnJsonConverter<ServiceT
|
||||
serviceTask.setImplementationType(IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
|
||||
}
|
||||
|
||||
private static void setConditionExtensionElement(BpmnJsonNode node, ServiceTask serviceTask) {
|
||||
if (Objects.isNull(node.getProperty())) {
|
||||
return;
|
||||
}
|
||||
ExtensionElement fieldElement = new ExtensionElement();
|
||||
fieldElement.setName(CONFIG_CONDITION_PERMISSION);
|
||||
fieldElement.setElementText(Objects.nonNull(node.getProperty().getConditionPermission()) ?
|
||||
JSON.toJSONString(node.getProperty().getConditionPermission()) : null);
|
||||
serviceTask.addExtensionElement(fieldElement);
|
||||
}
|
||||
|
||||
private static void setFormFieldExtensionElement(BpmnJsonNode node, ServiceTask serviceTask) {
|
||||
if (Objects.isNull(node.getProperty())) {
|
||||
return;
|
||||
|
||||
@ -45,12 +45,14 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_CURRENT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_HISTORY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CONDITION_PERMISSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_PERMISSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_LEADER_RANGE_UNIT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_EXCLUDE_COOPERATE_TYPES;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_EXCLUDE_IDENTITY_TYPES;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_FILTER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_RANGE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_ONLY_IN_PROJECT_ENABLE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_LIMIT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_ORG_LIMIT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_ROLE_LIMIT;
|
||||
@ -99,6 +101,8 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter<UserTask> {
|
||||
setApprovalExtensionElement(node, userTask);
|
||||
// "表单权限设置"
|
||||
setFormFieldExtensionElement(node, userTask);
|
||||
// "条件权限设置"
|
||||
setConditionExtensionElement(node, userTask);
|
||||
// "高级设置",包含按钮配置,自动过审配置
|
||||
setAdvancedExtensionElement(node, userTask);
|
||||
// "待办消息模板配置"
|
||||
@ -183,6 +187,14 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter<UserTask> {
|
||||
specialtyFilterEnableElement.addAttribute(specialtyFilterEnableAttribute);
|
||||
userTask.addExtensionElement(specialtyFilterEnableElement);
|
||||
|
||||
ExtensionElement onlyInProjectEnableElement = new ExtensionElement();
|
||||
onlyInProjectEnableElement.setName(CONFIG_ONLY_IN_PROJECT_ENABLE);
|
||||
ExtensionAttribute onlyInProjectEnableAttribute = new ExtensionAttribute();
|
||||
onlyInProjectEnableAttribute.setName(ELEMENT_ATTRIBUTE_CHECKED);
|
||||
onlyInProjectEnableAttribute.setValue(String.valueOf(Boolean.TRUE.equals(node.getProperty().getOnlyInProjectEnable())));
|
||||
onlyInProjectEnableElement.addAttribute(onlyInProjectEnableAttribute);
|
||||
userTask.addExtensionElement(onlyInProjectEnableElement);
|
||||
|
||||
//添加自动审批配置
|
||||
ExtensionElement autoApprovalExtensionElement = new ExtensionElement();
|
||||
ExtensionAttribute pendingMessageAttribute = new ExtensionAttribute();
|
||||
@ -191,6 +203,17 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter<UserTask> {
|
||||
userTask.addExtensionElement(autoApprovalExtensionElement);
|
||||
}
|
||||
|
||||
private static void setConditionExtensionElement(BpmnJsonNode node, UserTask userTask) {
|
||||
if (Objects.isNull(node.getProperty()) || CollectionUtils.isEmpty(node.getProperty().getConditionPermission())) {
|
||||
return;
|
||||
}
|
||||
ExtensionElement fieldElement = new ExtensionElement();
|
||||
fieldElement.setName(CONFIG_CONDITION_PERMISSION);
|
||||
fieldElement.setElementText(Objects.nonNull(node.getProperty().getConditionPermission()) ?
|
||||
JSON.toJSONString(node.getProperty().getConditionPermission()) : null);
|
||||
userTask.addExtensionElement(fieldElement);
|
||||
}
|
||||
|
||||
private static void setFormFieldExtensionElement(BpmnJsonNode node, UserTask userTask) {
|
||||
if (Objects.isNull(node.getProperty()) || CollectionUtils.isEmpty(node.getProperty().getFieldPermission())) {
|
||||
return;
|
||||
@ -686,7 +709,7 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter<UserTask> {
|
||||
* @param node
|
||||
* @param userTask
|
||||
*/
|
||||
private static void setExecutionListeners(BpmnJsonNode node, UserTask userTask) {
|
||||
public static void setExecutionListeners(BpmnJsonNode node, UserTask userTask) {
|
||||
|
||||
List<FlowableListener> executionListeners = new ArrayList<>();
|
||||
// 设置执行监听
|
||||
@ -725,7 +748,7 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter<UserTask> {
|
||||
*
|
||||
* @param userTask
|
||||
*/
|
||||
private static void setTaskListeners(UserTask userTask) {
|
||||
public static void setTaskListeners(UserTask userTask) {
|
||||
List<FlowableListener> taskListeners = new ArrayList<>();
|
||||
// 设置任务监听
|
||||
FlowableListener taskListener = new FlowableListener();
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package cn.axzo.workflow.core.engine.cfg;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.impl.cfg.DefaultInternalJobManager;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
|
||||
import org.flowable.job.api.Job;
|
||||
|
||||
/**
|
||||
* 为解决引擎底层定时任务的 NPE 问题
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-24 17:42
|
||||
*/
|
||||
@Slf4j
|
||||
public class CustomDefaultInternalJobManager extends DefaultInternalJobManager {
|
||||
public CustomDefaultInternalJobManager(ProcessEngineConfigurationImpl processEngineConfiguration) {
|
||||
super(processEngineConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleJobDeleteInternal(Job job) {
|
||||
ExecutionEntity executionEntity = getExecutionEntityManager().findById(job.getExecutionId());
|
||||
log.info("handleJobDeleteInternal job.eId:{}, job.piId:{} ", job.getExecutionId(), job.getProcessInstanceId());
|
||||
if (executionEntity == null) {
|
||||
log.warn("handleJobDeleteInternal executionEntity is null for job.eId:{}, job.piId:{} ", job.getExecutionId(), job.getProcessInstanceId());
|
||||
return;
|
||||
}
|
||||
super.handleJobDeleteInternal(job);
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@ package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessTaskResultEnum;
|
||||
import cn.axzo.workflow.common.model.dto.SignatureDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
|
||||
@ -28,6 +29,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -38,6 +40,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CLOSE_PROCESS_ASSIG
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.PENDING_TEMPLATE_VARIABLE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGNATURE_COLLECTION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
|
||||
@ -81,6 +84,7 @@ public class CustomApproveTaskCmd extends AbstractCommand<Void> implements Seria
|
||||
* 指定节点类型
|
||||
*/
|
||||
private List<BpmnFlowNodeType> nodeTypes;
|
||||
private Map<String, Object> variables;
|
||||
|
||||
@Override
|
||||
public String paramToJsonString() {
|
||||
@ -92,6 +96,7 @@ public class CustomApproveTaskCmd extends AbstractCommand<Void> implements Seria
|
||||
params.put("approver", JSON.toJSONString(approver));
|
||||
params.put("nextApprover", JSON.toJSONString(nextApprover));
|
||||
params.put("nodeTypes", JSON.toJSONString(nodeTypes));
|
||||
params.put("variables", JSON.toJSONString(variables));
|
||||
return JSON.toJSONString(params);
|
||||
}
|
||||
|
||||
@ -115,6 +120,7 @@ public class CustomApproveTaskCmd extends AbstractCommand<Void> implements Seria
|
||||
} else {
|
||||
this.operationDesc = "已同意";
|
||||
}
|
||||
this.variables = dto.getVariables();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -156,8 +162,22 @@ public class CustomApproveTaskCmd extends AbstractCommand<Void> implements Seria
|
||||
}
|
||||
task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus());
|
||||
|
||||
if (!CollectionUtils.isEmpty(variables)) {
|
||||
Map<String, Object> pendingVariables = runtimeService.getVariable(task.getProcessInstanceId(), PENDING_TEMPLATE_VARIABLE, Map.class);
|
||||
if (!CollectionUtils.isEmpty(pendingVariables)) {
|
||||
variables.forEach((k, v) -> {
|
||||
if (pendingVariables.containsKey(k)) {
|
||||
pendingVariables.put(k, v);
|
||||
}
|
||||
});
|
||||
}
|
||||
// 如果有待办模板变量,则更新待办模板变量
|
||||
variables.put(PENDING_TEMPLATE_VARIABLE, pendingVariables);
|
||||
// 更新流程内的变量
|
||||
runtimeService.setVariables(task.getProcessInstanceId(), variables);
|
||||
}
|
||||
// 记录电子签名的图片
|
||||
recordSignature(task, runtimeService);
|
||||
recordSignature(task, runtimeService, attachmentList, advice, approver);
|
||||
|
||||
resetApproverNode(task.getProcessInstanceId());
|
||||
|
||||
@ -185,7 +205,14 @@ public class CustomApproveTaskCmd extends AbstractCommand<Void> implements Seria
|
||||
approver.setNodeId(logs.get(0).getAssigneeFull().get(0).getNodeId());
|
||||
}
|
||||
|
||||
private void recordSignature(TaskEntity task, RuntimeService runtimeService) {
|
||||
public static void recordSignature(TaskEntity task,
|
||||
RuntimeService runtimeService,
|
||||
List<AttachmentDTO> attachmentList,
|
||||
String advice,
|
||||
BpmnTaskDelegateAssigner approver) {
|
||||
if (Objects.isNull(approver)) {
|
||||
return;
|
||||
}
|
||||
List<SignatureDTO> signatures = runtimeService.getVariable(task.getProcessInstanceId(), SIGNATURE_COLLECTION, List.class);
|
||||
if (Objects.isNull(signatures)) {
|
||||
signatures = new ArrayList<>();
|
||||
@ -196,13 +223,16 @@ public class CustomApproveTaskCmd extends AbstractCommand<Void> implements Seria
|
||||
.setActivityId(task.getTaskDefinitionKey())
|
||||
.setActivityName(task.getName())
|
||||
.setSignatures(new ArrayList<>()));
|
||||
ListUtils.emptyIfNull(attachmentList).stream()
|
||||
.filter(i -> Objects.equals(i.getType(), AttachmentTypeEnum.signature))
|
||||
.findFirst()
|
||||
.ifPresent(attachment -> dto.getSignatures().add(0,
|
||||
new SignatureDTO.SignDetail()
|
||||
.setSignature(attachment.getUrl())
|
||||
.setAdvice(advice)));
|
||||
|
||||
dto.getSignatures().add(0, new SignatureDTO.SignDetail()
|
||||
.setApproverName(approver.getAssignerName())
|
||||
.setSignature(ListUtils.emptyIfNull(attachmentList).stream()
|
||||
.filter(i -> Objects.equals(i.getType(), AttachmentTypeEnum.signature))
|
||||
.findFirst().orElse(new AttachmentDTO()).getUrl())
|
||||
.setAdvice(advice)
|
||||
.setResult(BpmnProcessTaskResultEnum.APPROVED.getDesc())
|
||||
.setOperationTime(new Date())
|
||||
);
|
||||
if (!any.isPresent()) {
|
||||
signatures.add(dto);
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.dto.SignatureDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditWithFormDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
@ -14,7 +12,6 @@ import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
|
||||
import cn.axzo.workflow.core.service.ExtAxBpmnFormRelationService;
|
||||
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.flowable.common.engine.impl.identity.Authentication;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
@ -34,12 +31,10 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -48,10 +43,10 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CLOSE_PROCESS_ASSIG
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGNATURE_COLLECTION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_SUBMIT_FORM_VARIABLE;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
|
||||
import static cn.axzo.workflow.core.engine.cmd.CustomApproveTaskCmd.recordSignature;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
|
||||
@ -97,6 +92,10 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand<Void> implemen
|
||||
* 表单数据
|
||||
*/
|
||||
private final Map<String, Object> formVariables;
|
||||
/**
|
||||
* 更新或新增的流程变量
|
||||
*/
|
||||
private final Map<String, Object> variables;
|
||||
|
||||
@Override
|
||||
public String paramToJsonString() {
|
||||
@ -109,6 +108,7 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand<Void> implemen
|
||||
params.put("nextApprover", JSON.toJSONString(nextApprover));
|
||||
params.put("nodeTypes", JSON.toJSONString(nodeTypes));
|
||||
params.put("formVariables", JSON.toJSONString(formVariables));
|
||||
params.put("variables", JSON.toJSONString(variables));
|
||||
return JSON.toJSONString(params);
|
||||
}
|
||||
|
||||
@ -133,6 +133,7 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand<Void> implemen
|
||||
} else {
|
||||
this.operationDesc = "已同意";
|
||||
}
|
||||
this.variables = dto.getVariables();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -174,9 +175,10 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand<Void> implemen
|
||||
nextApprover);
|
||||
}
|
||||
task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus());
|
||||
|
||||
// 更新流程实例变量
|
||||
runtimeService.setVariables(task.getProcessInstanceId(), variables);
|
||||
// 记录电子签名的图片
|
||||
recordSignature(task, runtimeService);
|
||||
recordSignature(task, runtimeService, attachmentList, advice, approver);
|
||||
|
||||
resetApproverNode(task.getProcessInstanceId());
|
||||
|
||||
@ -255,30 +257,4 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand<Void> implemen
|
||||
}
|
||||
}
|
||||
|
||||
private void recordSignature(TaskEntity task, RuntimeService runtimeService) {
|
||||
List<SignatureDTO> signatures = runtimeService.getVariable(task.getProcessInstanceId(), SIGNATURE_COLLECTION, List.class);
|
||||
if (Objects.isNull(signatures)) {
|
||||
signatures = new ArrayList<>();
|
||||
}
|
||||
Optional<SignatureDTO> any = signatures.stream()
|
||||
.filter(i -> Objects.equals(i.getActivityId(), task.getTaskDefinitionKey())).findAny();
|
||||
SignatureDTO dto = any.orElse(new SignatureDTO()
|
||||
.setActivityId(task.getTaskDefinitionKey())
|
||||
.setActivityName(task.getName())
|
||||
.setSignatures(new ArrayList<>()));
|
||||
ListUtils.emptyIfNull(attachmentList).stream()
|
||||
.filter(i -> Objects.equals(i.getType(), AttachmentTypeEnum.signature))
|
||||
.findFirst()
|
||||
.ifPresent(attachment -> dto.getSignatures().add(0,
|
||||
new SignatureDTO.SignDetail()
|
||||
.setSignature(attachment.getUrl())
|
||||
.setAdvice(advice)));
|
||||
if (!any.isPresent()) {
|
||||
signatures.add(dto);
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEmpty(signatures)) {
|
||||
runtimeService.setVariable(task.getProcessInstanceId(), SIGNATURE_COLLECTION, signatures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,22 +1,30 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.engine.cmd.helper.CustomBpmnModelHelper;
|
||||
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
|
||||
import cn.axzo.workflow.core.engine.model.AddComment;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord;
|
||||
import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService;
|
||||
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.api.TaskInfo;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
@ -29,17 +37,25 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.code.OtherRespCode.ASSIGNEE_NODE_ID_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BACK_ACTIVITY_FRAGMENT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_ASSIGNER_SHOW_NUMBER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_COUNT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FORWARD_ACTIVITY_FRAGMENT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
||||
import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCategoryVersion;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addMultiTask;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.completeVirtualTask;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVirtualTask;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.deleteMultiTasks;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.getDuplicatePendingTasks;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerCount;
|
||||
@ -63,11 +79,14 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
private final List<AttachmentDTO> attachmentList;
|
||||
private final List<BpmnTaskDelegateAssigner> targetTaskAssigneeList;
|
||||
private final ExtAxHiTaskInstService extAxHiTaskInstService;
|
||||
private final ExtAxDynamicSignRecordService extAxDynamicSignRecordService;
|
||||
|
||||
public CustomCountersignUserTaskCmd(BpmnCountersignTypeEnum countersignType, String originTaskId,
|
||||
BpmnTaskDelegateAssigner originTaskAssignee, String advice,
|
||||
List<AttachmentDTO> attachmentList,
|
||||
List<BpmnTaskDelegateAssigner> targetTaskAssigneeList, ExtAxHiTaskInstService extAxHiTaskInstService) {
|
||||
List<BpmnTaskDelegateAssigner> targetTaskAssigneeList,
|
||||
ExtAxHiTaskInstService extAxHiTaskInstService,
|
||||
ExtAxDynamicSignRecordService extAxDynamicSignRecordService) {
|
||||
this.countersignType = countersignType;
|
||||
this.originTaskId = originTaskId;
|
||||
this.originTaskAssignee = originTaskAssignee;
|
||||
@ -75,6 +94,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
this.attachmentList = attachmentList;
|
||||
this.targetTaskAssigneeList = targetTaskAssigneeList;
|
||||
this.extAxHiTaskInstService = extAxHiTaskInstService;
|
||||
this.extAxDynamicSignRecordService = extAxDynamicSignRecordService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -100,6 +120,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
TaskService taskService = processEngineConfiguration.getTaskService();
|
||||
TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(originTaskId).singleResult();
|
||||
|
||||
// 1.5.4 版本,要求审批人必须回传 nodeId
|
||||
validTargetAssigneeNodeId(task.getProcessDefinitionId());
|
||||
|
||||
validTask(historicTaskInstance, task, originTaskAssignee, null);
|
||||
@ -130,9 +151,11 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
switch (countersignType) {
|
||||
case FORWARD_COUNTERSIGN:
|
||||
// 加签的一种方式:前加签,具体定义由后续产品需求来定
|
||||
forwardAndBackCountSign(commandContext, task, valuTargetAssigneeList);
|
||||
break;
|
||||
case BACK_COUNTERSIGN:
|
||||
// 加签的另一种方式
|
||||
forwardAndBackCountSign(commandContext, task, valuTargetAssigneeList);
|
||||
break;
|
||||
default:
|
||||
// 共享签,不区分顺序
|
||||
@ -143,6 +166,148 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 前、后加签
|
||||
* <p>
|
||||
* 使用内存动态变更模型连接实现前加签功能
|
||||
*
|
||||
* @param commandContext
|
||||
* @param task
|
||||
* @param valuTargetAssigneeList
|
||||
*/
|
||||
private void forwardAndBackCountSign(CommandContext commandContext, TaskEntity task, List<BpmnTaskDelegateAssigner> valuTargetAssigneeList) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
|
||||
Process process = ProcessDefinitionUtil.getProcess(processInstance.getProcessDefinitionId());
|
||||
UserTask originalUserTask = (UserTask) process.getFlowElement(task.getTaskDefinitionKey());
|
||||
|
||||
// 获取当前实例前加签次数
|
||||
Long counterSignCount = runtimeService.getVariable(processInstance.getId(), COUNTERSIGN_COUNT, Long.class);
|
||||
if (Objects.isNull(counterSignCount)) {
|
||||
counterSignCount = 0L;
|
||||
} else {
|
||||
counterSignCount = counterSignCount + 1;
|
||||
}
|
||||
runtimeService.setVariable(processInstance.getId(), COUNTERSIGN_COUNT, counterSignCount);
|
||||
|
||||
BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR;
|
||||
|
||||
// 生成加签节点ID
|
||||
String newActivityId = originalUserTask.getId();
|
||||
switch (countersignType) {
|
||||
case FORWARD_COUNTERSIGN:
|
||||
newActivityId = processActivityId(newActivityId, FORWARD_ACTIVITY_FRAGMENT, counterSignCount);
|
||||
break;
|
||||
case BACK_COUNTERSIGN:
|
||||
newActivityId = processActivityId(newActivityId, BACK_ACTIVITY_FRAGMENT, counterSignCount);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 创建被加签节点
|
||||
UserTask newUserTask = CustomBpmnModelHelper.createUserTask(processEngineConfiguration, originalUserTask, newActivityId, nodeMode, valuTargetAssigneeList);
|
||||
// 加入模型
|
||||
process.addFlowElement(newUserTask);
|
||||
// 重新连接顺序流 (Sequence Flow)
|
||||
CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask, countersignType);
|
||||
|
||||
saveCounterSignRecord(valuTargetAssigneeList, processInstance, originalUserTask, newUserTask, nodeMode);
|
||||
|
||||
if (Objects.equals(FORWARD_COUNTERSIGN, countersignType)) {
|
||||
log.info("前加签任务处理完成,原任务ID:{},新任务ID:{}", task.getId(), newUserTask.getId());
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.moveActivityIdTo(task.getTaskDefinitionKey(), newUserTask.getId())
|
||||
.changeState();
|
||||
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 前后加签动作记录,用于 JVM 重启后的动态恢复
|
||||
*
|
||||
* @param valuTargetAssigneeList
|
||||
* @param processInstance
|
||||
* @param originalUserTask
|
||||
* @param newUserTask
|
||||
* @param nodeMode
|
||||
*/
|
||||
private void saveCounterSignRecord(List<BpmnTaskDelegateAssigner> valuTargetAssigneeList, ProcessInstance processInstance, UserTask originalUserTask, UserTask newUserTask, BpmnFlowNodeMode nodeMode) {
|
||||
ExtAxDynamicSignRecord entity = new ExtAxDynamicSignRecord();
|
||||
entity.setProcessInstanceId(processInstance.getProcessInstanceId());
|
||||
entity.setProcessDefinitionId(processInstance.getProcessDefinitionId());
|
||||
entity.setOriginalActivityId(originalUserTask.getId());
|
||||
entity.setTargetActivityId(newUserTask.getId());
|
||||
entity.setCounterSignType(countersignType.getType());
|
||||
entity.setTargetNodeMode(nodeMode.getType());
|
||||
entity.setAssignerList(valuTargetAssigneeList);
|
||||
extAxDynamicSignRecordService.saveOrUpdate(entity);
|
||||
}
|
||||
|
||||
// 提取公共处理方法
|
||||
private String processActivityId(String originalId, String fragment, long count) {
|
||||
if (originalId.contains(fragment)) {
|
||||
int fragmentIndex = originalId.indexOf(fragment);
|
||||
return originalId.substring(0, fragmentIndex) + fragment + count;
|
||||
}
|
||||
return originalId + fragment + count; // 不包含目标片段时,返回原字符串
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 后加签
|
||||
* <p>
|
||||
* 基于当前节点的后加签,内部实现主要依靠加减签的能力实现
|
||||
*
|
||||
* @param commandContext
|
||||
* @param historicTaskInstance
|
||||
* @param task
|
||||
* @param valuTargetAssigneeList
|
||||
*/
|
||||
@Deprecated
|
||||
private void backCountSign(CommandContext commandContext,
|
||||
HistoricTaskInstance historicTaskInstance,
|
||||
TaskEntity task,
|
||||
List<BpmnTaskDelegateAssigner> valuTargetAssigneeList) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
TaskService taskService = processEngineConfiguration.getTaskService();
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(historicTaskInstance.getProcessDefinitionId());
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
|
||||
if (flowElement instanceof UserTask) {
|
||||
UserTask userTask = (UserTask) flowElement;
|
||||
BpmnFlowNodeMode nodeMode = Objects.equals(userTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR;
|
||||
switch (nodeMode) {
|
||||
case AND:
|
||||
// 这里仅是加签,还需要再触发当前人的同意
|
||||
shareCountSign(commandContext, task, valuTargetAssigneeList);
|
||||
break;
|
||||
case OR:
|
||||
// 修改审批人快照
|
||||
List<BpmnTaskDelegateAssigner> originAssigners = runtimeService.getVariable(task.getProcessInstanceId(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), List.class);
|
||||
originAssigners.removeIf(e -> !Objects.equals(e.buildAssigneeId(), originTaskAssignee.buildAssigneeId()));
|
||||
originAssigners.addAll(valuTargetAssigneeList);
|
||||
runtimeService.setVariable(task.getProcessInstanceId(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), originAssigners);
|
||||
|
||||
// 后加签的人
|
||||
valuTargetAssigneeList.forEach(e -> addMultiTask(commandContext, task, e));
|
||||
|
||||
// 删除除当前审批人的task
|
||||
List<Task> currentTasks = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).taskDefinitionKey(task.getTaskDefinitionKey()).active().list();
|
||||
currentTasks.removeIf(e -> Objects.equals(e.getAssignee(), originTaskAssignee.buildAssigneeId()));
|
||||
deleteMultiTasks(commandContext, currentTasks);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 共享签
|
||||
*
|
||||
@ -167,7 +332,6 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
|
||||
private void resolveOriginTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService,
|
||||
TaskService taskService, TaskEntity task) {
|
||||
// 构建评论内容
|
||||
StringBuilder message = new StringBuilder("添加");
|
||||
int end = Math.min(targetTaskAssigneeList.size(), COUNTERSIGN_ASSIGNER_SHOW_NUMBER);
|
||||
//加签人员数量显示指定个数
|
||||
@ -181,6 +345,19 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
message.append("等");
|
||||
}
|
||||
message.append(targetTaskAssigneeList.size()).append("人进行审批");
|
||||
|
||||
switch (countersignType) {
|
||||
case FORWARD_COUNTERSIGN:
|
||||
message.append("(前加签)");
|
||||
break;
|
||||
case BACK_COUNTERSIGN:
|
||||
message.append("(后加签)");
|
||||
break;
|
||||
default:
|
||||
message.append("(并加签)");
|
||||
break;
|
||||
}
|
||||
|
||||
Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(),
|
||||
task.getTaskDefinitionKey(), advice, originTaskAssignee, COUNTERSIGN.getStatus(), new AddComment(message.toString()));
|
||||
batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList, originTaskAssignee);
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo;
|
||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 获取指定流程节点配置的条件权限信息
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-29 18:02
|
||||
*/
|
||||
public class CustomGetConditionPermissionsCmd extends AbstractCommand<List<ConditionPermissionMetaInfo>> {
|
||||
private final String processInstanceId;
|
||||
|
||||
public CustomGetConditionPermissionsCmd(String processInstanceId) {
|
||||
this.processInstanceId = processInstanceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String paramToJsonString() {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("processInstanceId", processInstanceId);
|
||||
return JSON.toJSONString(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConditionPermissionMetaInfo> execute(CommandContext commandContext) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
if (Objects.isNull(processInstance)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
TaskService taskService = processEngineConfiguration.getTaskService();
|
||||
List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list();
|
||||
if (CollectionUtils.isEmpty(tasks)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processInstance.getProcessDefinitionId());
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(tasks.get(0).getTaskDefinitionKey());
|
||||
List<ConditionPermissionMetaInfo> conditions = BpmnMetaParserHelper.getConditionPermissionConf(flowElement).orElse(Collections.emptyList());
|
||||
List<String> conditionCodes = conditions.stream().map(ConditionPermissionMetaInfo::getConditionCode).collect(Collectors.toList());
|
||||
Map<String, Object> variables = runtimeService.getVariables(processInstanceId, conditionCodes);
|
||||
conditions.forEach(e -> e.setValue(variables.getOrDefault(e.getConditionCode(), null)));
|
||||
return conditions;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.form.api.FormEngineConfigurationApi;
|
||||
import org.flowable.form.api.FormInfo;
|
||||
import org.flowable.form.api.FormInstance;
|
||||
import org.flowable.form.api.FormRepositoryService;
|
||||
import org.flowable.form.api.FormService;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通过审批实例 ID 获取对应的表单定义实体的自定义命令
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-11-20 10:18
|
||||
*/
|
||||
public class CustomGetFormModelByProcessInstanceIdCmd extends AbstractCommand<FormInfo> implements Serializable {
|
||||
private final String processInstanceId;
|
||||
|
||||
public CustomGetFormModelByProcessInstanceIdCmd(String processInstanceId) {
|
||||
this.processInstanceId = processInstanceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String paramToJsonString() {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("processInstanceId", processInstanceId);
|
||||
return JSON.toJSONString(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FormInfo executeInternal(CommandContext commandContext) {
|
||||
FormEngineConfigurationApi formEngineConfiguration = CommandContextUtil.getFormEngineConfiguration(commandContext);
|
||||
FormService formService = formEngineConfiguration.getFormService();
|
||||
|
||||
List<FormInstance> list = formService.createFormInstanceQuery().processInstanceId(processInstanceId).orderBySubmittedDate().desc().list();
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String formDefinitionId = list.get(0).getFormDefinitionId();
|
||||
FormRepositoryService formRepositoryService = formEngineConfiguration.getFormRepositoryService();
|
||||
return formRepositoryService.getFormModelById(formDefinitionId);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.dto.SignatureDTO;
|
||||
import cn.axzo.workflow.core.common.utils.SpringContextUtils;
|
||||
import cn.axzo.workflow.core.service.CategoryService;
|
||||
@ -22,10 +23,13 @@ import java.util.Objects;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_MODEL_CATEGORY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGNATURE_COLLECTION;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_BELONG_TENANT_ID;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_DEFINITION_KEY;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_END_TIME;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INSTANCE_ID;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_NAME;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_RESULT;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_START_TIME;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
||||
|
||||
@ -63,9 +67,15 @@ public class CustomGetProcessInstanceVariablesCmd extends AbstractCommand<Map<St
|
||||
HistoryService historyService = processEngineConfiguration.getHistoryService();
|
||||
HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery()
|
||||
.processInstanceId(processInstanceId).includeProcessVariables().singleResult();
|
||||
if (Objects.isNull(instance)) {
|
||||
return variables;
|
||||
}
|
||||
variables.put(PRINT_VAR_PROCESS_NAME, instance.getName());
|
||||
variables.put(PRINT_VAR_PROCESS_BELONG_TENANT_ID, instance.getTenantId());
|
||||
// 添加流程开始时间
|
||||
variables.put(PRINT_VAR_PROCESS_START_TIME, sdf.format(instance.getStartTime()));
|
||||
variables.put(PRINT_VAR_PROCESS_END_TIME, Objects.nonNull(instance.getEndTime()) ? sdf.format(instance.getEndTime()) : null);
|
||||
variables.put(PRINT_VAR_PROCESS_RESULT, BpmnProcessInstanceResultEnum.fromValue(instance.getBusinessStatus()));
|
||||
// 添加流程业务 ID
|
||||
addProcessDefinitionKey(variables, instance);
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.HistoryService;
|
||||
@ -27,6 +28,8 @@ import org.flowable.form.api.FormService;
|
||||
import org.flowable.form.model.FormContainer;
|
||||
import org.flowable.form.model.FormField;
|
||||
import org.flowable.form.model.FormFieldTypes;
|
||||
import org.flowable.form.model.Option;
|
||||
import org.flowable.form.model.OptionFormField;
|
||||
import org.flowable.form.model.SimpleFormModel;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@ -42,6 +45,8 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.code.FormInstanceRespCode.FORM_DATA_PARSE_ERROR_BY_CHECKBOX;
|
||||
import static cn.axzo.workflow.common.code.FormInstanceRespCode.FORM_DATA_PARSE_ERROR_BY_RADIO;
|
||||
import static cn.axzo.workflow.common.code.FormModelRespCode.FORM_MODEL_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_MODEL_CATEGORY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||
@ -75,7 +80,7 @@ public class CustomGetProcessInstanceVariablesToObjectCmd extends AbstractComman
|
||||
|
||||
private final String processInstanceId;
|
||||
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
|
||||
private static final List<String> SUPPORTED_FORM_TYPES = Lists.newArrayList("input", "date", "textarea", "image", "contacts", "amount", "decimal");
|
||||
private static final List<String> SUPPORTED_FORM_TYPES = Lists.newArrayList("input", "date", "textarea", "image", "contacts", "amount", "decimal", "checkbox", "radio");
|
||||
|
||||
public CustomGetProcessInstanceVariablesToObjectCmd(String processInstanceId) {
|
||||
this.processInstanceId = processInstanceId;
|
||||
@ -219,6 +224,39 @@ public class CustomGetProcessInstanceVariablesToObjectCmd extends AbstractComman
|
||||
.type(convert(field.getType()))
|
||||
.build());
|
||||
}
|
||||
} else if (Objects.equals(field.getType(), "checkbox")) {
|
||||
if (field instanceof OptionFormField) {
|
||||
OptionFormField optionField = (OptionFormField) field;
|
||||
if (StringUtils.hasText(fieldValue.toString())
|
||||
&& fieldValue.toString().startsWith("[")
|
||||
&& fieldValue.toString().endsWith("]")) {
|
||||
List<String> selectedOptions = JSON.parseArray((String) fieldValue, String.class);
|
||||
List<String> optionNames = ListUtils.emptyIfNull(optionField.getOptions()).stream().filter(i -> selectedOptions.contains(i.getId())).map(Option::getName).collect(Collectors.toList());
|
||||
variables.add(VariableObjectDTO.builder()
|
||||
.key(field.getId())
|
||||
.desc(field.getName())
|
||||
.value(StringUtils.collectionToDelimitedString(optionNames, ";"))
|
||||
.type(convert(field.getType()))
|
||||
.build());
|
||||
}
|
||||
} else {
|
||||
throw new WorkflowEngineException(FORM_DATA_PARSE_ERROR_BY_CHECKBOX);
|
||||
}
|
||||
} else if (Objects.equals(field.getType(), "radio")) {
|
||||
if (field instanceof OptionFormField) {
|
||||
OptionFormField optionField = (OptionFormField) field;
|
||||
if (StringUtils.hasText(fieldValue.toString())) {
|
||||
List<String> optionNames = ListUtils.emptyIfNull(optionField.getOptions()).stream().filter(i -> Objects.equals(fieldValue, i.getId())).map(Option::getName).collect(Collectors.toList());
|
||||
variables.add(VariableObjectDTO.builder()
|
||||
.key(field.getId())
|
||||
.desc(field.getName())
|
||||
.value(StringUtils.collectionToDelimitedString(optionNames, ";"))
|
||||
.type(convert(field.getType()))
|
||||
.build());
|
||||
}
|
||||
} else {
|
||||
throw new WorkflowEngineException(FORM_DATA_PARSE_ERROR_BY_RADIO);
|
||||
}
|
||||
} else {
|
||||
variables.add(VariableObjectDTO.builder()
|
||||
.key(field.getId())
|
||||
@ -234,6 +272,7 @@ public class CustomGetProcessInstanceVariablesToObjectCmd extends AbstractComman
|
||||
}
|
||||
|
||||
private void addSignature(List<VariableObjectDTO> variables, List<SignatureDTO> signatures) {
|
||||
log.info("addSignature:{}", JSON.toJSONString(signatures));
|
||||
if (CollectionUtils.isEmpty(signatures)) {
|
||||
return;
|
||||
}
|
||||
@ -272,15 +311,10 @@ public class CustomGetProcessInstanceVariablesToObjectCmd extends AbstractComman
|
||||
groupVariables.forEach(group -> {
|
||||
if (!CollectionUtils.isEmpty(group.getVars())) {
|
||||
group.getVars().forEach(variable -> {
|
||||
Object value = bizVariables.getOrDefault(variable.getCode(), null);
|
||||
if (Objects.isNull(value)) {
|
||||
// 目前为了减少 wps 替换耗时,所以将没有值的变量,直接踢出
|
||||
return;
|
||||
}
|
||||
variables.add(VariableObjectDTO.builder()
|
||||
.key(variable.getCode())
|
||||
.desc(group.getGroupName() + variable.getName())
|
||||
.value(value)
|
||||
.value(bizVariables.getOrDefault(variable.getCode(), null))
|
||||
.type(convert(variable.getType()))
|
||||
.build());
|
||||
});
|
||||
@ -310,6 +344,8 @@ public class CustomGetProcessInstanceVariablesToObjectCmd extends AbstractComman
|
||||
case "amount":
|
||||
case "contacts":
|
||||
case "decimal":
|
||||
case "checkbox":
|
||||
case "radio":
|
||||
return VariableObjectDTO.Type.text;
|
||||
case "image":
|
||||
return VariableObjectDTO.Type.img;
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 覆写指定流程中的变量
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-02-08 10:14
|
||||
*/
|
||||
@Slf4j
|
||||
public class CustomOverrideProcessVariablesCmd extends AbstractCommand<Void> implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final String processInstanceId;
|
||||
private final Map<String, Object> variables;
|
||||
|
||||
public CustomOverrideProcessVariablesCmd(String processInstanceId, Map<String, Object> variables) {
|
||||
this.processInstanceId = processInstanceId;
|
||||
this.variables = variables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String paramToJsonString() {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("processInstanceId", processInstanceId);
|
||||
params.put("formVariables", variables);
|
||||
return JSON.toJSONString(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void executeInternal(CommandContext commandContext) {
|
||||
if (CollectionUtils.isEmpty(variables)) {
|
||||
return null;
|
||||
}
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
if (Objects.nonNull(processInstance)) {
|
||||
throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
runtimeService.setVariables(processInstanceId, variables);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,220 @@
|
||||
package cn.axzo.workflow.core.engine.cmd.helper;
|
||||
|
||||
import cn.axzo.workflow.common.enums.ApprovalMethodEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.ExtensionAttribute;
|
||||
import org.flowable.bpmn.model.ExtensionElement;
|
||||
import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.SequenceFlow;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
|
||||
import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
|
||||
import org.flowable.engine.impl.bpmn.parser.factory.ActivityBehaviorFactory;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.axzo.workflow.common.code.ConvertorRespCode.CREATE_BPMN_PRE_SIGN_ERROR;
|
||||
import static cn.axzo.workflow.common.code.ConvertorRespCode.CREATE_BPMN_USER_TASK_ERROR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVAL_METHOD;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_EMPTY_HANDLE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_SPECIFY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NODE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_DESC;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_VALUE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.OR_SIGN_EXPRESSION_ONLY_ONE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SEQUENCE_FLOW_ID;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnJsonConverterUtil.id;
|
||||
import static cn.axzo.workflow.core.converter.json.UserTaskJsonConverter.setExecutionListeners;
|
||||
import static cn.axzo.workflow.core.converter.json.UserTaskJsonConverter.setTaskListeners;
|
||||
|
||||
/**
|
||||
* 动态操作 BPMN 定义内容的帮助类
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-15 17:05
|
||||
*/
|
||||
@Slf4j
|
||||
public class CustomBpmnModelHelper {
|
||||
|
||||
private CustomBpmnModelHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 BPMN 中的 UserTask
|
||||
*
|
||||
* @param processEngineConfiguration
|
||||
* @param originalUserTask
|
||||
* @param nodeMode
|
||||
*/
|
||||
public static UserTask createUserTask(ProcessEngineConfigurationImpl processEngineConfiguration, UserTask originalUserTask, String customActivityId, BpmnFlowNodeMode nodeMode, List<BpmnTaskDelegateAssigner> assigners) {
|
||||
UserTask newUserTask = new UserTask();
|
||||
if (StringUtils.hasText(customActivityId)) {
|
||||
newUserTask.setId(customActivityId);
|
||||
} else {
|
||||
newUserTask.setId(originalUserTask.getId());
|
||||
}
|
||||
newUserTask.setName(originalUserTask.getName());
|
||||
newUserTask.setDocumentation("由" + originalUserTask.getId() + "节点加签生成");
|
||||
|
||||
MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics();
|
||||
loopCharacteristics.setInputDataItem(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + newUserTask.getId());
|
||||
loopCharacteristics.setElementVariable("assigneeName");
|
||||
newUserTask.setLoopCharacteristics(loopCharacteristics);
|
||||
newUserTask.setAssignee("${assigneeName}");
|
||||
|
||||
switch (nodeMode) {
|
||||
case AND:
|
||||
loopCharacteristics.setSequential(false);
|
||||
loopCharacteristics.setCompletionCondition(AND_SIGN_EXPRESSION);
|
||||
break;
|
||||
case OR:
|
||||
loopCharacteristics.setSequential(false);
|
||||
loopCharacteristics.setCompletionCondition(OR_SIGN_EXPRESSION_ONLY_ONE);
|
||||
break;
|
||||
case SEQUENCE:
|
||||
loopCharacteristics.setSequential(true);
|
||||
loopCharacteristics.setCompletionCondition(AND_SIGN_EXPRESSION);
|
||||
break;
|
||||
default:
|
||||
throw new WorkflowEngineException(CREATE_BPMN_USER_TASK_ERROR, nodeMode.getType());
|
||||
}
|
||||
|
||||
setTaskListeners(newUserTask);
|
||||
setExecutionListeners(new BpmnJsonNode(), newUserTask);
|
||||
|
||||
ExtensionElement approvalMethodElement = new ExtensionElement();
|
||||
approvalMethodElement.setName(CONFIG_APPROVAL_METHOD);
|
||||
|
||||
ExtensionAttribute approvalMethodValueAttribute = new ExtensionAttribute();
|
||||
approvalMethodValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
|
||||
approvalMethodValueAttribute.setValue(ApprovalMethodEnum.human.getType());
|
||||
approvalMethodElement.addAttribute(approvalMethodValueAttribute);
|
||||
|
||||
ExtensionAttribute approvalMethodDescAttribute = new ExtensionAttribute();
|
||||
approvalMethodDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
|
||||
approvalMethodDescAttribute.setValue("审批方式");
|
||||
approvalMethodElement.addAttribute(approvalMethodDescAttribute);
|
||||
newUserTask.addExtensionElement(approvalMethodElement);
|
||||
|
||||
ExtensionElement approverSpecifyElement = new ExtensionElement();
|
||||
approverSpecifyElement.setName(CONFIG_APPROVER_SPECIFY);
|
||||
ExtensionAttribute approverSpecifyValueAttribute = new ExtensionAttribute();
|
||||
approverSpecifyValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
|
||||
approverSpecifyValueAttribute.setValue(ApproverSpecifyEnum.fixedPerson.getType());
|
||||
approverSpecifyElement.addAttribute(approverSpecifyValueAttribute);
|
||||
ExtensionAttribute approverSpecifyDescAttribute = new ExtensionAttribute();
|
||||
approverSpecifyDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
|
||||
approverSpecifyDescAttribute.setValue("审批人指定");
|
||||
approverSpecifyElement.addAttribute(approverSpecifyDescAttribute);
|
||||
approverSpecifyElement.setElementText(JSON.toJSONString(assigners));
|
||||
newUserTask.addExtensionElement(approverSpecifyElement);
|
||||
|
||||
ExtensionElement nodeTypeElement = new ExtensionElement();
|
||||
nodeTypeElement.setName(CONFIG_NODE_TYPE);
|
||||
nodeTypeElement.setElementText(BpmnFlowNodeType.NODE_TASK.getType());
|
||||
newUserTask.addExtensionElement(nodeTypeElement);
|
||||
|
||||
// 追加设置审批人为空的配置,因为查找审批人模式是固定人员,会执行退场、离职校验,导致最终审批人可能为空
|
||||
// 审批人为空时
|
||||
ExtensionElement approverEmptyHandleTypeElement = new ExtensionElement();
|
||||
approverEmptyHandleTypeElement.setName(CONFIG_APPROVER_EMPTY_HANDLE_TYPE);
|
||||
ExtensionAttribute approverEmptyHandleTypeValueAttribute = new ExtensionAttribute();
|
||||
approverEmptyHandleTypeValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
|
||||
approverEmptyHandleTypeValueAttribute.setValue(ApproverEmptyHandleTypeEnum.autoPassed.getType());
|
||||
approverEmptyHandleTypeElement.setElementText("[]");
|
||||
approverEmptyHandleTypeElement.addAttribute(approverEmptyHandleTypeValueAttribute);
|
||||
|
||||
ExtensionAttribute approverEmptyHandleTypeDescAttribute = new ExtensionAttribute();
|
||||
approverEmptyHandleTypeDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
|
||||
approverEmptyHandleTypeDescAttribute.setValue("审批人为空时");
|
||||
approverEmptyHandleTypeElement.addAttribute(approverEmptyHandleTypeDescAttribute);
|
||||
newUserTask.addExtensionElement(approverEmptyHandleTypeElement);
|
||||
|
||||
ActivityBehaviorFactory activityBehaviorFactory = processEngineConfiguration.getActivityBehaviorFactory();
|
||||
UserTaskActivityBehavior userTaskActivityBehavior = activityBehaviorFactory.createUserTaskActivityBehavior(newUserTask);
|
||||
ParallelMultiInstanceBehavior behavior = activityBehaviorFactory.createParallelMultiInstanceBehavior(newUserTask, userTaskActivityBehavior);
|
||||
|
||||
behavior.setCollectionVariable(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + newUserTask.getId());
|
||||
behavior.setCollectionElementVariable("assigneeName");
|
||||
behavior.setCompletionCondition(loopCharacteristics.getCompletionCondition());
|
||||
newUserTask.setBehavior(behavior);
|
||||
return newUserTask;
|
||||
}
|
||||
|
||||
public static void rewireSequenceFlows(Process process, UserTask originalUserTask, UserTask targetUserTask, BpmnCountersignTypeEnum countersignType) {
|
||||
switch (countersignType) {
|
||||
case FORWARD_COUNTERSIGN:
|
||||
// 1. 找到所有指向原始节点的输入流
|
||||
List<SequenceFlow> incomingFlows = originalUserTask.getIncomingFlows();
|
||||
if (incomingFlows.isEmpty()) {
|
||||
throw new WorkflowEngineException(CREATE_BPMN_PRE_SIGN_ERROR, "节点 " + originalUserTask.getId() + " 没有输入流,无法进行前加签");
|
||||
}
|
||||
|
||||
// 2. 将这些输入流的目标从 originalUserTask 修改为 targetUserTask
|
||||
for (SequenceFlow incomingFlow : incomingFlows) {
|
||||
incomingFlow.setTargetRef(targetUserTask.getId());
|
||||
// 如果需要,也可以更新FlowElement中的引用,但通常改TargetRef即可
|
||||
}
|
||||
targetUserTask.setIncomingFlows(incomingFlows);
|
||||
|
||||
// 3. 创建一个新的顺序流,从 targetUserTask 指向 originalUserTask
|
||||
SequenceFlow newSequenceFlow = new SequenceFlow();
|
||||
newSequenceFlow.setId(id(SEQUENCE_FLOW_ID + "_ForwardSign"));
|
||||
newSequenceFlow.setSourceRef(targetUserTask.getId());
|
||||
newSequenceFlow.setSourceFlowElement(targetUserTask);
|
||||
newSequenceFlow.setTargetRef(originalUserTask.getId());
|
||||
newSequenceFlow.setTargetFlowElement(originalUserTask);
|
||||
|
||||
targetUserTask.setOutgoingFlows(Collections.singletonList(newSequenceFlow));
|
||||
process.addFlowElement(newSequenceFlow);
|
||||
|
||||
originalUserTask.setIncomingFlows(Collections.singletonList(newSequenceFlow));
|
||||
break;
|
||||
case BACK_COUNTERSIGN:
|
||||
// 1. 找到所有指向原始节点的输出流
|
||||
List<SequenceFlow> outgoingFlows = originalUserTask.getOutgoingFlows();
|
||||
if (outgoingFlows.isEmpty()) {
|
||||
throw new WorkflowEngineException(CREATE_BPMN_PRE_SIGN_ERROR, "节点 " + originalUserTask.getId() + " 没有输出流,无法进行后加签");
|
||||
}
|
||||
|
||||
// 2. 将这些输出流的源从 originalUserTask 修改为 targetUserTask
|
||||
for (SequenceFlow outgoingFlow : outgoingFlows) {
|
||||
outgoingFlow.setSourceRef(targetUserTask.getId());
|
||||
// 如果需要,也可以更新FlowElement中的引用,但通常改SourceRef即可
|
||||
}
|
||||
targetUserTask.setOutgoingFlows(outgoingFlows);
|
||||
|
||||
// 3. 创建一个新的顺序流,从 originalUserTask 指向 targetUserTask
|
||||
SequenceFlow backSequenceFlow = new SequenceFlow();
|
||||
backSequenceFlow.setId(id(SEQUENCE_FLOW_ID + "_BackSign"));
|
||||
backSequenceFlow.setSourceRef(originalUserTask.getId());
|
||||
backSequenceFlow.setSourceFlowElement(originalUserTask);
|
||||
backSequenceFlow.setTargetRef(targetUserTask.getId());
|
||||
backSequenceFlow.setTargetFlowElement(targetUserTask);
|
||||
|
||||
originalUserTask.setOutgoingFlows(Collections.singletonList(backSequenceFlow));
|
||||
process.addFlowElement(backSequenceFlow);
|
||||
|
||||
targetUserTask.setIncomingFlows(Collections.singletonList(backSequenceFlow));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,6 +78,10 @@ import static org.flowable.task.api.Task.DEFAULT_PRIORITY;
|
||||
@Slf4j
|
||||
public class CustomTaskHelper {
|
||||
|
||||
private CustomTaskHelper() {
|
||||
|
||||
}
|
||||
|
||||
public static void addMultiTask(CommandContext commandContext, TaskEntity originTask,
|
||||
BpmnTaskDelegateAssigner newTaskAssignee) {
|
||||
if (Objects.isNull(originTask)) {
|
||||
@ -225,7 +229,7 @@ public class CustomTaskHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验人员数量是否超过限制
|
||||
* 校验人员数量是否超过60个人的限制
|
||||
*
|
||||
* @param runtimeService
|
||||
* @param taskEntity
|
||||
@ -360,8 +364,8 @@ public class CustomTaskHelper {
|
||||
*/
|
||||
public static TaskEntity createVirtualTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService
|
||||
, String processInstanceId, String nodeName, String taskDefinitionKey, String advice,
|
||||
BpmnTaskDelegateAssigner assigner,
|
||||
String extTaskInstStatus, AddComment addComment) {
|
||||
BpmnTaskDelegateAssigner assigner,
|
||||
String extTaskInstStatus, AddComment addComment) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
HistoryService historyService = processEngineConfiguration.getHistoryService();
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package cn.axzo.workflow.core.engine.job;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomCancelProcessInstanceCmd;
|
||||
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
|
||||
@ -34,8 +33,8 @@ public class AsyncCancelProcessInstanceJobHandler extends AbstractExecuteWithLoc
|
||||
log.info("AsyncCancelProcessInstanceHandler executing...,jobInfo:{}", JSONUtil.toJsonStr(job));
|
||||
log(job);
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
BpmnProcessInstanceCancelDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnProcessInstanceCancelDTO.class);
|
||||
processEngineConfiguration.getCommandExecutor().execute(new CustomCancelProcessInstanceCmd((SuperBpmnProcessInstanceCancelDTO) dto, extAxHiTaskInstService));
|
||||
SuperBpmnProcessInstanceCancelDTO dto = JSONUtil.toBean(job.getCustomValues(), SuperBpmnProcessInstanceCancelDTO.class);
|
||||
processEngineConfiguration.getCommandExecutor().execute(new CustomCancelProcessInstanceCmd(dto, extAxHiTaskInstService));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.job;
|
||||
import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomCountersignUserTaskCmd;
|
||||
import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService;
|
||||
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -19,9 +20,12 @@ public class AsyncCountersignUserTaskJobHandler extends AbstractJobHandler imple
|
||||
public static final String TYPE = "async-countersign-task";
|
||||
|
||||
private final ExtAxHiTaskInstService extAxHiTaskInstService;
|
||||
private final ExtAxDynamicSignRecordService extAxDynamicSignRecordService;
|
||||
|
||||
public AsyncCountersignUserTaskJobHandler(ExtAxHiTaskInstService extAxHiTaskInstService) {
|
||||
public AsyncCountersignUserTaskJobHandler(ExtAxHiTaskInstService extAxHiTaskInstService,
|
||||
ExtAxDynamicSignRecordService extAxDynamicSignRecordService) {
|
||||
this.extAxHiTaskInstService = extAxHiTaskInstService;
|
||||
this.extAxDynamicSignRecordService = extAxDynamicSignRecordService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -42,6 +46,7 @@ public class AsyncCountersignUserTaskJobHandler extends AbstractJobHandler imple
|
||||
dto.getAdvice(),
|
||||
dto.getAttachmentList(),
|
||||
dto.getTargetAssignerList(),
|
||||
extAxHiTaskInstService));
|
||||
extAxHiTaskInstService,
|
||||
extAxDynamicSignRecordService));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,16 @@
|
||||
package cn.axzo.workflow.core.listener;
|
||||
|
||||
import cn.axzo.workflow.common.constant.BpmnConstants;
|
||||
import cn.axzo.workflow.core.common.context.OperationContext;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC;
|
||||
|
||||
/**
|
||||
@ -43,4 +49,30 @@ public abstract class AbstractBpmnEventListener<T extends OperationContext> impl
|
||||
}
|
||||
return processDefinitionId.split(":")[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一些业务不需要关心的变量
|
||||
*
|
||||
* @param originVariables
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, Object> removeBpmnConstantsVariables(Map<String, Object> originVariables) {
|
||||
if (originVariables == null) return new HashMap<>();
|
||||
|
||||
// 定义需要移除的前缀列表
|
||||
List<String> prefixesToRemove = Arrays.asList(
|
||||
BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO,
|
||||
BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT,
|
||||
BpmnConstants.TASK_COMPLETE_OPERATION_TYPE,
|
||||
BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO
|
||||
);
|
||||
|
||||
return originVariables.entrySet().stream()
|
||||
.filter(entry -> entry.getKey() != null)
|
||||
// 核心修改:检查 key 是否以任一前缀开头
|
||||
.filter(entry -> prefixesToRemove.stream()
|
||||
.noneMatch(prefix -> entry.getKey().startsWith(prefix)))
|
||||
.collect(HashMap::new, (m, e) -> m.put(e.getKey(), e.getValue()), HashMap::putAll);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -84,4 +84,9 @@ public class ExtAxDict extends BaseEntity<ExtAxDict> {
|
||||
* 版本号
|
||||
*/
|
||||
private Integer version;
|
||||
|
||||
/**
|
||||
* 自定替换未设置的变量为空串
|
||||
*/
|
||||
private Boolean autoReplaceVariables;
|
||||
}
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
package cn.axzo.workflow.core.repository.entity;
|
||||
|
||||
import cn.axzo.framework.data.mybatisplus.model.BaseEntity;
|
||||
import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.conf.handler.ListAssigneeTypeHandler;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 扩展动态前后加签记录,用于应用重启后的模型内容恢复
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-17 18:23
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName(value = "ext_ax_dynamic_sign_record", autoResultMap = true)
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class ExtAxDynamicSignRecord extends BaseEntity<ExtAxDynamicSignRecord> {
|
||||
/**
|
||||
* 流程实例 ID
|
||||
*/
|
||||
private String processInstanceId;
|
||||
/**
|
||||
* 流程实例对应的流程定义 ID
|
||||
*/
|
||||
private String processDefinitionId;
|
||||
/**
|
||||
* 加签原节点
|
||||
*/
|
||||
private String originalActivityId;
|
||||
/**
|
||||
* 加签目标节点
|
||||
*/
|
||||
private String targetActivityId;
|
||||
/**
|
||||
* 加签类型,前加签/后加签
|
||||
* {@link BpmnCountersignTypeEnum}
|
||||
*/
|
||||
private String counterSignType;
|
||||
/**
|
||||
* 目标节点的审批方式(会签、或签、顺序签)
|
||||
*/
|
||||
private String targetNodeMode;
|
||||
/**
|
||||
* 被加签的审批人
|
||||
*/
|
||||
@TableField(value = "assigner_list", typeHandler = ListAssigneeTypeHandler.class)
|
||||
private List<BpmnTaskDelegateAssigner> assignerList;
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package cn.axzo.workflow.core.repository.mapper;
|
||||
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 动态前后加签记录 Mapper
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-17 18:28
|
||||
*/
|
||||
@Mapper
|
||||
public interface ExtAxDynamicSignRecordMapper extends BaseMapperX<ExtAxDynamicSignRecord> {
|
||||
}
|
||||
@ -1,9 +1,13 @@
|
||||
package cn.axzo.workflow.core.repository.mapper;
|
||||
|
||||
import cn.axzo.workflow.core.conf.handler.ListAssigneeTypeHandler;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Result;
|
||||
import org.apache.ibatis.annotations.Results;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
@Mapper
|
||||
public interface ExtAxProcessLogMapper extends BaseMapperX<ExtAxProcessLog> {
|
||||
@ -13,5 +17,8 @@ public interface ExtAxProcessLogMapper extends BaseMapperX<ExtAxProcessLog> {
|
||||
|
||||
|
||||
@Select("select * from ext_ax_process_log WHERE process_instance_id = #{processInstanceId} and task_id = #{taskId}")
|
||||
@Results({
|
||||
@Result(column = "assignee_full", property = "assigneeFull", jdbcType = JdbcType.ARRAY, typeHandler = ListAssigneeTypeHandler.class)
|
||||
})
|
||||
ExtAxProcessLog findByProcessIdAndTaskIdWithDeleted(String processInstanceId, String taskId);
|
||||
}
|
||||
|
||||
@ -10,10 +10,12 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCre
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceVariablesUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanceSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ProcessDocQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskButtonSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo;
|
||||
import cn.axzo.workflow.common.model.request.form.instance.FormVariablesUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO;
|
||||
@ -211,4 +213,8 @@ public interface BpmnProcessInstanceService {
|
||||
boolean hasPrintTemplate(String processInstanceId, String processDefinitionId);
|
||||
|
||||
List<DocPendingVO> processInstanceSelectDocs(ProcessDocQueryDTO dto);
|
||||
|
||||
void overrideProcessVariables(BpmnProcessInstanceVariablesUpdateDTO dto);
|
||||
|
||||
List<ConditionPermissionMetaInfo> getConditions(String processInstanceId);
|
||||
}
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
package cn.axzo.workflow.core.service;
|
||||
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* 动态前后加签记录服务接口
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-17 18:30
|
||||
*/
|
||||
public interface ExtAxDynamicSignRecordService extends IService<ExtAxDynamicSignRecord> {
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.workflow.core.service;
|
||||
|
||||
import cn.axzo.workflow.common.model.dto.CustomDocDTO;
|
||||
import cn.axzo.workflow.common.model.dto.SimpleDocDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverReadStatusDTO;
|
||||
@ -18,5 +19,5 @@ public interface ExtAxReadRecordService extends IService<ExtAxReadRecord> {
|
||||
|
||||
List<SimpleDocDTO> queryReadStatus(ApproverReadStatusDTO dto);
|
||||
|
||||
Boolean changeReadStatus(ChangeApproverReadStatusDTO dto);
|
||||
Boolean changeReadStatus(ChangeApproverReadStatusDTO dto, List<CustomDocDTO> customDocs);
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import cn.axzo.workflow.common.enums.BusinessTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.ButtonVisibleScopeEnum;
|
||||
import cn.axzo.workflow.common.enums.WorkspaceType;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.dto.CustomDocDTO;
|
||||
import cn.axzo.workflow.common.model.dto.SignFileDTO;
|
||||
import cn.axzo.workflow.common.model.dto.SimpleDocDTO;
|
||||
import cn.axzo.workflow.common.model.request.BpmnApproveConf;
|
||||
@ -29,6 +30,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCre
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceVariablesUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanceSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO;
|
||||
@ -38,6 +40,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskButtonSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.category.CategorySearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo;
|
||||
import cn.axzo.workflow.common.model.request.form.instance.FormVariablesUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.BatchOperationItemResultVO;
|
||||
@ -64,8 +67,10 @@ import cn.axzo.workflow.core.engine.cmd.CustomCancelProcessInstanceAsyncCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomCancelProcessInstanceCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomCarbonCopyUserSelectorCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomForecastUserTaskAssigneeCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomGetConditionPermissionsCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomGetModelDocsCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomOverrideFormVariablesByLatestInstanceCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomOverrideProcessVariablesCmd;
|
||||
import cn.axzo.workflow.core.engine.listener.EngineExecutionStartListener;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxBpmnFormRelation;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst;
|
||||
@ -154,6 +159,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME;
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CREATE_PARAM_ERROR;
|
||||
@ -187,6 +193,9 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIA
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.PENDING_TEMPLATE_VARIABLE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.PROCESS_OWNERSHIP_APPLICATION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGNATORIES;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_BASED_FILE_TAG_ORDER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOCS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_PROCESS_ENABLE_DOC_IDS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_VARIABLE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION;
|
||||
@ -495,6 +504,12 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
|
||||
dto.getVariables().put(SIGN_PROCESS_ENABLE_DOC_IDS, dto.getDocIds());
|
||||
dto.getVariables().put(SIGN_VARIABLE, dto.getBizCustomVariables());
|
||||
dto.getVariables().put(SIGNATORIES, dto.getSignatories());
|
||||
// 业务自定义文档
|
||||
dto.getVariables().put(SIGN_BIZ_CUSTOM_DOCS, dto.getCustomDocs());
|
||||
// 业务自定义文档追加顺序类型
|
||||
dto.getVariables().put(SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, StringUtils.hasText(dto.getDocAddOrderType()) ? dto.getDocAddOrderType() : "last");
|
||||
// 基于业务的标签排序
|
||||
dto.getVariables().put(SIGN_BIZ_BASED_FILE_TAG_ORDER, dto.getBasedFileTagOrder());
|
||||
}
|
||||
});
|
||||
dto.getVariables().put(INTERNAL_INITIATOR, dto.getInitiator().toJson());
|
||||
@ -1798,7 +1813,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
|
||||
});
|
||||
}
|
||||
|
||||
public List<AttachmentDTO> getAttachmentByType(Map<String, List<Attachment>> attachmentByTaskMap, String
|
||||
public static List<AttachmentDTO> getAttachmentByType(Map<String, List<Attachment>> attachmentByTaskMap, String
|
||||
taskId, AttachmentTypeEnum type) {
|
||||
return ListUtils.emptyIfNull(attachmentByTaskMap.get(taskId)).stream()
|
||||
.filter(attachment -> Objects.equals(type.getType(), attachment.getType()))
|
||||
@ -1874,6 +1889,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
|
||||
CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor();
|
||||
List<DocBaseVO> docs = commandExecutor.execute(new CustomGetModelDocsCmd(dto.getProcessInstanceId(), true, extAxModelDocMapper, extAxReModelService));
|
||||
|
||||
// 获取业务自定义传入的文档
|
||||
getAndAddBizCustomDocs(dto.getProcessInstanceId(), docs);
|
||||
|
||||
Map<Long, Boolean> readStatusMap = new HashMap<>();
|
||||
if (Objects.nonNull(dto.getAssigner())) {
|
||||
readStatusMap.putAll(extAxReadRecordService.queryReadStatus(ApproverReadStatusDTO.builder()
|
||||
@ -1892,8 +1910,74 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
|
||||
if (Objects.nonNull(archive)) {
|
||||
t.setFileRelationId(archive.getFileCode());
|
||||
t.setFileKey(archive.getFileKey());
|
||||
} else {
|
||||
// 业务自定义文档
|
||||
t.setFileKey(s.getFileRelationId());
|
||||
}
|
||||
t.setReadStatus(readStatusMap.getOrDefault(t.getId(), false));
|
||||
});
|
||||
}
|
||||
|
||||
private List<DocBaseVO> getAndAddBizCustomDocs(String processInstanceId, List<DocBaseVO> docs) {
|
||||
String tenantId;
|
||||
if (CollectionUtils.isEmpty(docs)) {
|
||||
HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
tenantId = Objects.nonNull(processInstance) ? processInstance.getTenantId() : "";
|
||||
} else {
|
||||
tenantId = docs.get(0).getTenantId();
|
||||
}
|
||||
HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId)
|
||||
.variableName(SIGN_BIZ_CUSTOM_DOCS).singleResult();
|
||||
if (Objects.isNull(historicVariableInstance)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<CustomDocDTO> bizCustomDocs = Optional.ofNullable((List<CustomDocDTO>) historicVariableInstance.getValue())
|
||||
.orElse(Collections.emptyList());
|
||||
|
||||
// 业务自定义文档
|
||||
List<DocBaseVO> customBizDocs = BeanMapper.copyList(bizCustomDocs, DocBaseVO.class, (s, t) -> {
|
||||
t.setStatus(true);
|
||||
t.setTempFile(false);
|
||||
t.setTemplateName(s.getFileName());
|
||||
t.setTag(s.getFileTag());
|
||||
t.setTenantId(tenantId);
|
||||
t.setFileRelationId(s.getFileKey());
|
||||
});
|
||||
|
||||
HistoricVariableInstance signBizOrder = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).variableName(SIGN_BIZ_BASED_FILE_TAG_ORDER).singleResult();
|
||||
List<String> basedFileTagOrder = Optional.ofNullable((List<String>) signBizOrder.getValue()).orElse(Collections.emptyList());
|
||||
if (!CollectionUtils.isEmpty(basedFileTagOrder)) {
|
||||
docs.addAll(customBizDocs);
|
||||
// 基于 fileTag 排序
|
||||
Map<String, Integer> fileTagOrderMap = IntStream.range(0, basedFileTagOrder.size())
|
||||
.boxed()
|
||||
.collect(Collectors.toMap(basedFileTagOrder::get, i -> i, (a, b) -> a));
|
||||
|
||||
docs.sort(Comparator.comparing(d -> fileTagOrderMap.getOrDefault(d.getTag(), Integer.MAX_VALUE)));
|
||||
docs = docs.stream().sorted(Comparator.comparingInt(d -> fileTagOrderMap.getOrDefault(d.getTag(), Integer.MAX_VALUE)))
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
HistoricVariableInstance bizDocOrderType = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).variableName(SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE).singleResult();
|
||||
String customAddType = String.valueOf(bizDocOrderType.getValue());
|
||||
if ("last".equals(customAddType)) {
|
||||
docs.addAll(customBizDocs);
|
||||
} else {
|
||||
docs.addAll(0, customBizDocs);
|
||||
}
|
||||
}
|
||||
return docs;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void overrideProcessVariables(BpmnProcessInstanceVariablesUpdateDTO dto) {
|
||||
CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor();
|
||||
commandExecutor.execute(new CustomOverrideProcessVariablesCmd(dto.getProcessInstanceId(), dto.getBizCustomVariables()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConditionPermissionMetaInfo> getConditions(String processInstanceId) {
|
||||
CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor();
|
||||
return commandExecutor.execute(new CustomGetConditionPermissionsCmd(processInstanceId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,6 +53,7 @@ import cn.axzo.workflow.core.engine.cmd.CustomTransferUserTaskCmd;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessDefinitionService;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessTaskService;
|
||||
import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService;
|
||||
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
|
||||
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
|
||||
import cn.axzo.workflow.core.service.converter.BpmnHistoricAttachmentConverter;
|
||||
@ -187,6 +188,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
|
||||
private ExtAxProcessLogService processLogService;
|
||||
@Resource
|
||||
private SupportRefreshProperties refreshProperties;
|
||||
@Resource
|
||||
private ExtAxDynamicSignRecordService extAxDynamicSignRecordService;
|
||||
|
||||
@Override
|
||||
public BpmPageResult<BpmnTaskTodoPageItemVO> getTodoTaskPage(BpmnTaskPageSearchDTO dto) {
|
||||
@ -862,7 +865,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
|
||||
} else {
|
||||
commandExecutor.execute(new CustomCountersignUserTaskCmd(BpmnCountersignTypeEnum.valueOfType(dto.getCountersignType()), dto.getTaskId(),
|
||||
dto.getOriginAssigner(), dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssignerList(),
|
||||
extAxHiTaskInstService));
|
||||
extAxHiTaskInstService, extAxDynamicSignRecordService));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -119,6 +119,7 @@ public class CategoryServiceImpl extends ServiceImpl<ExtAxDictMapper, ExtAxDict>
|
||||
dict.setIcon(dto.getIcon());
|
||||
dict.setDisplayInitiateMenu(dto.getDisplayInitiateMenu());
|
||||
dict.setVersion(dto.getVersion());
|
||||
dict.setAutoReplaceVariables(Boolean.TRUE.equals(dto.getAutoReplaceVariables()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
package cn.axzo.workflow.core.service.impl;
|
||||
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord;
|
||||
import cn.axzo.workflow.core.repository.mapper.ExtAxDynamicSignRecordMapper;
|
||||
import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 流程签署业务信息记录
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-04-02 10:06
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class ExtAxDynamicSignRecordServiceImpl extends ServiceImpl<ExtAxDynamicSignRecordMapper, ExtAxDynamicSignRecord> implements ExtAxDynamicSignRecordService {
|
||||
|
||||
@Resource
|
||||
private ExtAxDynamicSignRecordMapper extAxDynamicSignRecordMapper;
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.workflow.core.service.impl;
|
||||
|
||||
import cn.axzo.workflow.common.model.dto.CustomDocDTO;
|
||||
import cn.axzo.workflow.common.model.dto.SimpleDocDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverReadStatusDTO;
|
||||
@ -11,7 +12,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@ -34,8 +34,6 @@ public class ExtAxReadRecordServiceImpl extends ServiceImpl<ExtAxReadRecordMappe
|
||||
@Resource
|
||||
private ExtAxReadRecordMapper extAxReadRecordMapper;
|
||||
@Resource
|
||||
private TaskService taskService;
|
||||
@Resource
|
||||
private ExtAxModelDocService modelDocService;
|
||||
|
||||
@Override
|
||||
@ -48,7 +46,7 @@ public class ExtAxReadRecordServiceImpl extends ServiceImpl<ExtAxReadRecordMappe
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean changeReadStatus(ChangeApproverReadStatusDTO dto) {
|
||||
public Boolean changeReadStatus(ChangeApproverReadStatusDTO dto, List<CustomDocDTO> customDocs) {
|
||||
ExtAxReadRecord entity = new ExtAxReadRecord();
|
||||
entity.setProcessInstanceId(dto.getProcessInstanceId());
|
||||
entity.setPersonId(Long.valueOf(dto.getAssigner().getPersonId()));
|
||||
@ -63,7 +61,11 @@ public class ExtAxReadRecordServiceImpl extends ServiceImpl<ExtAxReadRecordMappe
|
||||
record.setPersonId(Long.valueOf(dto.getAssigner().getPersonId()));
|
||||
record.setReadStatus(Lists.newArrayList(SimpleDocDTO.builder()
|
||||
.id(dto.getDocId())
|
||||
.tag(modelDocService.get(dto.getDocId()).getTag())
|
||||
.tag(dto.getDocId() > 0 ? modelDocService.get(dto.getDocId()).getTag()
|
||||
: customDocs.stream()
|
||||
.filter(i -> Objects.equals(i.getId(), dto.getDocId()))
|
||||
.findFirst()
|
||||
.orElse(new CustomDocDTO()).getFileTag())
|
||||
.readStatus(dto.getReadStatus())
|
||||
.build()));
|
||||
extAxReadRecordMapper.insert(record);
|
||||
@ -76,7 +78,11 @@ public class ExtAxReadRecordServiceImpl extends ServiceImpl<ExtAxReadRecordMappe
|
||||
} else {
|
||||
record.getReadStatus().add(SimpleDocDTO.builder()
|
||||
.id(dto.getDocId())
|
||||
.tag(modelDocService.get(dto.getDocId()).getTag())
|
||||
.tag(dto.getDocId() > 0 ? modelDocService.get(dto.getDocId()).getTag()
|
||||
: customDocs.stream()
|
||||
.filter(i -> Objects.equals(i.getId(), dto.getDocId()))
|
||||
.findFirst()
|
||||
.orElse(new CustomDocDTO()).getFileTag())
|
||||
.readStatus(dto.getReadStatus())
|
||||
.build());
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package cn.axzo.workflow.form.service.converter;
|
||||
import cn.axzo.workflow.common.model.request.form.definition.FormFieldDTO;
|
||||
import org.flowable.form.model.FormContainer;
|
||||
import org.flowable.form.model.FormField;
|
||||
import org.flowable.form.model.OptionFormField;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@ -34,6 +35,16 @@ public interface FormFieldConverter extends EntityConverter<FormFieldDTO, FormFi
|
||||
@Mapping(target = "params", source = "entity.params")
|
||||
FormFieldDTO toVo(FormField entity);
|
||||
|
||||
@Mapping(target = "fieldType", expression = "java(entity.getClass().getSimpleName())")
|
||||
@Mapping(target = "id", source = "entity.id")
|
||||
@Mapping(target = "name", source = "entity.name")
|
||||
@Mapping(target = "type", source = "entity.type")
|
||||
@Mapping(target = "value", expression = "java(ConversionUtils.convertObject(entity.getValue()))")
|
||||
@Mapping(target = "placeholder", source = "entity.placeholder")
|
||||
@Mapping(target = "params", source = "entity.params")
|
||||
@Mapping(target = "options", source = "entity.options")
|
||||
FormFieldDTO toVo(OptionFormField entity);
|
||||
|
||||
@Mapping(target = "fieldType", expression = "java(entity.getClass().getSimpleName())")
|
||||
@Mapping(target = "id", source = "entity.id")
|
||||
@Mapping(target = "name", source = "entity.name")
|
||||
@ -50,7 +61,9 @@ public interface FormFieldConverter extends EntityConverter<FormFieldDTO, FormFi
|
||||
for (FormField entity : entities) {
|
||||
if(entity instanceof FormContainer) {
|
||||
dtos.add(toVo((FormContainer) entity));
|
||||
} else{
|
||||
} else if (entity instanceof OptionFormField) {
|
||||
dtos.add(toVo((OptionFormField) entity));
|
||||
} else {
|
||||
dtos.add(toVo((FormField) entity));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
package cn.axzo.workflow.form.service.converter;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.form.definition.FormFieldDTO;
|
||||
import cn.axzo.workflow.common.model.request.form.definition.OptionDTO;
|
||||
import cn.axzo.workflow.common.model.response.form.instance.FormInstanceVO;
|
||||
import cn.axzo.workflow.common.model.response.form.model.FormModelVO;
|
||||
import org.flowable.form.api.FormInstanceInfo;
|
||||
import org.flowable.form.api.FormModel;
|
||||
import org.flowable.form.model.FormContainer;
|
||||
import org.flowable.form.model.FormField;
|
||||
import org.flowable.form.model.Option;
|
||||
import org.flowable.form.model.OptionFormField;
|
||||
import org.flowable.form.model.SimpleFormModel;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -64,6 +68,11 @@ public interface FormInstanceConverter extends EntityConverter<FormInstanceVO, F
|
||||
formFieldDTO.setValue(ConversionUtils.convertObject(formField.getValue()));
|
||||
formFieldDTO.setPlaceholder(formField.getPlaceholder());
|
||||
formFieldDTO.setParams(formField.getParams());
|
||||
if (formField instanceof OptionFormField) {
|
||||
OptionFormField optionFormField = (OptionFormField) formField;
|
||||
formFieldDTO.setFieldType(optionFormField.getClass().getSimpleName());
|
||||
formFieldDTO.setOptions(optionsToOptionDTOs(optionFormField.getOptions()));
|
||||
}
|
||||
if (formField instanceof FormContainer) {
|
||||
FormContainer formContainer = (FormContainer) formField;
|
||||
formFieldDTO.setFieldType(formContainer.getClass().getSimpleName());
|
||||
@ -72,6 +81,19 @@ public interface FormInstanceConverter extends EntityConverter<FormInstanceVO, F
|
||||
return formFieldDTO;
|
||||
}
|
||||
|
||||
default List<OptionDTO> optionsToOptionDTOs(List<Option> options) {
|
||||
if (CollectionUtils.isEmpty(options)) {
|
||||
return null;
|
||||
}
|
||||
return options.stream()
|
||||
.map(option -> {
|
||||
OptionDTO optionDTO = new OptionDTO();
|
||||
optionDTO.setId(option.getId());
|
||||
optionDTO.setName(option.getName());
|
||||
return optionDTO;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 辅助方法,用于处理List<FormContainer>到List<FormFieldDTO>的转换,调用上面自定义的转换方法
|
||||
default List<FormFieldDTO> formContainersToFormFieldDTOs(List<FormField> formContainers) {
|
||||
|
||||
@ -158,6 +158,18 @@
|
||||
<groupId>cn.axzo.infra</groupId>
|
||||
<artifactId>adapter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.nekohtml</groupId>
|
||||
<artifactId>nekohtml</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -12,7 +12,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
|
||||
@MapperScan({"cn.axzo.workflow.core.**.mapper", "cn.axzo.workflow.admin.**.mapper"})
|
||||
@ComponentScan({"cn.axzo.workflow"})
|
||||
@ComponentScan({"cn.axzo.workflow", "cn.axzo.oss"})
|
||||
@EnableFeignClients({"cn.axzo.oss", "cn.axzo.riven.client.feign", "cn.axzo.msg.center", "cn.axzo.basics.profiles"})
|
||||
@SpringBootApplication(exclude = RabbitAutoConfiguration.class)
|
||||
@EnableTransactionManagement
|
||||
|
||||
@ -13,6 +13,7 @@ import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.time.Duration;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Objects;
|
||||
@ -22,10 +23,10 @@ import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_A
|
||||
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT;
|
||||
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE;
|
||||
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_130;
|
||||
import static cn.axzo.workflow.common.constant.StarterConstants.ENABLE_MANAGEABLE;
|
||||
import static cn.axzo.workflow.common.code.OtherRespCode.CLIENT_VERSION_SUPPORT;
|
||||
import static cn.axzo.workflow.common.code.OtherRespCode.MICRO_SERVER_NEED_REBUILD;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_130;
|
||||
import static cn.axzo.workflow.common.constant.StarterConstants.ENABLE_MANAGEABLE;
|
||||
|
||||
/**
|
||||
* 客户端与服务端的版本比较
|
||||
@ -47,11 +48,11 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor {
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
if (Objects.equals(HEADER_HTTP_CLIENT_VALUE, request.getHeader(HEADER_HTTP_CLIENT))) {
|
||||
String headerClientVersion = request.getHeader(HEADER_API_VERSION)
|
||||
.replaceAll("-SNAPSHOT", "")
|
||||
.replaceAll("-RELEASE", "");
|
||||
.replaceAll("-SNAPSHOT", "")
|
||||
.replaceAll("-RELEASE", "");
|
||||
serviceVersion = serviceVersion
|
||||
.replaceAll("-SNAPSHOT", "")
|
||||
.replaceAll("-RELEASE", "");
|
||||
.replaceAll("-SNAPSHOT", "")
|
||||
.replaceAll("-RELEASE", "");
|
||||
DefaultArtifactVersion minimumSupportedVersion = new DefaultArtifactVersion(FLOW_SERVER_VERSION_130);
|
||||
DefaultArtifactVersion clientVersion = new DefaultArtifactVersion(headerClientVersion);
|
||||
DefaultArtifactVersion serverVersion = new DefaultArtifactVersion(serviceVersion);
|
||||
@ -65,10 +66,29 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor {
|
||||
throw new WorkflowEngineException(CLIENT_VERSION_SUPPORT, serviceVersion, headerClientVersion);
|
||||
}
|
||||
}
|
||||
|
||||
if (request.getRequestURI().contains("/web/process/validate-auth")) {
|
||||
return true;
|
||||
}
|
||||
if (request.getRequestURI().contains("/web/process/form")) {
|
||||
HttpSession session = request.getSession();
|
||||
// 检查session中是否有"已验证"标记
|
||||
Boolean isAuthenticated = (Boolean) session.getAttribute("isAuthenticated");
|
||||
if (isAuthenticated == null || !isAuthenticated) {
|
||||
// 未验证:转发到原页面(由页面展示授权码输入框)
|
||||
return true; // 不拦截,由页面逻辑处理
|
||||
// 或重定向到单独的授权页面:response.sendRedirect("/auth/page");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 仅 feignApi 才需要检查版本
|
||||
if (!request.getRequestURI().contains("/web/") && !request.getRequestURI().contains("checkDeath")
|
||||
&& !request.getRequestURI().contains("/error")
|
||||
&& !StringUtils.hasText(request.getHeader(HEADER_HTTP_CLIENT))) {
|
||||
&& !request.getRequestURI().contains(".ico")// 这三行主要解决form.html页面访问
|
||||
&& !request.getRequestURI().contains(".json")//
|
||||
&& !request.getRequestURI().contains(".html")//
|
||||
&& !request.getRequestURI().contains("/error")
|
||||
&& !StringUtils.hasText(request.getHeader(HEADER_HTTP_CLIENT))) {
|
||||
String serverName = request.getHeader(HEADER_SERVER_NAME);
|
||||
printHeader(request);
|
||||
log.error(MICRO_SERVER_NEED_REBUILD.getMessage(), serverName);
|
||||
@ -104,7 +124,7 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor {
|
||||
}
|
||||
ExtAxProperty property = extAxProperty.get();
|
||||
if (Objects.equals(property.getValue(), clientVersion.toString())
|
||||
&& Objects.equals(property.getManageable().toString(), manageableStatus)) {
|
||||
&& Objects.equals(property.getManageable().toString(), manageableStatus)) {
|
||||
return;
|
||||
}
|
||||
property.setName(requestApplicationName);
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
package cn.axzo.workflow.server.common.util;
|
||||
|
||||
/**
|
||||
* 处理字符串视觉显示宽度的工具类
|
||||
* 适用于中英文混排的对齐场景
|
||||
*/
|
||||
public class VisualStringUtils {
|
||||
|
||||
// 私有构造器,防止实例化
|
||||
private VisualStringUtils() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
}
|
||||
|
||||
/**
|
||||
* 将输入字符串转换为等效视觉长度的空格字符串
|
||||
* 例:"Hi中" -> " " (4个空格:H=1, i=1, 中=2)
|
||||
*
|
||||
* @param input 原始字符串
|
||||
* @return 等长的空格字符串,如果输入为null则返回空串
|
||||
*/
|
||||
public static String toEqualLengthSpace(String input) {
|
||||
if (input == null || input.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (char c : input.toCharArray()) {
|
||||
if (isWideChar(c)) {
|
||||
sb.append(" "); // 宽字符占2格
|
||||
} else {
|
||||
sb.append(" "); // 窄字符占1格
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字符串的视觉显示长度
|
||||
* (中文算2,英文算1)
|
||||
*
|
||||
* @param input 输入字符串
|
||||
* @return 视觉长度
|
||||
*/
|
||||
public static int getVisualLength(String input) {
|
||||
if (input == null || input.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
int length = 0;
|
||||
for (char c : input.toCharArray()) {
|
||||
length += isWideChar(c) ? 2 : 1;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符是否为宽字符(占2个显示宽度)
|
||||
* 逻辑:非 ASCII 字符 (code > 255) 视为宽字符
|
||||
*/
|
||||
private static boolean isWideChar(char c) {
|
||||
// 0-255 包括了数字、英文大小写、英文标点符号 (半角)
|
||||
// 大于 255 的涵盖了汉字、全角符号、日韩文等
|
||||
return c > 255;
|
||||
}
|
||||
}
|
||||
@ -18,9 +18,11 @@ import cn.axzo.workflow.common.model.dto.UploadFieldDTO;
|
||||
import cn.axzo.workflow.common.model.dto.VariableObjectDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomGetProcessInstanceVariablesToObjectCmd;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONException;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -28,6 +30,8 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -41,7 +45,9 @@ import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCE
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_PHONE_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_POSITION;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_POSITION_DESC;
|
||||
import static cn.axzo.workflow.common.model.dto.VariableObjectDTO.Type.img;
|
||||
import static cn.axzo.workflow.common.model.dto.VariableObjectDTO.Type.signatureAndAdvice;
|
||||
import static cn.axzo.workflow.common.model.dto.VariableObjectDTO.Type.text;
|
||||
|
||||
/**
|
||||
* WPS 工具类
|
||||
@ -50,6 +56,7 @@ import static cn.axzo.workflow.common.model.dto.VariableObjectDTO.Type.signature
|
||||
* @since 2025-04-09 20:41
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class WpsUtil {
|
||||
public static final List<FileTypeEnum> WPS_SUPPORTED_FILE_TYPES = Lists.newArrayList(FileTypeEnum.WORD, FileTypeEnum.EXCEL);
|
||||
@Resource
|
||||
@ -58,6 +65,71 @@ public class WpsUtil {
|
||||
private ServerFileServiceApi serverFileServiceApi;
|
||||
@Resource
|
||||
private OrganizationalNodeUserQueryApi organizationalNodeUserQueryApi;
|
||||
private static final String TRANSPARENT_IMAGE_URL = "https://axzo-obs-public.obs.cn-north-4.myhuaweicloud.com:443/obs-public/obs-public/62F92618016840F89D8810CD1816E04D.png";
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<String> strList = new ArrayList<>();
|
||||
strList.add("[中文]");
|
||||
strList.add("[中文,English,]");
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 wps 文件变量替换接口
|
||||
*
|
||||
* @param fileCode 基于该模板进行变量替换
|
||||
* @param fileKey 如果有值,则变量替换完成后,直接将文档覆盖该 fileKey 对应的文件;
|
||||
* @return 返回替换变量后的文件oss 的 fileKey
|
||||
*/
|
||||
public String wpsFileVariableReplace(List<VariableObjectDTO> wpsVariables,
|
||||
String fileCode, String fileKey, String fileName, Boolean autoReplaceVariables) {
|
||||
List<VariableObjectDTO> variables = wpsVariables.stream()
|
||||
.filter(i -> Objects.equals(i.getType().name(), VariableObjectDTO.Type.img.name()) || Objects.equals(i.getType().name(), VariableObjectDTO.Type.text.name()))
|
||||
.filter(i -> {
|
||||
if (Objects.equals(Boolean.TRUE, autoReplaceVariables)) {
|
||||
return true;
|
||||
} else {
|
||||
return Objects.nonNull(i.getValue()) && checkNotEmptyColl(i);
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
List<FileReplaceContent> fileReplaceContents = BeanMapper.copyList(variables, FileReplaceContent.class, (s, t) -> {
|
||||
t.setKey(s.getDesc());
|
||||
if (Objects.equals(s.getType().name(), VariableObjectDTO.Type.img.name())) {
|
||||
List<UploadFieldDTO> uploadFieldDTOS = new ArrayList<>();
|
||||
if (isJson(s.getValue().toString())) {
|
||||
uploadFieldDTOS.addAll(JSON.parseArray(s.getValue().toString(), UploadFieldDTO.class));
|
||||
} else {
|
||||
uploadFieldDTOS.addAll(JSON.parseArray(JSON.toJSONString(s.getValue()), UploadFieldDTO.class));
|
||||
}
|
||||
t.setContent(CollectionUtils.isEmpty(uploadFieldDTOS) ?
|
||||
// 强制设置为透明图片
|
||||
TRANSPARENT_IMAGE_URL : uploadFieldDTOS.get(0).getFileUrl());
|
||||
} else {
|
||||
t.setContent(Objects.nonNull(s.getValue()) ? s.getValue().toString() : "");
|
||||
}
|
||||
t.setType(s.getType().name());
|
||||
t.setPrefix("[");
|
||||
t.setSuffix("]");
|
||||
});
|
||||
|
||||
// 处理空值
|
||||
if (Objects.equals(Boolean.TRUE, autoReplaceVariables)) {
|
||||
fileReplaceContents.stream()
|
||||
.filter(i -> !StringUtils.hasText(i.getContent()))
|
||||
.forEach(i -> {
|
||||
if (Objects.equals(i.getType(), img.name())) {
|
||||
//强制设置为透明图片
|
||||
i.setContent(TRANSPARENT_IMAGE_URL);
|
||||
} else if (Objects.equals(i.getType(), text.name())) {
|
||||
// 将变量替换未空串
|
||||
String equalLengthSpace = VisualStringUtils.toEqualLengthSpace(i.getPrefix() + i.getKey() + i.getSuffix());
|
||||
i.setContent(equalLengthSpace);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return replaceWordText(fileCode, fileKey, fileName, fileReplaceContents);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 wps 文件变量替换接口
|
||||
@ -69,18 +141,19 @@ public class WpsUtil {
|
||||
public String wpsFileVariableReplace(List<VariableObjectDTO> wpsVariables,
|
||||
String fileCode, String fileKey, String fileName) {
|
||||
|
||||
List<FileReplaceContent> fileReplaceContents = BeanMapper.copyList(wpsVariables.stream()
|
||||
.filter(i -> Objects.nonNull(i.getValue()))
|
||||
.filter(i -> !(Objects.equals(i.getType().name(), "img") && !StringUtils.hasText(i.getValue().toString())))
|
||||
/*List<FileReplaceContent> fileReplaceContents = BeanMapper.copyList(wpsVariables.stream()
|
||||
.filter(i -> Objects.nonNull(i.getValue()) && checkNotEmptyColl(i))
|
||||
.filter(i -> Objects.equals(i.getType().name(), "img") || Objects.equals(i.getType().name(), "text"))
|
||||
.collect(Collectors.toList()), FileReplaceContent.class, (s, t) -> {
|
||||
t.setKey(s.getDesc());
|
||||
if (Objects.equals(s.getType().name(), "img")) {
|
||||
List<UploadFieldDTO> uploadFieldDTOS;
|
||||
if (isJson(s.getValue().toString())) {
|
||||
t.setContent(JSON.parseArray(s.getValue().toString(), UploadFieldDTO.class).get(0).getFileUrl());
|
||||
uploadFieldDTOS = JSON.parseArray(s.getValue().toString(), UploadFieldDTO.class);
|
||||
} else {
|
||||
t.setContent(JSON.parseArray(JSON.toJSONString(s.getValue()), UploadFieldDTO.class).get(0).getFileUrl());
|
||||
uploadFieldDTOS = JSON.parseArray(JSON.toJSONString(s.getValue()), UploadFieldDTO.class);
|
||||
}
|
||||
t.setContent(CollectionUtils.isEmpty(uploadFieldDTOS) ? "" : uploadFieldDTOS.get(0).getFileUrl());
|
||||
} else {
|
||||
t.setContent(Objects.nonNull(s.getValue()) ? s.getValue().toString() : "");
|
||||
}
|
||||
@ -88,6 +161,11 @@ public class WpsUtil {
|
||||
t.setPrefix("[");
|
||||
t.setSuffix("]");
|
||||
});
|
||||
return replaceWordText(fileCode, fileKey, fileName, fileReplaceContents);*/
|
||||
return wpsFileVariableReplace(wpsVariables, fileCode, fileKey, fileName, false);
|
||||
}
|
||||
|
||||
private String replaceWordText(String fileCode, String fileKey, String fileName, List<FileReplaceContent> fileReplaceContents) {
|
||||
if (StringUtils.hasText(fileCode)) {
|
||||
FileTemplateReplaceRequest request = new FileTemplateReplaceRequest();
|
||||
request.setFileCode(fileCode);
|
||||
@ -103,6 +181,14 @@ public class WpsUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkNotEmptyColl(VariableObjectDTO i) {
|
||||
if (!(i.getValue() instanceof Collection)) {
|
||||
return true;
|
||||
}
|
||||
return !CollectionUtils.isEmpty((Collection<?>) i.getValue());
|
||||
|
||||
}
|
||||
|
||||
public List<VariableObjectDTO> getWpsReplaceVariables(ProcessEngineConfigurationImpl processEngineConfiguration, String processInstanceId) {
|
||||
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
|
||||
List<VariableObjectDTO> wpsVariables =
|
||||
@ -111,15 +197,28 @@ public class WpsUtil {
|
||||
List<VariableObjectDTO> signatureAndAdvices = Lists.newArrayList();
|
||||
wpsVariables.stream().filter(i -> Objects.equals(signatureAndAdvice, i.getType())).forEach(variableObjectDTO -> {
|
||||
List<SignatureDTO.SignDetail> signDetails = (List<SignatureDTO.SignDetail>) variableObjectDTO.getValue();
|
||||
log.info("getWpsReplaceVariables signDetails: {}", JSON.toJSONString(signDetails));
|
||||
if (!CollectionUtils.isEmpty(signDetails)) {
|
||||
SignatureDTO.SignDetail signDetail = signDetails.get(0);
|
||||
signatureAndAdvices.add(VariableObjectDTO.builder()
|
||||
.key(variableObjectDTO.getKey() + "_approverName")
|
||||
.desc(variableObjectDTO.getDesc() + "姓名")
|
||||
.value(signDetail.getApproverName())
|
||||
.type(VariableObjectDTO.Type.text)
|
||||
.build());
|
||||
signatureAndAdvices.add(VariableObjectDTO.builder()
|
||||
.key(variableObjectDTO.getKey() + "_activityResult")
|
||||
.desc(variableObjectDTO.getDesc() + "审批结果")
|
||||
.value(signDetail.getResult())
|
||||
.type(VariableObjectDTO.Type.text)
|
||||
.build());
|
||||
ApiSignUrlDownloadRequest request = ApiSignUrlDownloadRequest.builder()
|
||||
.fileKeys(Lists.newArrayList(signDetail.getSignature())).build();
|
||||
List<ApiSignUrlDownloadResponse> signUrl = RpcExternalUtil.rpcProcessor(() -> serverFileServiceApi.signUrlFetchDownload(request), "获取手写签图片地址", request);
|
||||
signatureAndAdvices.add(VariableObjectDTO.builder()
|
||||
.key(variableObjectDTO.getKey() + "_signature")
|
||||
.desc(variableObjectDTO.getDesc() + "电子签名")
|
||||
.value(Lists.newArrayList(UploadFieldDTO.builder().fileKey(signDetail.getSignature()).fileUrl(signUrl.get(0).getSignUrl()).build()))
|
||||
.value(CollectionUtils.isEmpty(signUrl) ? Lists.newArrayList() : Lists.newArrayList(UploadFieldDTO.builder().fileKey(signDetail.getSignature()).fileUrl(CollectionUtils.isEmpty(signUrl) ? null : signUrl.get(0).getSignUrl()).build()))
|
||||
.type(VariableObjectDTO.Type.img)
|
||||
.build());
|
||||
signatureAndAdvices.add(VariableObjectDTO.builder()
|
||||
@ -128,6 +227,12 @@ public class WpsUtil {
|
||||
.value(signDetail.getAdvice())
|
||||
.type(VariableObjectDTO.Type.text)
|
||||
.build());
|
||||
signatureAndAdvices.add(VariableObjectDTO.builder()
|
||||
.key(variableObjectDTO.getKey() + "_activityOperationTime")
|
||||
.desc(variableObjectDTO.getDesc() + "日期")
|
||||
.value(DateUtil.format(signDetail.getOperationTime(), "yyyy.MM.dd"))
|
||||
.type(VariableObjectDTO.Type.text)
|
||||
.build());
|
||||
}
|
||||
});
|
||||
wpsVariables.addAll(signatureAndAdvices);
|
||||
@ -152,6 +257,7 @@ public class WpsUtil {
|
||||
.build());
|
||||
|
||||
});
|
||||
log.info("wpsVariables: {}", JSON.toJSONString(wpsVariables));
|
||||
return wpsVariables;
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import cn.axzo.karma.client.model.response.PersonProfileResp;
|
||||
import cn.axzo.orggateway.api.nodeuser.resp.FlowTaskAssignerV2Resp;
|
||||
import cn.axzo.workflow.common.enums.ApproverScopeEnum;
|
||||
import cn.axzo.workflow.common.enums.CarbonCopyObjectType;
|
||||
import cn.axzo.workflow.common.exception.WorkflowApproverCalcException;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||
@ -45,6 +46,7 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.CALC_TASK_ASSIGNEE_ERROR;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.COOPERATION_NOT_EXIST_WITH_NODE;
|
||||
import static cn.axzo.workflow.common.code.ConvertorRespCode.CONVERTOR_META_DATA_FORMAT_ERROR;
|
||||
import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_USER_TASK_CALC_ERROR;
|
||||
import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_USER_TASK_PARAM_ERROR;
|
||||
@ -122,6 +124,40 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected final <T> T parseFoundationApiResultWithErrCode(Supplier<cn.axzo.foundation.result.ApiResult<T>> supplier, String operatorDesc,
|
||||
String extInfo, Object... param) {
|
||||
StopWatch stopWatch = new StopWatch(operatorDesc);
|
||||
log.info("{}-Param: {}", operatorDesc, JSONUtil.toJsonStr(param));
|
||||
stopWatch.start();
|
||||
cn.axzo.foundation.result.ApiResult<T> result = supplier.get();
|
||||
stopWatch.stop();
|
||||
log.info("{}-Cost:{}, Result: {}", operatorDesc,
|
||||
"API StopWatch '" + stopWatch.getId() + "': running time = " + stopWatch.getTotalTimeSeconds() + " 's",
|
||||
JSONUtil.toJsonStr(result));
|
||||
try {
|
||||
if (stopWatch.getTotalTimeSeconds() > refreshProperties.getApiTimeout() && Boolean.TRUE.equals(refreshProperties.getSendDingTalk())) {
|
||||
DingTalkUtils.sendDingTalkForSlowUrl(applicationContext.getEnvironment()
|
||||
.getProperty("spring.profiles.active"),
|
||||
stopWatch.getTotalTimeSeconds(),
|
||||
extInfo,
|
||||
param,
|
||||
result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
Assert.notNull(result, "服务调用异常");
|
||||
if (Objects.equals(30022100, result.getCode())) {
|
||||
// 特殊需求,组织不存在时抛得的异常码
|
||||
throw new WorkflowApproverCalcException(COOPERATION_NOT_EXIST_WITH_NODE);
|
||||
}
|
||||
// 200自定义处理
|
||||
if (HttpStatus.HTTP_OK != result.getCode()) {
|
||||
throw new WorkflowEngineException(CALC_TASK_ASSIGNEE_ERROR, "[API:" + extInfo + "]" + result.getMsg());
|
||||
}
|
||||
return result.getData();
|
||||
}
|
||||
|
||||
protected final <T> T parseFoundationApiResult(Supplier<cn.axzo.foundation.result.ApiResult<T>> supplier, String operatorDesc,
|
||||
String extInfo, Object... param) {
|
||||
StopWatch stopWatch = new StopWatch(operatorDesc);
|
||||
|
||||
@ -9,9 +9,11 @@ import cn.axzo.orggateway.api.nodeuser.resp.FlowTaskAssignerV2Resp;
|
||||
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverSpecifyRangeEnum;
|
||||
import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum;
|
||||
import cn.axzo.workflow.common.exception.WorkflowApproverCalcException;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.dto.CooperationOrgDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -21,6 +23,7 @@ import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -33,12 +36,14 @@ import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_USER_TA
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CLOSE_PROCESS_ASSIGNER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN;
|
||||
import static cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum.transferToAdmin;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecifyRange;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecifyRangeOrgLimit;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecifyValueV2;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getAreaFilterEnable;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getOnlyInProjectEnable;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSpecialtyFilterEnable;
|
||||
|
||||
/**
|
||||
@ -76,6 +81,7 @@ public class BasedIdentityV2TaskAssigneeSelector extends AbstractBpmnTaskAssigne
|
||||
.initiatorPersonId(initiator.parsePersonId())
|
||||
.areaCodes(getAreaFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeAreaCodes())) : Sets.newHashSet())
|
||||
.specialtyCodes(getSpecialtyFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeSpecialtyCodes())) : Sets.newHashSet())
|
||||
.projectIds(getOnlyInProjectEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getProjectIds())) : Sets.newHashSet())
|
||||
.querySupervisorWhileMissMatched(getApproverEmptyHandleType(flowElement).filter(type -> Objects.equals(type, transferToAdmin)).isPresent());
|
||||
switch (optRange.get()) {
|
||||
case within_the_project:
|
||||
@ -118,8 +124,14 @@ public class BasedIdentityV2TaskAssigneeSelector extends AbstractBpmnTaskAssigne
|
||||
break;
|
||||
}
|
||||
FlowTaskAssignerV2Req request = v2ReqBuilder.build();
|
||||
List<FlowTaskAssignerV2Resp> apiResultUsers = parseFoundationApiResult(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询身份下的人" + execution.getProcessInstanceId() + flowElement.getId(),
|
||||
"cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request);
|
||||
List<FlowTaskAssignerV2Resp> apiResultUsers = new ArrayList<>();
|
||||
try {
|
||||
apiResultUsers.addAll(parseFoundationApiResultWithErrCode(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询身份下的人" + execution.getProcessInstanceId() + flowElement.getId(),
|
||||
"cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request));
|
||||
} catch (WorkflowApproverCalcException e) {
|
||||
log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e);
|
||||
execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + flowElement.getId(), true);
|
||||
}
|
||||
return convertApprover(apiResultUsers);
|
||||
}
|
||||
|
||||
|
||||
@ -7,8 +7,10 @@ import cn.axzo.orggateway.api.nodeuser.req.FlowTaskAssignerV2Req;
|
||||
import cn.axzo.orggateway.api.nodeuser.resp.FlowTaskAssignerV2Resp;
|
||||
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
||||
import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum;
|
||||
import cn.axzo.workflow.common.exception.WorkflowApproverCalcException;
|
||||
import cn.axzo.workflow.common.model.dto.CooperationOrgDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
@ -17,17 +19,20 @@ import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN;
|
||||
import static cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum.transferToAdmin;
|
||||
import static cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum.in_project;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getAreaFilterEnable;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getInitiatorLeaderRangeUnit;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getOnlyInProjectEnable;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSpecialtyFilterEnable;
|
||||
|
||||
/**
|
||||
@ -69,11 +74,18 @@ public class BasedInitiatorLeaderV2TaskAssigneeSelector extends AbstractBpmnTask
|
||||
.initiatorPersonId(initiator.parsePersonId())
|
||||
.areaCodes(getAreaFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeAreaCodes())) : Sets.newHashSet())
|
||||
.specialtyCodes(getSpecialtyFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeSpecialtyCodes())) : Sets.newHashSet())
|
||||
.projectIds(getOnlyInProjectEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getProjectIds())) : Sets.newHashSet())
|
||||
.querySupervisorWhileMissMatched(getApproverEmptyHandleType(flowElement).filter(type -> Objects.equals(type, transferToAdmin)).isPresent());
|
||||
|
||||
FlowTaskAssignerV2Req request = v2ReqBuilder.build();
|
||||
List<FlowTaskAssignerV2Resp> apiResultUsers = parseFoundationApiResult(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询发起人主管的审批人" + execution.getProcessInstanceId() + flowElement.getId(),
|
||||
"cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request);
|
||||
List<FlowTaskAssignerV2Resp> apiResultUsers = new ArrayList<>();
|
||||
try {
|
||||
apiResultUsers.addAll(parseFoundationApiResultWithErrCode(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询发起人主管的审批人" + execution.getProcessInstanceId() + flowElement.getId(),
|
||||
"cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request));
|
||||
} catch (WorkflowApproverCalcException e) {
|
||||
log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e);
|
||||
execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + flowElement.getId(), true);
|
||||
}
|
||||
return convertApprover(apiResultUsers);
|
||||
}
|
||||
|
||||
|
||||
@ -10,9 +10,11 @@ import cn.axzo.workflow.common.enums.ApproverSpecifyRangeEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum;
|
||||
import cn.axzo.workflow.common.enums.CooperateShipTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum;
|
||||
import cn.axzo.workflow.common.exception.WorkflowApproverCalcException;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.dto.CooperationOrgDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -22,6 +24,7 @@ import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -33,6 +36,7 @@ import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_POSITIO
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CLOSE_PROCESS_ASSIGNER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN;
|
||||
import static cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum.transferToAdmin;
|
||||
import static cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum.in_project;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType;
|
||||
@ -42,6 +46,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprove
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecifyValueV2;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getAreaFilterEnable;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCooperateShipType;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getOnlyInProjectEnable;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSpecialtyFilterEnable;
|
||||
|
||||
/**
|
||||
@ -80,6 +85,7 @@ public class BasedPositionV2TaskAssigneeSelector extends AbstractBpmnTaskAssigne
|
||||
.initiatorPersonId(initiator.parsePersonId())
|
||||
.areaCodes(getAreaFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeAreaCodes())) : Sets.newHashSet())
|
||||
.specialtyCodes(getSpecialtyFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeSpecialtyCodes())) : Sets.newHashSet())
|
||||
.projectIds(getOnlyInProjectEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getProjectIds())) : Sets.newHashSet())
|
||||
.querySupervisorWhileMissMatched(getApproverEmptyHandleType(flowElement).filter(type -> Objects.equals(type, transferToAdmin)).isPresent());
|
||||
switch (optRange.get()) {
|
||||
case within_the_project:
|
||||
@ -141,8 +147,14 @@ public class BasedPositionV2TaskAssigneeSelector extends AbstractBpmnTaskAssigne
|
||||
break;
|
||||
}
|
||||
FlowTaskAssignerV2Req request = v2ReqBuilder.build();
|
||||
List<FlowTaskAssignerV2Resp> apiResultUsers = parseFoundationApiResult(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询岗位下的人" + execution.getProcessInstanceId() + flowElement.getId(),
|
||||
"cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request);
|
||||
List<FlowTaskAssignerV2Resp> apiResultUsers = new ArrayList<>();
|
||||
try {
|
||||
apiResultUsers.addAll(parseFoundationApiResultWithErrCode(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询岗位下的人" + execution.getProcessInstanceId() + flowElement.getId(),
|
||||
"cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request));
|
||||
} catch (WorkflowApproverCalcException e) {
|
||||
log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e);
|
||||
execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + flowElement.getId(), true);
|
||||
}
|
||||
return convertApprover(apiResultUsers);
|
||||
}
|
||||
|
||||
|
||||
@ -10,9 +10,11 @@ import cn.axzo.workflow.common.enums.ApproverSpecifyRangeEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum;
|
||||
import cn.axzo.workflow.common.enums.CooperateShipTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum;
|
||||
import cn.axzo.workflow.common.exception.WorkflowApproverCalcException;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.dto.CooperationOrgDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -23,6 +25,7 @@ import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -34,6 +37,7 @@ import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_ROLE_V2
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CLOSE_PROCESS_ASSIGNER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN;
|
||||
import static cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum.transferToAdmin;
|
||||
import static cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum.in_project;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType;
|
||||
@ -43,6 +47,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprove
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecifyValueV2;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getAreaFilterEnable;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCooperateShipType;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getOnlyInProjectEnable;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSpecialtyFilterEnable;
|
||||
|
||||
/**
|
||||
@ -82,6 +87,7 @@ public class BasedRoleV2TaskAssigneeSelector extends AbstractBpmnTaskAssigneeSel
|
||||
.initiatorPersonId(initiator.parsePersonId())
|
||||
.areaCodes(getAreaFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeAreaCodes())) : Sets.newHashSet())
|
||||
.specialtyCodes(getSpecialtyFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeSpecialtyCodes())) : Sets.newHashSet())
|
||||
.projectIds(getOnlyInProjectEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getProjectIds())) : Sets.newHashSet())
|
||||
.querySupervisorWhileMissMatched(getApproverEmptyHandleType(flowElement).filter(type -> Objects.equals(type, transferToAdmin)).isPresent());
|
||||
switch (optRange.get()) {
|
||||
case within_the_project:
|
||||
@ -144,8 +150,14 @@ public class BasedRoleV2TaskAssigneeSelector extends AbstractBpmnTaskAssigneeSel
|
||||
break;
|
||||
}
|
||||
FlowTaskAssignerV2Req request = v2ReqBuilder.build();
|
||||
List<FlowTaskAssignerV2Resp> apiResultUsers = parseFoundationApiResult(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询角色下的人" + execution.getProcessInstanceId() + flowElement.getId(),
|
||||
"cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request);
|
||||
List<FlowTaskAssignerV2Resp> apiResultUsers = new ArrayList<>();
|
||||
try {
|
||||
apiResultUsers.addAll(parseFoundationApiResultWithErrCode(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询角色下的人" + execution.getProcessInstanceId() + flowElement.getId(),
|
||||
"cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request));
|
||||
} catch (WorkflowApproverCalcException e) {
|
||||
log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e);
|
||||
execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + flowElement.getId(), true);
|
||||
}
|
||||
return convertApprover(apiResultUsers);
|
||||
}
|
||||
|
||||
|
||||
@ -63,6 +63,7 @@ public class OperationFileArchiveActivityEvent_101_Listener extends AbstractBpmn
|
||||
List<VariableObjectDTO> wpsReplaceVariables = wpsUtil.getWpsReplaceVariables(processEngineConfiguration, execution.getProcessInstanceId());
|
||||
processSign.getFileArchive().stream().filter(i -> Objects.equals(i.getFileType(), FileTypeEnum.WORD)
|
||||
|| Objects.equals(i.getFileType(), FileTypeEnum.EXCEL))
|
||||
.filter(i -> Boolean.TRUE.equals(i.getNeedReplaceVariables()))
|
||||
.forEach(docBaseVO -> {
|
||||
String newFileKey = wpsUtil.wpsFileVariableReplace(wpsReplaceVariables, null, docBaseVO.getFileKey(), docBaseVO.getTemplateName() + docBaseVO.getFileType().getSuffix());
|
||||
docBaseVO.setFileKey(newFileKey);
|
||||
|
||||
@ -178,7 +178,7 @@ public class RocketMqBpmActivityEvent_100_Listener extends AbstractBpmnEventList
|
||||
if (Objects.nonNull(processInstance)) {
|
||||
dto.setProcessDefinitionKey(processInstance.getProcessDefinitionKey());
|
||||
dto.setBusinessKey(processInstance.getBusinessKey());
|
||||
dto.setVariables(processInstance.getProcessVariables());
|
||||
dto.setVariables(removeBpmnConstantsVariables(processInstance.getProcessVariables()));
|
||||
dto.setWorkflowEngineVersion(String.valueOf(processInstance.getProcessVariables()
|
||||
.getOrDefault(WORKFLOW_ENGINE_VERSION, FLOW_SERVER_VERSION_121)));
|
||||
} else {
|
||||
|
||||
@ -23,10 +23,10 @@ import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.engine.HistoryService;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@ -45,7 +45,6 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
||||
@ -109,6 +108,8 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
|
||||
@Resource
|
||||
private HistoryService historyService;
|
||||
@Resource
|
||||
private RuntimeService runtimeService;
|
||||
@Resource
|
||||
private TaskService taskService;
|
||||
@Value("${sendMq:true}")
|
||||
private Boolean sendMQ;
|
||||
@ -365,11 +366,8 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
|
||||
private Map<String, Object> collectionVariable(MessagePushEvent event) {
|
||||
Map<String, Object> variables = new HashMap<>();
|
||||
|
||||
Map<String, Object> originVariables = runtimeService.getVariables(event.getProcessInstanceId());
|
||||
BpmnProcessInstanceVO processInstance = getContext().getInstanceVO(() -> getBpmnProcessInstanceVO(event));
|
||||
Map<String, Object> originVariables = processInstance.getVariables().entrySet().stream()
|
||||
.filter(e -> Objects.nonNull(e.getKey()) && Objects.nonNull(e.getValue()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
|
||||
BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(originVariables.get(INTERNAL_INITIATOR));
|
||||
if (Objects.isNull(initiator)) {
|
||||
initiator = new BpmnTaskDelegateAssigner();
|
||||
@ -451,7 +449,7 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
|
||||
.setTemplateId(templateId)
|
||||
.setTaskId(event.getTaskId())
|
||||
.setReceivePersons(event.getAssigners())
|
||||
.setVariables(variables)
|
||||
.setVariables(removeBpmnConstantsVariables(variables))
|
||||
.setProcessApproveConf(event.getProcessApproveConfig())
|
||||
.setActivitySignature(activitySignature)
|
||||
.setTerminalType(terminalType);
|
||||
|
||||
@ -4,12 +4,14 @@ import cn.axzo.workflow.common.enums.FileTypeEnum;
|
||||
import cn.axzo.workflow.common.model.dto.SignFileDTO;
|
||||
import cn.axzo.workflow.common.model.dto.VariableObjectDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnSignConf;
|
||||
import cn.axzo.workflow.common.model.response.category.CategoryItemVO;
|
||||
import cn.axzo.workflow.core.common.context.ProcessOperationContext;
|
||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||
import cn.axzo.workflow.core.listener.AbstractBpmnEventListener;
|
||||
import cn.axzo.workflow.core.listener.BpmnProcessEventListener;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxDocContent;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxProcessSign;
|
||||
import cn.axzo.workflow.core.service.CategoryService;
|
||||
import cn.axzo.workflow.core.service.ExtAxDocContentService;
|
||||
import cn.axzo.workflow.core.service.ExtAxModelDocService;
|
||||
import cn.axzo.workflow.core.service.ExtAxProcessSignService;
|
||||
@ -35,6 +37,8 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_MODEL_CATEGORY;
|
||||
|
||||
/**
|
||||
* 签署业务,审批完成后,进行文件归档,并对所有工人发送业务待办
|
||||
*
|
||||
@ -55,6 +59,8 @@ public class FileArchiveProcessEventListener extends AbstractBpmnEventListener<P
|
||||
@Resource
|
||||
private ExtAxDocContentService extAxDocContentService;
|
||||
@Resource
|
||||
private CategoryService categoryService;
|
||||
@Resource
|
||||
private WpsUtil wpsUtil;
|
||||
|
||||
|
||||
@ -71,18 +77,21 @@ public class FileArchiveProcessEventListener extends AbstractBpmnEventListener<P
|
||||
HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery()
|
||||
.processInstanceId(processInstanceId).includeProcessVariables().singleResult();
|
||||
|
||||
CategoryItemVO category = categoryService.get(BPM_MODEL_CATEGORY, mainProcess.getId()).orElse(new CategoryItemVO());
|
||||
// 文件归档,将审批过程中产生的数据全部替换文档模板变量
|
||||
archiveFinalDocs(instance);
|
||||
archiveFinalDocs(instance, category.getAutoReplaceVariables());
|
||||
}
|
||||
|
||||
private void archiveFinalDocs(HistoricProcessInstance instance) {
|
||||
private void archiveFinalDocs(HistoricProcessInstance instance, Boolean autoReplaceVariables) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) getEngineConfiguration();
|
||||
ExtAxProcessSign processSign = extAxProcessSignService.findByProcessInstanceId(instance.getId());
|
||||
List<VariableObjectDTO> wpsReplaceVariables = wpsUtil.getWpsReplaceVariables(processEngineConfiguration, instance.getId());
|
||||
|
||||
processSign.getFileArchive().stream().filter(i -> Objects.equals(i.getFileType(), FileTypeEnum.WORD)
|
||||
|| Objects.equals(i.getFileType(), FileTypeEnum.EXCEL))
|
||||
.filter(i -> Boolean.TRUE.equals(i.getNeedReplaceVariables()))
|
||||
.forEach(docBaseVO -> {
|
||||
String newFileKey = wpsUtil.wpsFileVariableReplace(wpsReplaceVariables, null, docBaseVO.getFileKey(), docBaseVO.getTemplateName() + docBaseVO.getFileType().getSuffix());
|
||||
String newFileKey = wpsUtil.wpsFileVariableReplace(wpsReplaceVariables, null, docBaseVO.getFileKey(), docBaseVO.getTemplateName() + docBaseVO.getFileType().getSuffix(), autoReplaceVariables);
|
||||
docBaseVO.setFileKey(newFileKey);
|
||||
});
|
||||
// 删除非 WPS 的临时文档
|
||||
@ -115,6 +124,6 @@ public class FileArchiveProcessEventListener extends AbstractBpmnEventListener<P
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE + 3;
|
||||
return Integer.MIN_VALUE + 99;
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ public class RocketMqBpmnProcessEventListener extends AbstractBpmnEventListener<
|
||||
.setProcessDefinitionKey(((ExecutionEntityImpl) event.getEntity()).getProcessDefinitionKey())
|
||||
.setProcessDefinitionVersion(((ExecutionEntityImpl) event.getEntity()).getProcessDefinitionVersion())
|
||||
.setInitiator(initiator)
|
||||
.setVariables(((ExecutionEntityImpl) event.getEntity()).getVariables())
|
||||
.setVariables(removeBpmnConstantsVariables(((ExecutionEntityImpl) event.getEntity()).getVariables()))
|
||||
.setStartTime(((ExecutionEntityImpl) event.getEntity()).getStartTime())
|
||||
.setTenantId(((ExecutionEntityImpl) event.getEntity()).getTenantId())
|
||||
.setBusinessKey(((ExecutionEntityImpl) event.getEntity()).getBusinessKey())
|
||||
@ -117,7 +117,7 @@ public class RocketMqBpmnProcessEventListener extends AbstractBpmnEventListener<
|
||||
.setProcessDefinitionKey(((ExecutionEntityImpl) event.getEntity()).getProcessDefinitionKey())
|
||||
.setProcessDefinitionVersion(((ExecutionEntityImpl) event.getEntity()).getProcessDefinitionVersion())
|
||||
.setInitiator(initiator)
|
||||
.setVariables(((ExecutionEntityImpl) event.getEntity()).getVariables())
|
||||
.setVariables(removeBpmnConstantsVariables(((ExecutionEntityImpl) event.getEntity()).getVariables()))
|
||||
.setStartTime(((ExecutionEntityImpl) event.getEntity()).getStartTime())
|
||||
.setTenantId(((ExecutionEntityImpl) event.getEntity()).getTenantId())
|
||||
.setBusinessKey(((ExecutionEntityImpl) event.getEntity()).getProcessInstance().getBusinessKey())
|
||||
@ -151,7 +151,7 @@ public class RocketMqBpmnProcessEventListener extends AbstractBpmnEventListener<
|
||||
.setInitiator(initiator)
|
||||
.setLastOperationAssigner(getContext().getLastOperationAssigner(() -> BpmnTaskDelegateAssigner.toObjectCompatible(
|
||||
runtimeService.getVariable(event.getProcessInstanceId(), CLOSE_PROCESS_ASSIGNER, BpmnTaskDelegateAssigner.class))))
|
||||
.setVariables(((FlowableProcessCancelledEventImpl) event).getExecution().getVariables())
|
||||
.setVariables(removeBpmnConstantsVariables(((FlowableProcessCancelledEventImpl) event).getExecution().getVariables()))
|
||||
.setStartTime(((ExecutionEntityImpl) ((FlowableProcessCancelledEventImpl) event).getExecution()).getStartTime())
|
||||
.setTenantId(((FlowableProcessCancelledEventImpl) event).getExecution().getTenantId())
|
||||
.setBusinessKey(((FlowableProcessCancelledEventImpl) event).getExecution().getProcessInstanceBusinessKey())
|
||||
@ -192,7 +192,7 @@ public class RocketMqBpmnProcessEventListener extends AbstractBpmnEventListener<
|
||||
.setInitiator(initiator)
|
||||
.setLastOperationAssigner(getContext().getLastOperationAssigner(() -> BpmnTaskDelegateAssigner.toObjectCompatible(
|
||||
runtimeService.getVariable(event.getProcessInstanceId(), CLOSE_PROCESS_ASSIGNER, BpmnTaskDelegateAssigner.class))))
|
||||
.setVariables(((FlowableProcessCancelledEventImpl) event).getExecution().getVariables())
|
||||
.setVariables(removeBpmnConstantsVariables(((FlowableProcessCancelledEventImpl) event).getExecution().getVariables()))
|
||||
.setStartTime(((ExecutionEntityImpl) ((FlowableProcessCancelledEventImpl) event).getExecution()).getStartTime())
|
||||
.setTenantId(((FlowableProcessCancelledEventImpl) event).getExecution().getTenantId())
|
||||
.setBusinessKey(((FlowableProcessCancelledEventImpl) event).getExecution().getProcessInstanceBusinessKey())
|
||||
@ -228,7 +228,7 @@ public class RocketMqBpmnProcessEventListener extends AbstractBpmnEventListener<
|
||||
.setInitiator(initiator)
|
||||
.setLastOperationAssigner(getContext().getLastOperationAssigner(() -> BpmnTaskDelegateAssigner.toObjectCompatible(
|
||||
runtimeService.getVariable(event.getProcessInstanceId(), CLOSE_PROCESS_ASSIGNER, BpmnTaskDelegateAssigner.class))))
|
||||
.setVariables(((FlowableProcessCancelledEventImpl) event).getExecution().getVariables())
|
||||
.setVariables(removeBpmnConstantsVariables(((FlowableProcessCancelledEventImpl) event).getExecution().getVariables()))
|
||||
.setStartTime(((ExecutionEntityImpl) ((FlowableProcessCancelledEventImpl) event).getExecution()).getStartTime())
|
||||
.setTenantId(((FlowableProcessCancelledEventImpl) event).getExecution().getTenantId())
|
||||
.setBusinessKey(((FlowableProcessCancelledEventImpl) event).getExecution().getProcessInstanceBusinessKey())
|
||||
@ -264,7 +264,7 @@ public class RocketMqBpmnProcessEventListener extends AbstractBpmnEventListener<
|
||||
.setInitiator(initiator)
|
||||
.setLastOperationAssigner(getContext().getLastOperationAssigner(() -> BpmnTaskDelegateAssigner.toObjectCompatible(
|
||||
runtimeService.getVariable(event.getProcessInstanceId(), CLOSE_PROCESS_ASSIGNER, BpmnTaskDelegateAssigner.class))))
|
||||
.setVariables(((ExecutionEntityImpl) event.getEntity()).getVariables())
|
||||
.setVariables(removeBpmnConstantsVariables(((ExecutionEntityImpl) event.getEntity()).getVariables()))
|
||||
.setStartTime(((ExecutionEntityImpl) event.getEntity()).getStartTime())
|
||||
.setTenantId(((ExecutionEntityImpl) event.getEntity()).getTenantId())
|
||||
.setBusinessKey(((ExecutionEntityImpl) event.getEntity()).getProcessInstanceBusinessKey())
|
||||
|
||||
@ -3,6 +3,7 @@ package cn.axzo.workflow.server.controller.listener.task;
|
||||
import cn.axzo.nanopart.doc.api.anonymous.DocAnonymousDatabaseApi;
|
||||
import cn.axzo.nanopart.doc.api.index.request.CopyNodeRequest;
|
||||
import cn.axzo.workflow.common.enums.FileTypeEnum;
|
||||
import cn.axzo.workflow.common.model.dto.CustomDocDTO;
|
||||
import cn.axzo.workflow.common.model.dto.SignFileDTO;
|
||||
import cn.axzo.workflow.common.model.dto.VariableObjectDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnSignConf;
|
||||
@ -23,6 +24,7 @@ import cn.axzo.workflow.server.common.util.WpsUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
|
||||
@ -35,10 +37,17 @@ import org.springframework.util.CollectionUtils;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_BASED_FILE_TAG_ORDER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOCS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
||||
|
||||
/**
|
||||
@ -90,17 +99,59 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve
|
||||
processSign.setProcessInstanceId(processInstanceId);
|
||||
processSign.setSignType(signConfig.get().getSignType().getType());
|
||||
processSign.setPendingMessageId(signConfig.get().getSignPendingProperty().getPendingMessageId());
|
||||
|
||||
// 业务自定义文档
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
List<CustomDocDTO> customDocs = Optional.ofNullable(
|
||||
runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class))
|
||||
.orElse(Collections.emptyList());
|
||||
|
||||
if (CollectionUtils.isEmpty(docs)) {
|
||||
processSign.setDocTemplate(Collections.emptyList());
|
||||
processSign.setFileArchive(Collections.emptyList());
|
||||
} else {
|
||||
// 复制基础模板
|
||||
List<SignFileDTO> docTemplates = copyTempTemplate(docs);
|
||||
processSign.setDocTemplate(docTemplates);
|
||||
|
||||
List<SignFileDTO> archives = replaceTemplateVariable(docTemplates, processEngineConfiguration, processInstanceId);
|
||||
processSign.setFileArchive(archives);
|
||||
}
|
||||
if (CollectionUtils.isEmpty(customDocs)) {
|
||||
processSign.setFileArchive(Collections.emptyList());
|
||||
}
|
||||
// 复制基础模板
|
||||
List<SignFileDTO> docTemplates = copyTempTemplate(docs);
|
||||
|
||||
List<SignFileDTO> customDocTemplates = new ArrayList<>();
|
||||
for (CustomDocDTO customDoc : customDocs) {
|
||||
customDocTemplates.add(SignFileDTO.builder()
|
||||
.id(customDoc.getId())
|
||||
.fileName(customDoc.getFileName())
|
||||
.templateName(customDoc.getFileName())
|
||||
.fileTag(customDoc.getFileTag())
|
||||
.fileCode(customDoc.getFileCode())
|
||||
.fileKey(customDoc.getFileKey())
|
||||
.fileType(customDoc.getFileType())
|
||||
.needReplaceVariables(Boolean.TRUE.equals(customDoc.getNeedReplaceVariables()))
|
||||
.build());
|
||||
}
|
||||
List<String> basedFileTagOrder = runtimeService.getVariable(processInstanceId, SIGN_BIZ_BASED_FILE_TAG_ORDER, List.class);
|
||||
if (Objects.nonNull(basedFileTagOrder)) {
|
||||
docTemplates.addAll(customDocTemplates);
|
||||
// 基于 fileTag 排序
|
||||
Map<String, Integer> fileTagOrderMap = IntStream.range(0, basedFileTagOrder.size())
|
||||
.boxed()
|
||||
.collect(Collectors.toMap(basedFileTagOrder::get, i -> i, (a, b) -> a));
|
||||
|
||||
docTemplates.sort(Comparator.comparing(d -> fileTagOrderMap.getOrDefault(d.getFileTag(), Integer.MAX_VALUE)));
|
||||
docTemplates = docTemplates.stream().sorted(Comparator.comparingInt(d -> fileTagOrderMap.getOrDefault(d.getFileTag(), Integer.MAX_VALUE)))
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
// 基于前插还是后插排序
|
||||
String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, String.class);
|
||||
if (Objects.equals("last", customAddType)) {
|
||||
docTemplates.addAll(customDocTemplates);
|
||||
} else {
|
||||
docTemplates.addAll(0, customDocTemplates);
|
||||
}
|
||||
}
|
||||
processSign.setDocTemplate(docTemplates);
|
||||
|
||||
List<SignFileDTO> archives = replaceTemplateVariable(docTemplates, processEngineConfiguration, processInstanceId);
|
||||
processSign.setFileArchive(archives);
|
||||
// 没有可用的文档,但仍然记录库表
|
||||
extAxProcessSignService.save(processSign);
|
||||
}
|
||||
@ -108,20 +159,22 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve
|
||||
private List<SignFileDTO> replaceTemplateVariable(List<SignFileDTO> docTemplates, ProcessEngineConfigurationImpl processEngineConfiguration, String processInstanceId) {
|
||||
List<SignFileDTO> archives = new ArrayList<>();
|
||||
List<VariableObjectDTO> wpsReplaceVariables = wpsUtil.getWpsReplaceVariables(processEngineConfiguration, processInstanceId);
|
||||
docTemplates.forEach(template -> {
|
||||
SignFileDTO signFileDTO = new SignFileDTO();
|
||||
signFileDTO.setId(template.getId());
|
||||
signFileDTO.setFileName(template.getFileName());
|
||||
signFileDTO.setTemplateName(template.getTemplateName());
|
||||
signFileDTO.setFileTag(template.getFileTag());
|
||||
signFileDTO.setFileType(template.getFileType());
|
||||
signFileDTO.setFileCode(template.getFileCode());
|
||||
if (Objects.equals(template.getFileType(), FileTypeEnum.WORD) || Objects.equals(template.getFileType(), FileTypeEnum.EXCEL)) {
|
||||
String fileKey = wpsUtil.wpsFileVariableReplace(wpsReplaceVariables, template.getFileCode(), null, template.getTemplateName() + template.getFileType().getSuffix());
|
||||
signFileDTO.setFileKey(fileKey);
|
||||
}
|
||||
archives.add(signFileDTO);
|
||||
});
|
||||
docTemplates.stream().filter(i -> Boolean.TRUE.equals(i.getNeedReplaceVariables()))
|
||||
.forEach(template -> {
|
||||
SignFileDTO signFileDTO = new SignFileDTO();
|
||||
signFileDTO.setId(template.getId());
|
||||
signFileDTO.setFileName(template.getFileName());
|
||||
signFileDTO.setTemplateName(template.getTemplateName());
|
||||
signFileDTO.setFileTag(template.getFileTag());
|
||||
signFileDTO.setFileType(template.getFileType());
|
||||
signFileDTO.setFileCode(template.getFileCode());
|
||||
signFileDTO.setNeedReplaceVariables(template.getNeedReplaceVariables());
|
||||
if (Objects.equals(template.getFileType(), FileTypeEnum.WORD) || Objects.equals(template.getFileType(), FileTypeEnum.EXCEL)) {
|
||||
String fileKey = wpsUtil.wpsFileVariableReplace(wpsReplaceVariables, template.getFileCode(), template.getFileKey(), template.getTemplateName() + template.getFileType().getSuffix());
|
||||
signFileDTO.setFileKey(fileKey);
|
||||
}
|
||||
archives.add(signFileDTO);
|
||||
});
|
||||
return archives;
|
||||
}
|
||||
|
||||
@ -152,6 +205,7 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve
|
||||
default:
|
||||
break;
|
||||
}
|
||||
signFileDTO.setNeedReplaceVariables(true);
|
||||
files.add(signFileDTO);
|
||||
});
|
||||
return files;
|
||||
|
||||
@ -154,7 +154,7 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene
|
||||
.setInitiator(BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR)))
|
||||
.setApprover(BpmnTaskDelegateAssigner.toObjectCompatible(
|
||||
delegateTask.getVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + delegateTask.getId())))
|
||||
.setVariables(delegateTask.getVariables())
|
||||
.setVariables(removeBpmnConstantsVariables(delegateTask.getVariables()))
|
||||
.setStartTime(delegateTask.getCreateTime())
|
||||
.setTenantId(delegateTask.getTenantId())
|
||||
.setBusinessKey(processInstance.getBusinessKey())
|
||||
|
||||
@ -0,0 +1,240 @@
|
||||
package cn.axzo.workflow.server.controller.web;
|
||||
|
||||
import cn.axzo.framework.domain.data.AssertUtil;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessTaskService;
|
||||
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
|
||||
import cn.axzo.workflow.server.controller.web.bpmn.BpmnProcessInstanceController;
|
||||
import cn.axzo.workflow.server.controller.web.bpmn.BpmnProcessJobController;
|
||||
import cn.axzo.workflow.server.controller.web.bpmn.BpmnProcessTaskController;
|
||||
import cn.axzo.workflow.server.service.AuthCodeService;
|
||||
import cn.axzo.workflow.server.xxljob.DangerSuperOperationJobHandler;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
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.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.StarterConstants.K8S_POD_NAME_SPACE;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
|
||||
|
||||
/**
|
||||
* 用于临时处理审批的一些问题
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-11-18 15:37
|
||||
*/
|
||||
@Slf4j
|
||||
@Controller
|
||||
public class DangerOperationController {
|
||||
@Resource
|
||||
private RuntimeService runtimeService;
|
||||
@Resource
|
||||
private BpmnProcessInstanceController instanceController;
|
||||
@Resource
|
||||
private BpmnProcessTaskController taskController;
|
||||
@Resource
|
||||
private BpmnProcessTaskService taskService;
|
||||
@Resource
|
||||
private BpmnProcessJobController jobController;
|
||||
@Resource
|
||||
private ExtAxProcessLogService processLogService;
|
||||
@Resource
|
||||
private AuthCodeService authCodeService;
|
||||
@Resource
|
||||
private Environment environment;
|
||||
|
||||
// 显示表单页面
|
||||
@GetMapping("/web/process/form")
|
||||
public String showProcessForm(HttpSession session, Model model) {
|
||||
// 检查session中是否已验证授权码
|
||||
Boolean isAuthenticated = (Boolean) session.getAttribute("isAuthenticated");
|
||||
model.addAttribute("isAuthenticated", isAuthenticated != null && isAuthenticated);
|
||||
|
||||
String myPodNamespace = environment.getProperty(K8S_POD_NAME_SPACE);
|
||||
model.addAttribute("apiBaseUrl", StringUtils.hasText(myPodNamespace) ? "/workflow-engine" : "");
|
||||
// 可以在这里添加需要传递到页面的数据
|
||||
return "form"; // 对应templates目录下的form.html
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权码
|
||||
*
|
||||
* @param password
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/web/process/get-auth-code")
|
||||
@ResponseBody
|
||||
public CommonResponse<String> getAuthCode(@RequestParam String password) {
|
||||
if (Objects.equals("WANG+lI648438", password)) {
|
||||
String authCode = authCodeService.generateAuthCode();
|
||||
return CommonResponse.success(authCode);
|
||||
}
|
||||
return CommonResponse.error("密码错误");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户输入的授权码
|
||||
*/
|
||||
@PostMapping("/web/process/validate-auth")
|
||||
public String validateAuthCode(@RequestParam String authCode, HttpSession session, Model model) {
|
||||
if (Objects.equals("WANG+lI648438", authCode) || authCodeService.validateAuthCode(authCode)) {
|
||||
// 验证通过:在session中标记
|
||||
session.setAttribute("isAuthenticated", true);
|
||||
model.addAttribute("isAuthenticated", true);
|
||||
} else {
|
||||
// 验证失败:提示错误
|
||||
model.addAttribute("isAuthenticated", false);
|
||||
model.addAttribute("authError", "授权码无效或已过期,请重新输入");
|
||||
}
|
||||
String myPodNamespace = environment.getProperty(K8S_POD_NAME_SPACE);
|
||||
model.addAttribute("apiBaseUrl", StringUtils.hasText(myPodNamespace) ? "/workflow-engine" : "");
|
||||
return "form"; // 重新显示授权码输入框
|
||||
}
|
||||
|
||||
// 处理表单提交
|
||||
@PostMapping(value = "/web/process/handle")
|
||||
@ResponseBody
|
||||
public CommonResponse<String> handleProcess(@Validated @RequestBody DangerSuperOperationJobHandler.DangerOperationJobParam jobParam, Model model) {
|
||||
|
||||
// 处理表单提交的逻辑
|
||||
log.info("请求参入: {}", JSON.toJSONString(jobParam));
|
||||
|
||||
try {
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(jobParam.getProcessInstanceId()).singleResult();
|
||||
AssertUtil.notNull(processInstance, PROCESS_INSTANCE_NOT_EXISTS);
|
||||
// 这里可以添加实际的业务逻辑,如调用流程引擎API等
|
||||
switch (jobParam.getOperationType()) {
|
||||
case CANCEL:
|
||||
cancelProcessInstance(jobParam);
|
||||
break;
|
||||
case APPROVE:
|
||||
approveTask(jobParam);
|
||||
break;
|
||||
case REJECT:
|
||||
rejectTask(jobParam);
|
||||
break;
|
||||
case ABORT:
|
||||
abortProcessInstance(jobParam);
|
||||
break;
|
||||
case RESUMER_DEADLINE_JOB:
|
||||
resumerDeadlineJob(jobParam);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 可以将处理结果添加到模型中返回给页面
|
||||
model.addAttribute("message", "操作已成功提交");
|
||||
return CommonResponse.success("操作已成功提交");
|
||||
} catch (Exception e) {
|
||||
model.addAttribute("message", "操作失败: " + e.getMessage());
|
||||
return CommonResponse.error("操作失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void resumerDeadlineJob(DangerSuperOperationJobHandler.DangerOperationJobParam jobParam) {
|
||||
jobController.executeDeadLetterJobAction("", jobParam.getProcessInstanceId());
|
||||
}
|
||||
|
||||
private void abortProcessInstance(DangerSuperOperationJobHandler.DangerOperationJobParam jobParam) {
|
||||
instanceController.abortProcessInstance(BpmnProcessInstanceAbortDTO.builder()
|
||||
.processInstanceId(jobParam.getProcessInstanceId())
|
||||
.advice(jobParam.getComment())
|
||||
.build());
|
||||
}
|
||||
|
||||
private void rejectTask(DangerSuperOperationJobHandler.DangerOperationJobParam jobParam) {
|
||||
String personId = jobParam.getPersonId();
|
||||
if (!StringUtils.hasText(personId)) {
|
||||
log.warn("缺少 personId 参数,无法驳回任务");
|
||||
}
|
||||
|
||||
String taskId = null;
|
||||
if (!Objects.equals("0", personId)) {
|
||||
taskId = taskService.findTaskIdByInstanceIdAndPersonId(jobParam.getProcessInstanceId(), jobParam.getPersonId());
|
||||
}
|
||||
|
||||
ExtAxProcessLog query = new ExtAxProcessLog();
|
||||
query.setProcessInstanceId(jobParam.getProcessInstanceId());
|
||||
query.setTaskId(taskId);
|
||||
query.setStatus(PROCESSING.getStatus());
|
||||
List<ExtAxProcessLog> logs = processLogService.genericQuery(query);
|
||||
if (CollectionUtils.isEmpty(logs)) {
|
||||
log.warn("未找到可操作的任务日志,无法驳回任务,processInstanceId={}, personId={}", jobParam.getProcessInstanceId(), jobParam.getPersonId());
|
||||
return;
|
||||
}
|
||||
|
||||
taskController.rejectTask(BpmnTaskAuditDTO.builder()
|
||||
.processInstanceId(jobParam.getProcessInstanceId())
|
||||
.advice(jobParam.getComment())
|
||||
.approver(logs.get(0).getAssigneeFull().get(0))
|
||||
.async(false)
|
||||
.build());
|
||||
}
|
||||
|
||||
private void approveTask(DangerSuperOperationJobHandler.DangerOperationJobParam jobParam) {
|
||||
String personId = jobParam.getPersonId();
|
||||
if (!StringUtils.hasText(personId)) {
|
||||
log.warn("缺少 personId 参数,无法驳回任务");
|
||||
}
|
||||
|
||||
String taskId = null;
|
||||
if (!Objects.equals("0", personId)) {
|
||||
taskId = taskService.findTaskIdByInstanceIdAndPersonId(jobParam.getProcessInstanceId(), jobParam.getPersonId());
|
||||
}
|
||||
|
||||
ExtAxProcessLog query = new ExtAxProcessLog();
|
||||
query.setProcessInstanceId(jobParam.getProcessInstanceId());
|
||||
query.setTaskId(taskId);
|
||||
query.setStatus(PROCESSING.getStatus());
|
||||
List<ExtAxProcessLog> logs = processLogService.genericQuery(query);
|
||||
if (CollectionUtils.isEmpty(logs)) {
|
||||
log.warn("未找到可操作的任务日志,无法驳回任务,processInstanceId={}, personId={}", jobParam.getProcessInstanceId(), jobParam.getPersonId());
|
||||
return;
|
||||
}
|
||||
|
||||
taskController.approveTask(BpmnTaskAuditDTO.builder()
|
||||
.processInstanceId(jobParam.getProcessInstanceId())
|
||||
.advice(jobParam.getComment())
|
||||
.approver(logs.get(0).getAssigneeFull().get(0))
|
||||
.async(false)
|
||||
.build());
|
||||
}
|
||||
|
||||
private void cancelProcessInstance(DangerSuperOperationJobHandler.DangerOperationJobParam jobParam) {
|
||||
String processInstanceId = jobParam.getProcessInstanceId();
|
||||
BpmnTaskDelegateAssigner assigner = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(processInstanceId, INTERNAL_INITIATOR));
|
||||
BpmnProcessInstanceCancelDTO cancelDTO = new BpmnProcessInstanceCancelDTO();
|
||||
cancelDTO.setProcessInstanceId(processInstanceId);
|
||||
cancelDTO.setInitiator(assigner);
|
||||
cancelDTO.setReason(jobParam.getComment());
|
||||
cancelDTO.setAsync(false);
|
||||
instanceController.cancelProcessInstance(cancelDTO);
|
||||
log.info("撤回操作完成");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
package cn.axzo.workflow.server.controller.web;
|
||||
|
||||
import cn.axzo.framework.domain.ServiceException;
|
||||
import cn.axzo.oss.http.api.ServerFileServiceSdk;
|
||||
import cn.axzo.oss.http.model.ServerFileUploadSdkRequest;
|
||||
import cn.axzo.oss.http.model.ServerFileUploadSdkResponse;
|
||||
import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi;
|
||||
import cn.axzo.workflow.common.model.dto.VariableObjectDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
|
||||
@ -14,6 +17,7 @@ import cn.axzo.workflow.core.engine.cmd.CustomGetProcessInstanceVariablesToObjec
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxBpmnFormRelation;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessInstanceService;
|
||||
import cn.axzo.workflow.core.service.ExtAxBpmnFormRelationService;
|
||||
import cn.axzo.workflow.core.service.support.ExpressionConditionCmd;
|
||||
import cn.axzo.workflow.core.service.support.FlowNodeForecastService;
|
||||
import cn.axzo.workflow.form.service.FormDefinitionService;
|
||||
import cn.axzo.workflow.server.common.annotation.RepeatSubmit;
|
||||
@ -23,6 +27,7 @@ import cn.axzo.workflow.server.xxljob.SpecifyProcessInstanceSyncEsJobHandler;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
|
||||
@ -54,6 +59,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -113,6 +120,8 @@ public class TestController {
|
||||
private TaskService taskService;
|
||||
@Resource
|
||||
private SupportRefreshProperties refreshProperties;
|
||||
@Resource
|
||||
private ServerFileServiceSdk serverFileServiceSdk;
|
||||
|
||||
@RepeatSubmit
|
||||
@GetMapping("/test")
|
||||
@ -375,6 +384,14 @@ public class TestController {
|
||||
return CommonResponse.success(value);
|
||||
}
|
||||
|
||||
@GetMapping("/process/expression/testing")
|
||||
public CommonResponse<String> parseProcessExpression(@RequestParam String processInstanceId, @RequestParam String expression) {
|
||||
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
|
||||
// 自定义命令执行表达式
|
||||
Object value = commandExecutor.execute(new ExpressionConditionCmd(runtimeService, processEngineConfiguration, processInstanceId, expression));
|
||||
return CommonResponse.success(Objects.toString(value, ""));
|
||||
}
|
||||
|
||||
@GetMapping("/es/index")
|
||||
public CommonResponse<String> esIndex(@RequestParam String str) {
|
||||
esIndexOperationJobHandler.execute(str);
|
||||
@ -405,5 +422,16 @@ public class TestController {
|
||||
public CommonResponse<String> refreshProperties() {
|
||||
return CommonResponse.success(JSON.toJSONString(refreshProperties));
|
||||
}
|
||||
|
||||
@PostMapping("/server/file/upload")
|
||||
@SneakyThrows
|
||||
public CommonResponse<String> serverFileUpload(@RequestBody ServerFileUploadSdkRequest request) {
|
||||
String filePath = "/Users/wangli/Downloads/锦绣碧湖B区B-1工程模板施工专项方案4-30.docx";
|
||||
byte[] fileBytes = Files.readAllBytes(Paths.get(filePath));
|
||||
request.setFileContent(fileBytes);
|
||||
ServerFileUploadSdkResponse serverFileUploadSdkResponse = serverFileServiceSdk.uploadFile(request);
|
||||
return CommonResponse.success(JSON.toJSONString(serverFileUploadSdkResponse));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
|
||||
import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.dto.CustomDocDTO;
|
||||
import cn.axzo.workflow.common.model.dto.SignFileDTO;
|
||||
import cn.axzo.workflow.common.model.dto.SimpleDocDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.log.LogApproveSearchDTO;
|
||||
@ -21,6 +22,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCre
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceVariablesUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanceSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO;
|
||||
@ -28,6 +30,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverRead
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ProcessDocQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskButtonSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo;
|
||||
import cn.axzo.workflow.common.model.request.form.instance.FormVariablesUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO;
|
||||
@ -66,6 +69,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@ -95,6 +99,7 @@ import java.util.stream.Stream;
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_DOC_ID_NOT_IN_MODEL;
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_DOC_READ_PARAM_ERROR;
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_EXT_LOG_PARAM_ERROR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOCS;
|
||||
import static cn.azxo.framework.common.model.CommonResponse.success;
|
||||
|
||||
/**
|
||||
@ -306,8 +311,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
|
||||
@PutMapping("/status/update")
|
||||
@RepeatSubmit
|
||||
@Override
|
||||
public CommonResponse<Boolean> updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId,
|
||||
@NotNull(message = "状态不能为空") @RequestParam Integer status) {
|
||||
public CommonResponse<Boolean> updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer status) {
|
||||
log.info("获得流程实例 updateProcessStatus===>>>参数:{},{}", processDefinitionId, status);
|
||||
Boolean result = bpmnProcessInstanceService.updateProcessStatus(processDefinitionId, status);
|
||||
return success(result);
|
||||
@ -323,8 +327,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
|
||||
@Operation(summary = "获取审批流程实例的运行图")
|
||||
@GetMapping("/graphical")
|
||||
@Override
|
||||
public CommonResponse<ObjectNode> processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
|
||||
@Nullable @RequestParam(required = false) String tenantId) {
|
||||
public CommonResponse<ObjectNode> processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId) {
|
||||
return success(bpmnProcessInstanceService.getProcessInstanceGraphical(processInstanceId, tenantId));
|
||||
}
|
||||
|
||||
@ -338,8 +341,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
|
||||
@Operation(summary = "获取指定实例的全节点执行顺序推算")
|
||||
@GetMapping("/node/forecasting")
|
||||
@Override
|
||||
public CommonResponse<List<ProcessNodeDetailVO>> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
|
||||
@Nullable String tenantId) {
|
||||
public CommonResponse<List<ProcessNodeDetailVO>> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable String tenantId) {
|
||||
return success(bpmnProcessInstanceService.getProcessInstanceNodeForecast(processInstanceId, tenantId));
|
||||
}
|
||||
|
||||
@ -356,10 +358,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
|
||||
@Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序")
|
||||
@GetMapping("/node/filter/forecasting")
|
||||
@Override
|
||||
public CommonResponse<List<ProcessNodeDetailVO>> processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId,
|
||||
@Nullable @RequestParam(required = false) String tenantId,
|
||||
@RequestParam(required = false, defaultValue = "false") Boolean allNode,
|
||||
@Nullable @RequestParam(required = false) List<String> nodeDefinitionKeys) {
|
||||
public CommonResponse<List<ProcessNodeDetailVO>> processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId, @RequestParam(required = false, defaultValue = "false") Boolean allNode, @Nullable @RequestParam(required = false) List<String> nodeDefinitionKeys) {
|
||||
if (allNode) {
|
||||
return success(bpmnProcessInstanceService.getProcessInstanceNodeForecast(processInstanceId, tenantId));
|
||||
} else {
|
||||
@ -377,13 +376,20 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
|
||||
@Operation(summary = "获取指定流程实例的流程变量")
|
||||
@GetMapping("/cooperation-org")
|
||||
@Override
|
||||
public CommonResponse<Map<String, Object>> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
|
||||
@Nullable String tenantId) {
|
||||
HistoricProcessInstance processInstance = bpmnProcessInstanceService.getProcessInstance(processInstanceId,
|
||||
tenantId, true);
|
||||
public CommonResponse<Map<String, Object>> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable String tenantId) {
|
||||
HistoricProcessInstance processInstance = bpmnProcessInstanceService.getProcessInstance(processInstanceId, tenantId, true);
|
||||
return success(processInstance.getProcessVariables());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Operation(summary = "更新流程实例中的业务自定义变量集合")
|
||||
@PostMapping("/biz/custom/variables/update")
|
||||
public CommonResponse<Boolean> updateProcessBizCustomVariables(@Validated @RequestBody BpmnProcessInstanceVariablesUpdateDTO dto) {
|
||||
log.info("更新流程实例中的业务自定义变量集合 updateProcessBizCustomVariables===>>>参数:{}", JSONUtil.toJsonStr(dto));
|
||||
bpmnProcessInstanceService.overrideProcessVariables(dto);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 枢智业务(审批台账专用)
|
||||
*
|
||||
@ -466,18 +472,10 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
|
||||
}
|
||||
|
||||
private void parseSignatureUrl(BpmnProcessInstanceLogVO log) {
|
||||
List<String> signUrls = log.getTaskDetails().stream()
|
||||
.filter(i -> StringUtils.hasText(i.getTaskId()))
|
||||
.map(BpmnTaskInstanceLogVO::getSignatureUrl)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
List<String> signUrls = log.getTaskDetails().stream().filter(i -> StringUtils.hasText(i.getTaskId())).map(BpmnTaskInstanceLogVO::getSignatureUrl).filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
||||
if (!CollectionUtils.isEmpty(signUrls)) {
|
||||
Map<String, String> ossUrlMap = ListUtils.emptyIfNull(getSignPrivateUrl(signUrls)).stream()
|
||||
.collect(Collectors.toMap(ApiSignUrlDownloadResponse::getFileKey, ApiSignUrlDownloadResponse::getSignUrl, (s, t) -> s));
|
||||
log.getTaskDetails().stream()
|
||||
.filter(i -> StringUtils.hasText(i.getTaskId()))
|
||||
.forEach(i -> i.setSignatureUrl(ossUrlMap.getOrDefault(i.getSignatureUrl(), null)));
|
||||
Map<String, String> ossUrlMap = ListUtils.emptyIfNull(getSignPrivateUrl(signUrls)).stream().collect(Collectors.toMap(ApiSignUrlDownloadResponse::getFileKey, ApiSignUrlDownloadResponse::getSignUrl, (s, t) -> s));
|
||||
log.getTaskDetails().stream().filter(i -> StringUtils.hasText(i.getTaskId())).forEach(i -> i.setSignatureUrl(ossUrlMap.getOrDefault(i.getSignatureUrl(), null)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -509,8 +507,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
|
||||
}
|
||||
ApiSignUrlDownloadRequest ossRequest = new ApiSignUrlDownloadRequest();
|
||||
ossRequest.setFileKeys(fileKeys);
|
||||
Map</*fileKey*/String, /*ossUrl*/ApiSignUrlDownloadResponse> ossUrlMap = RpcExternalUtil.rpcProcessor(() -> serverFileServiceApi.signUrlFetchDownload(ossRequest), "批量获取文件 OSS 地址", ossRequest)
|
||||
.stream().collect(Collectors.toMap(ApiSignUrlDownloadResponse::getFileKey, Function.identity(), (s, t) -> s));
|
||||
Map</*fileKey*/String, /*ossUrl*/ApiSignUrlDownloadResponse> ossUrlMap = RpcExternalUtil.rpcProcessor(() -> serverFileServiceApi.signUrlFetchDownload(ossRequest), "批量获取文件 OSS 地址", ossRequest).stream().collect(Collectors.toMap(ApiSignUrlDownloadResponse::getFileKey, Function.identity(), (s, t) -> s));
|
||||
docs.forEach(i -> {
|
||||
if (StringUtils.hasText(i.getFileKey())) {
|
||||
ApiSignUrlDownloadResponse ossFileInfo = ossUrlMap.getOrDefault(i.getFileKey(), null);
|
||||
@ -542,10 +539,20 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
|
||||
}
|
||||
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
|
||||
List<DocBaseVO> relationDocs = commandExecutor.execute(new CustomGetModelDocsCmd(dto.getProcessInstanceId(), true, extAxModelDocMapper, extAxReModelService));
|
||||
relationDocs.stream().filter(i -> Objects.equals(i.getId(), dto.getDocId()))
|
||||
.findAny().orElseThrow(() -> new WorkflowEngineException(PROCESS_DOC_ID_NOT_IN_MODEL));
|
||||
|
||||
return success(readRecordService.changeReadStatus(dto));
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
List<CustomDocDTO> customDocs = ListUtils.emptyIfNull(runtimeService.getVariable(dto.getProcessInstanceId(), SIGN_BIZ_CUSTOM_DOCS, List.class));
|
||||
|
||||
// 检查 relationDocs 中是否存在具有指定 id 的对象
|
||||
boolean existsInRelationDocs = relationDocs.stream().anyMatch(doc -> Objects.equals(doc.getId(), dto.getDocId()));
|
||||
|
||||
// 检查 customDocs 中是否存在具有指定 id 的对象
|
||||
boolean existsInCustomDocs = customDocs.stream().anyMatch(doc -> Objects.equals(doc.getId(), dto.getDocId()));
|
||||
if (!existsInRelationDocs && !existsInCustomDocs) {
|
||||
throw new WorkflowEngineException(PROCESS_DOC_ID_NOT_IN_MODEL);
|
||||
}
|
||||
|
||||
return success(readRecordService.changeReadStatus(dto, customDocs));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -602,4 +609,17 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
|
||||
return logVO;
|
||||
}).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程实例的条件字段信息
|
||||
*
|
||||
* @param processInstanceId
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "获取流程实例的条件字段信息, 仅用于同意抽屉展示")
|
||||
@GetMapping("/conditions")
|
||||
@Override
|
||||
public CommonResponse<List<ConditionPermissionMetaInfo>> getConditions(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId) {
|
||||
return success(bpmnProcessInstanceService.getConditions(processInstanceId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ import com.alibaba.fastjson.JSON;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.flowable.form.api.FormInfo;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@ -54,6 +55,7 @@ import javax.validation.constraints.NotEmpty;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_OPERATION_PARAM_INVALID;
|
||||
@ -112,6 +114,10 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp
|
||||
if (!StringUtils.hasText(dto.getTaskId())) {
|
||||
dto.setTaskId(bpmnProcessTaskService.findTaskIdByInstanceIdAndPersonId(dto.getProcessInstanceId(), dto.getApprover().getPersonId()));
|
||||
}
|
||||
|
||||
// 移除 variable 中 value 为 null 的 key
|
||||
MapUtils.emptyIfNull(dto.getVariables()).entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||
|
||||
List<AttachmentDTO> tempAttachments = ListUtils.defaultIfNull(dto.getAttachmentList(), new ArrayList<>());
|
||||
if (StringUtils.hasText(dto.getSignatureUrl())) {
|
||||
AttachmentDTO signature = new AttachmentDTO();
|
||||
@ -138,6 +144,10 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp
|
||||
if (!StringUtils.hasText(dto.getTaskId())) {
|
||||
dto.setTaskId(bpmnProcessTaskService.findTaskIdByInstanceIdAndPersonId(dto.getProcessInstanceId(), dto.getApprover().getPersonId()));
|
||||
}
|
||||
|
||||
// 移除 variable 中 value 为 null 的 key
|
||||
MapUtils.emptyIfNull(dto.getVariables()).entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||
|
||||
List<AttachmentDTO> tempAttachments = ListUtils.defaultIfNull(dto.getAttachmentList(), new ArrayList<>());
|
||||
if (StringUtils.hasText(dto.getSignatureUrl())) {
|
||||
AttachmentDTO signature = new AttachmentDTO();
|
||||
|
||||
@ -1,47 +1,79 @@
|
||||
package cn.axzo.workflow.server.controller.web.manage;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.maokai.api.client.OrganizationalNodeUserQueryApi;
|
||||
import cn.axzo.maokai.api.vo.request.OrgNodeUserBriefInfoListReq;
|
||||
import cn.axzo.maokai.api.vo.response.OrgNodeUserBriefInfoResp;
|
||||
import cn.axzo.nanopart.doc.api.conversion.DocConversionApi;
|
||||
import cn.axzo.nanopart.doc.api.conversion.req.QueryConversionTaskRequestV2;
|
||||
import cn.axzo.nanopart.doc.api.conversion.req.SubmitConversionTaskRequest;
|
||||
import cn.axzo.nanopart.doc.api.conversion.res.FileConvertResultResp;
|
||||
import cn.axzo.nanopart.doc.api.enums.DocConversionTypeEnum;
|
||||
import cn.axzo.oss.http.api.ServerFileServiceApi;
|
||||
import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
|
||||
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
|
||||
import cn.axzo.workflow.client.feign.manage.PrintAdminApi;
|
||||
import cn.axzo.workflow.common.constant.VariableConstants;
|
||||
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.enums.VarTypeEnum;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.dto.print.FieldAttributeDTO;
|
||||
import cn.axzo.workflow.common.model.dto.print.PrintFieldDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.print.Print4ProcessLogDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.print.PrintFieldQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.print.PrintProcessLogPdfDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.print.PrintTemplateConfigUpsertDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.print.QueryProcessLogPdfDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.common.model.request.category.CategoryGroupVarSearchDto;
|
||||
import cn.axzo.workflow.common.model.response.ProcessLogItemDTO;
|
||||
import cn.axzo.workflow.common.model.response.TableItemDTO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.PrintData4LogVO;
|
||||
import cn.axzo.workflow.common.model.response.category.CategoryGroupVarItemVo;
|
||||
import cn.axzo.workflow.common.model.response.print.ProcessLogPdfResultDTO;
|
||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||
import cn.axzo.workflow.core.conf.SupportRefreshProperties;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomGetFormInstanceLatestValuesCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomGetFormModelByProcessInstanceIdCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomGetProcessInstanceVariablesCmd;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessDefinitionService;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessInstanceService;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessModelService;
|
||||
import cn.axzo.workflow.core.service.CategoryGroupService;
|
||||
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
|
||||
import cn.axzo.workflow.server.common.annotation.ErrorReporter;
|
||||
import cn.axzo.workflow.server.common.util.RpcExternalUtil;
|
||||
import cn.axzo.workflow.server.controller.web.bpmn.BpmnProcessInstanceController;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.collect.Lists;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.engine.task.Attachment;
|
||||
import org.flowable.form.api.FormInfo;
|
||||
import org.flowable.form.api.FormRepositoryService;
|
||||
import org.flowable.form.model.FormContainer;
|
||||
import org.flowable.form.model.FormField;
|
||||
import org.flowable.form.model.FormFieldTypes;
|
||||
import org.flowable.form.model.Option;
|
||||
import org.flowable.form.model.OptionFormField;
|
||||
import org.flowable.form.model.SimpleFormModel;
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@ -66,6 +98,7 @@ import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.code.FormModelRespCode.FORM_MODEL_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.code.OtherRespCode.CANT_GENERATE_PROCESS_LOG_PDF;
|
||||
import static cn.axzo.workflow.common.constant.FormConstants.FORM_FIELD_TYPE_IMAGE;
|
||||
import static cn.axzo.workflow.common.constant.FormConstants.FORM_FIELD_TYPE_INPUT;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_DEFINITION_KEY;
|
||||
@ -79,16 +112,24 @@ import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCE
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_PHONE_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_POSITION;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_POSITION_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_UNIT;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INSTANCE_ID;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INSTANCE_ID_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOGS;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOGS_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_NODE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ADVICE;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ADVICE_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_APPROVER_NAME;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_APPROVER_NAME_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_OPERATION;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_OPERATION_TIME;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_OPERATION_TIME_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_POSITION;
|
||||
@ -97,12 +138,15 @@ import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCE
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_SIGNATURE_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_UNIT;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_UNIT_DESC;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_NAME;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_RESULT;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_START_TIME;
|
||||
import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_START_TIME_DESC;
|
||||
import static cn.axzo.workflow.common.enums.PrintFieldCategoryEnum.form;
|
||||
import static cn.axzo.workflow.common.enums.PrintFieldCategoryEnum.sign;
|
||||
import static cn.axzo.workflow.common.enums.PrintFieldCategoryEnum.signature;
|
||||
import static cn.axzo.workflow.common.enums.PrintFieldCategoryEnum.system;
|
||||
import static cn.axzo.workflow.core.service.impl.BpmnProcessInstanceServiceImpl.getAttachmentByType;
|
||||
import static cn.azxo.framework.common.model.CommonResponse.success;
|
||||
|
||||
/**
|
||||
@ -111,13 +155,13 @@ import static cn.azxo.framework.common.model.CommonResponse.success;
|
||||
* @author wangli
|
||||
* @since 2025-01-16 17:48
|
||||
*/
|
||||
@Slf4j
|
||||
@RequestMapping({"/web/v1/api/print/admin", "/api/print/admin"})
|
||||
@RestController
|
||||
@ErrorReporter
|
||||
@Validated
|
||||
public class PrintAdminController implements PrintAdminApi {
|
||||
|
||||
private static final Logger log = org.slf4j.LoggerFactory.getLogger(PrintAdminController.class);
|
||||
@Resource
|
||||
private FormRepositoryService formRepositoryService;
|
||||
@Resource
|
||||
@ -134,6 +178,18 @@ public class PrintAdminController implements PrintAdminApi {
|
||||
private CategoryGroupService categoryGroupService;
|
||||
@Resource
|
||||
private BpmnProcessModelService bpmnProcessModelService;
|
||||
@Resource
|
||||
private ExtAxProcessLogService processLogService;
|
||||
@Resource
|
||||
private TaskService taskService;
|
||||
@Resource
|
||||
private ServerFileServiceApi serverFileServiceApi;
|
||||
@Resource
|
||||
private DocConversionApi docConversionApi;
|
||||
@Resource
|
||||
private SupportRefreshProperties refreshProperties;
|
||||
@Resource
|
||||
private RuntimeService runtimeService;
|
||||
|
||||
/**
|
||||
* 查询指定流程实例是否能使用打印
|
||||
@ -162,6 +218,7 @@ public class PrintAdminController implements PrintAdminApi {
|
||||
bpmnProcessModelService.printTemplateConfig(dto);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取打印模板中可打印的字段, 或者是 WPS 模板中可配置的变量字段
|
||||
*
|
||||
@ -180,17 +237,29 @@ public class PrintAdminController implements PrintAdminApi {
|
||||
List<FormField> formFields = ((SimpleFormModel) formModel.getFormModel()).getFields();
|
||||
formFields.forEach(formField -> {
|
||||
FormContainer formContainer = (FormContainer) formField;
|
||||
printFields.addAll(formContainer.getFields().get(0).stream().map(field -> {
|
||||
PrintFieldDTO printFieldDTO = new PrintFieldDTO()
|
||||
.setName(field.getName())
|
||||
.setCode(field.getId())
|
||||
.setFieldCategoryType(form)
|
||||
.setFieldFormType(field.getType());
|
||||
switchAmount(field, printFieldDTO);
|
||||
switchFormContainer(field, printFieldDTO);
|
||||
return printFieldDTO;
|
||||
}
|
||||
).collect(Collectors.toList()));
|
||||
printFields.addAll(formContainer.getFields().get(0).stream()
|
||||
.filter(field -> {
|
||||
// if (Objects.equals(Boolean.TRUE, dto.getFilterEnablePrint())) {
|
||||
if (!CollectionUtils.isEmpty(field.getParams())) {
|
||||
Optional<Object> optEnablePrint = Optional.ofNullable(field.getParam("enablePrint"));
|
||||
return optEnablePrint.map(obj -> Boolean.parseBoolean(obj.toString())).orElse(Boolean.TRUE);
|
||||
}
|
||||
return true;
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
})
|
||||
.map(field -> {
|
||||
PrintFieldDTO printFieldDTO = new PrintFieldDTO()
|
||||
.setName(field.getName())
|
||||
.setCode(field.getId())
|
||||
.setFieldCategoryType(form)
|
||||
.setFieldFormType(field.getType());
|
||||
switchAmount(field, printFieldDTO);
|
||||
switchFormContainer(field, printFieldDTO);
|
||||
return printFieldDTO;
|
||||
}
|
||||
).collect(Collectors.toList()));
|
||||
});
|
||||
} catch (FlowableObjectNotFoundException e) {
|
||||
log.warn("can't found form model");
|
||||
@ -305,8 +374,13 @@ public class PrintAdminController implements PrintAdminApi {
|
||||
.setCode(activity.getId())
|
||||
.setFieldCategoryType(signature)
|
||||
.setFieldFormType("signature")
|
||||
.setAttributes(Lists.newArrayList(new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_SIGNATURE).setName(PRINT_VAR_PROCESS_LOG_SIGNATURE_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT),
|
||||
new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_ADVICE).setName(PRINT_VAR_PROCESS_LOG_ADVICE_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT))))
|
||||
.setAttributes(Lists.newArrayList(
|
||||
new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_APPROVER_NAME).setName(PRINT_VAR_PROCESS_LOG_APPROVER_NAME_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT),
|
||||
new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT).setName(PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT),
|
||||
new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_ADVICE).setName(PRINT_VAR_PROCESS_LOG_ADVICE_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT),
|
||||
new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_SIGNATURE).setName(PRINT_VAR_PROCESS_LOG_SIGNATURE_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT),
|
||||
new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME).setName(PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT)
|
||||
)))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
@ -335,21 +409,30 @@ public class PrintAdminController implements PrintAdminApi {
|
||||
// 生成系统字段的变量
|
||||
generateSystemFieldVariables(processInstanceId, result);
|
||||
|
||||
FormInfo formInfo = commandExecutor.execute(new CustomGetFormModelByProcessInstanceIdCmd(processInstanceId));
|
||||
// 将所有变量都转换成 JSON 对象返回
|
||||
convertValueToObject(result);
|
||||
convertValueToObject(result, formInfo);
|
||||
return success(result);
|
||||
}
|
||||
|
||||
private void convertValueToObject(Map<String, Object> result) {
|
||||
if (CollectionUtils.isEmpty(result)) {
|
||||
private void convertValueToObject(Map<String, Object> result, FormInfo formInfo) {
|
||||
if (CollectionUtils.isEmpty(result) || Objects.isNull(formInfo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, FormField> stringFormFieldMap = ((SimpleFormModel) formInfo.getFormModel()).allFieldsAsMap();
|
||||
result.forEach((key, value) -> {
|
||||
if (!(value instanceof String)) {
|
||||
return;
|
||||
}
|
||||
if (((String) value).startsWith("[")) {
|
||||
|
||||
if (stringFormFieldMap.containsKey(key) && stringFormFieldMap.get(key) instanceof OptionFormField) {
|
||||
OptionFormField optionFormField = (OptionFormField) stringFormFieldMap.get(key);
|
||||
if (Objects.equals("checkbox", optionFormField.getType())) {
|
||||
result.put(key, buildOptionFieldValue(optionFormField, JSONObject.parseArray((String) value, String.class)));
|
||||
} else if (Objects.equals("radio", optionFormField.getType())) {
|
||||
result.put(key, buildOptionFieldValue(optionFormField, Lists.newArrayList((String) value)));
|
||||
}
|
||||
} else if (((String) value).startsWith("[")) {
|
||||
result.put(key, JSONArray.parseArray((String) value));
|
||||
} else if (((String) value).startsWith("{")) {
|
||||
result.put(key, JSONObject.parseObject((String) value));
|
||||
@ -357,6 +440,16 @@ public class PrintAdminController implements PrintAdminApi {
|
||||
});
|
||||
}
|
||||
|
||||
private String buildOptionFieldValue(OptionFormField optionFormField, List<String> selectedValues) {
|
||||
if (CollectionUtils.isEmpty(optionFormField.getOptions())) {
|
||||
return "";
|
||||
}
|
||||
return optionFormField.getOptions().stream()
|
||||
.filter(i -> selectedValues.contains(i.getId()))
|
||||
.map(Option::getName)
|
||||
.collect(Collectors.joining(";"));
|
||||
}
|
||||
|
||||
private void generateSystemFieldVariables(String processInstanceId, Map<String, Object> result) {
|
||||
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
|
||||
Map<String, Object> variables = commandExecutor.execute(new CustomGetProcessInstanceVariablesCmd(processInstanceId));
|
||||
@ -368,6 +461,7 @@ public class PrintAdminController implements PrintAdminApi {
|
||||
variables.put(PRINT_VAR_PROCESS_INITIATOR_NAME, user.isPresent() ? user.get().getRealName() : "");
|
||||
variables.put(PRINT_VAR_PROCESS_INITIATOR_POSITION, user.isPresent() && Objects.nonNull(user.get().getJob()) ? user.get().getJob().getName() : "");
|
||||
variables.put(PRINT_VAR_PROCESS_INITIATOR_PHONE, user.isPresent() ? user.get().getProfile().getPhone() : "");
|
||||
variables.put(PRINT_VAR_PROCESS_INITIATOR_UNIT, user.isPresent() ? user.get().getOrganizationalUnitName() : "");
|
||||
variables.remove(PRINT_VAR_PROCESS_INITIATOR);
|
||||
}
|
||||
// 填充审批日志
|
||||
@ -383,11 +477,14 @@ public class PrintAdminController implements PrintAdminApi {
|
||||
.forEach(taskLog -> {
|
||||
Map<String, Object> taskLogMap = new HashMap<>();
|
||||
taskLogMap.put(PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME, taskLog.getName());
|
||||
taskLogMap.put(PRINT_VAR_PROCESS_LOG_ACTIVITY_NODE_TYPE, taskLog.getNodeType().getType());
|
||||
Optional<OrgNodeUserBriefInfoResp> user = getUserInfo(taskLog.getAssigneeSnapshot());
|
||||
taskLogMap.put(PRINT_VAR_PROCESS_LOG_APPROVER_NAME, user.isPresent() ? user.get().getRealName() : "");
|
||||
taskLogMap.put(PRINT_VAR_PROCESS_LOG_UNIT, user.isPresent() ? user.get().getOrganizationalUnitName() : "");
|
||||
taskLogMap.put(PRINT_VAR_PROCESS_LOG_POSITION, user.isPresent() && Objects.nonNull(user.get().getJob()) ? user.get().getJob().getName() : "");
|
||||
taskLogMap.put(PRINT_VAR_PROCESS_LOG_ADVICE, taskLog.getAdvice());
|
||||
taskLogMap.put(PRINT_VAR_PROCESS_LOG_OPERATION, taskLog.getOperationDesc());
|
||||
taskLogMap.put(PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT, taskLog.getResult().getStatus());
|
||||
taskLogMap.put(PRINT_VAR_PROCESS_LOG_OPERATION_TIME, sdf.format(taskLog.getCreateTime()));
|
||||
taskLogMap.put(PRINT_VAR_PROCESS_LOG_SIGNATURE, taskLog.getSignatureUrl());
|
||||
taskLogs.add(taskLogMap);
|
||||
@ -427,4 +524,130 @@ public class PrintAdminController implements PrintAdminApi {
|
||||
return users.stream().sorted(Comparator.comparing(OrgNodeUserBriefInfoResp::getExited).reversed())
|
||||
.collect(Collectors.toList()).stream().findFirst();
|
||||
}
|
||||
|
||||
@Operation(summary = "获取用于打印审批日志公共模板的数据")
|
||||
@PostMapping("/process/log/data/v2")
|
||||
@Override
|
||||
public CommonResponse<PrintData4LogVO> getPrintDataForProcessLog(@Validated @RequestBody Print4ProcessLogDTO dto) {
|
||||
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
|
||||
Map<String, Object> variables = commandExecutor.execute(new CustomGetProcessInstanceVariablesCmd(dto.getProcessInstanceId()));
|
||||
|
||||
PrintData4LogVO vo = new PrintData4LogVO();
|
||||
vo.setProcessName((String) variables.getOrDefault(PRINT_VAR_PROCESS_NAME, ""));
|
||||
vo.setTenantName(String.valueOf(variables.get(VariableConstants.PRINT_VAR_PROCESS_BELONG_TENANT_ID)));
|
||||
vo.setCreateAt(String.valueOf(variables.get(VariableConstants.PRINT_VAR_PROCESS_START_TIME)));
|
||||
vo.setResult((BpmnProcessInstanceResultEnum) variables.get(PRINT_VAR_PROCESS_RESULT));
|
||||
|
||||
List<TableItemDTO> systemVarItems = new ArrayList<>();
|
||||
systemVarItems.add(TableItemDTO.builder()
|
||||
.label(PRINT_VAR_PROCESS_INSTANCE_ID_DESC)
|
||||
.code(PRINT_VAR_PROCESS_INSTANCE_ID)
|
||||
.type(FORM_FIELD_TYPE_INPUT)
|
||||
.value(variables.get(PRINT_VAR_PROCESS_INSTANCE_ID))
|
||||
.build());
|
||||
|
||||
// 解析发起人
|
||||
BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(variables.getOrDefault(PRINT_VAR_PROCESS_INITIATOR, null));
|
||||
if (Objects.nonNull(initiator)) {
|
||||
Optional<OrgNodeUserBriefInfoResp> user = getUserInfo(initiator);
|
||||
systemVarItems.add(TableItemDTO.builder()
|
||||
.label(PRINT_VAR_PROCESS_INITIATOR_NAME_DESC)
|
||||
.code(PRINT_VAR_PROCESS_INITIATOR_NAME)
|
||||
.type(FORM_FIELD_TYPE_INPUT)
|
||||
.value(user.isPresent() ? user.get().getRealName() : "")
|
||||
.build());
|
||||
systemVarItems.add(TableItemDTO.builder()
|
||||
.label(PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC)
|
||||
.code(PRINT_VAR_PROCESS_INITIATOR_UNIT)
|
||||
.type(FORM_FIELD_TYPE_INPUT)
|
||||
.value(user.isPresent() ? user.get().getOrganizationalUnitName() : "")
|
||||
.build());
|
||||
}
|
||||
|
||||
vo.setSystemVarItems(systemVarItems);
|
||||
|
||||
// 审批日志
|
||||
List<ProcessLogItemDTO> logItems = new ArrayList<>();
|
||||
Map<String, List<Attachment>> attachmentByTaskMap =
|
||||
taskService.getProcessInstanceAttachments(dto.getProcessInstanceId()).stream()
|
||||
.collect(Collectors.groupingBy(Attachment::getTaskId));
|
||||
ExtAxProcessLog query = new ExtAxProcessLog();
|
||||
query.setProcessInstanceId(dto.getProcessInstanceId());
|
||||
// TODO 这里可能需要结合节点隐藏来过滤
|
||||
processLogService.genericQuery(query).stream()
|
||||
.sorted(Comparator.comparing(ExtAxProcessLog::getEndTime, Comparator.nullsLast(Comparator.naturalOrder())))
|
||||
.collect(Collectors.toList())
|
||||
.forEach(log -> {
|
||||
logItems.add(ProcessLogItemDTO.builder()
|
||||
.advice(log.getAdvice())
|
||||
.activityName(log.getActivityName())
|
||||
.operationDesc(log.getOperationDesc())
|
||||
.imageList(getAttachmentByType(attachmentByTaskMap, log.getTaskId(), AttachmentTypeEnum.image))
|
||||
.fileList(getAttachmentByType(attachmentByTaskMap, log.getTaskId(), AttachmentTypeEnum.file))
|
||||
.signatureUrl(getAttachmentByType(attachmentByTaskMap, log.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl())
|
||||
.operationTime(DateUtil.format(log.getEndTime(), "yyyy.MM.dd HH:mm:ss"))
|
||||
.result(log.getStatus())
|
||||
.build());
|
||||
});
|
||||
parseSignatureUrl(logItems);
|
||||
vo.setLogItems(logItems);
|
||||
|
||||
return success(vo);
|
||||
}
|
||||
|
||||
|
||||
private void parseSignatureUrl(List<ProcessLogItemDTO> logItems) {
|
||||
List<String> signUrls = logItems.stream()
|
||||
.map(ProcessLogItemDTO::getSignatureUrl)
|
||||
.filter(StringUtils::hasText)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
if (!CollectionUtils.isEmpty(signUrls)) {
|
||||
Map<String, String> ossUrlMap = ListUtils.emptyIfNull(getSignPrivateUrl(signUrls)).stream()
|
||||
.collect(Collectors.toMap(ApiSignUrlDownloadResponse::getFileKey, ApiSignUrlDownloadResponse::getSignUrl, (s, t) -> s));
|
||||
logItems.stream()
|
||||
.filter(i -> StringUtils.hasText(i.getSignatureUrl()))
|
||||
.forEach(i -> i.setSignatureUrl(ossUrlMap.getOrDefault(i.getSignatureUrl(), null)));
|
||||
}
|
||||
}
|
||||
|
||||
private List<ApiSignUrlDownloadResponse> getSignPrivateUrl(List<String> signUrls) {
|
||||
ApiSignUrlDownloadRequest request = new ApiSignUrlDownloadRequest();
|
||||
request.setFileKeys(signUrls);
|
||||
return RpcExternalUtil.rpcProcessor(() -> serverFileServiceApi.signUrlFetchDownload(request), "批量获取手写签私有访问地址", request);
|
||||
}
|
||||
|
||||
@Operation(summary = "后端请求指定流程日志 PDF 文件生成")
|
||||
@PostMapping("/process/log/pdf")
|
||||
@Override
|
||||
public CommonResponse<String> createProcessLogPdf(@Validated @RequestBody PrintProcessLogPdfDTO dto) {
|
||||
if (!StringUtils.hasText(dto.getBizCode())) {
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(dto.getProcessInstanceId()).singleResult();
|
||||
if (Objects.nonNull(processInstance)) {
|
||||
throw new WorkflowEngineException(CANT_GENERATE_PROCESS_LOG_PDF);
|
||||
}
|
||||
}
|
||||
SubmitConversionTaskRequest request = new SubmitConversionTaskRequest();
|
||||
request.setBizCode(StringUtils.hasText(dto.getBizCode()) ? dto.getBizCode() : "workflow-process-log");
|
||||
request.setBizKey(StringUtils.hasText(dto.getBizKey()) ? dto.getBizKey() : dto.getProcessInstanceId() + ":" + dto.getPersonId());
|
||||
request.setConversionType(DocConversionTypeEnum.HTML_URL_TO_PDF);
|
||||
request.setFileName(String.format(refreshProperties.getProcessLogHtmlUrl(), dto.getProcessInstanceId(), dto.getPersonId()));
|
||||
String taskId = RpcExternalUtil.rpcApiResultProcessor(() -> docConversionApi.submitConvertTask(request), "创建网页转 PDF 的异步任务", request);
|
||||
return CommonResponse.success(taskId);
|
||||
}
|
||||
|
||||
@Operation(summary = "后端查询指定审批日志 PDF 文件的生成结果")
|
||||
@PostMapping("/process/log/pdf/result")
|
||||
@Override
|
||||
public CommonResponse<ProcessLogPdfResultDTO> queryProcessLogPdfResult(@Validated @RequestBody QueryProcessLogPdfDTO dto) {
|
||||
QueryConversionTaskRequestV2 request = new QueryConversionTaskRequestV2();
|
||||
request.setBizCode(StringUtils.hasText(dto.getBizCode()) ? dto.getBizCode() : "workflow-process-log");
|
||||
request.setBizKeys(Lists.newArrayList(StringUtils.hasText(dto.getBizKey()) ? dto.getBizKey() : dto.getProcessInstanceId() + ":" + dto.getPersonId()));
|
||||
List<FileConvertResultResp> taskConvertResults = RpcExternalUtil.rpcApiResultProcessor(() -> docConversionApi.queryConvertResultByBiz(request), "查询流程日志转 PDF 的结果", request);
|
||||
List<ProcessLogPdfResultDTO> results = BeanMapper.copyList(taskConvertResults, ProcessLogPdfResultDTO.class, (s, t) -> {
|
||||
t.setPdfFileKey(s.getResultFileFileKey());
|
||||
t.setStatus(s.getStatus().name());
|
||||
});
|
||||
return CommonResponse.success(results.isEmpty() ? null : results.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@ import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@ -52,18 +53,24 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_BACK_COUNTERSIGN;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_FORWARD_COUNTERSIGN;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SUPPORT_UPGRADE_VARIABLE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN;
|
||||
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.nobody;
|
||||
import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.BACK_COUNTERSIGN;
|
||||
import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.GENERAL;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.OR;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.HIDDEN;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.HANDLING;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getActivitySignature;
|
||||
@ -152,9 +159,17 @@ public class TaskEntityEventHandle implements EntityEventHandle<TaskEntity> {
|
||||
} else {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<BpmnTaskDelegateAssigner> assigneeList = runtimeService.getVariable(taskEntity.getProcessInstanceId(),
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(), List.class);
|
||||
List<BpmnTaskDelegateAssigner> assigneeList = new ArrayList<>();
|
||||
if (Objects.equals(FORWARD_COUNTERSIGN.getType(), taskEntity.getScopeType())) {
|
||||
assigneeList.addAll(runtimeService.getVariable(taskEntity.getProcessInstanceId(),
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + INTERNAL_ACTIVITY_FORWARD_COUNTERSIGN + taskEntity.getParentTaskId(), List.class));
|
||||
} else if (Objects.equals(BACK_COUNTERSIGN.getType(), taskEntity.getScopeType())) {
|
||||
assigneeList.addAll(runtimeService.getVariable(taskEntity.getProcessInstanceId(),
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + INTERNAL_ACTIVITY_BACK_COUNTERSIGN + taskEntity.getParentTaskId(), List.class));
|
||||
} else {
|
||||
assigneeList.addAll(runtimeService.getVariable(taskEntity.getProcessInstanceId(),
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(), List.class));
|
||||
}
|
||||
ListUtils.emptyIfNull(assigneeList).stream().filter(e -> Objects.equals(e.buildAssigneeId(), taskEntity.getAssignee())).findAny()
|
||||
.ifPresent(assignee -> {
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
@ -283,12 +298,18 @@ public class TaskEntityEventHandle implements EntityEventHandle<TaskEntity> {
|
||||
String completionType = taskEntity.getVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), String.class);
|
||||
if (StringUtils.hasText(completionType) && !Objects.equals(DELETED.getStatus(), completionType)) {
|
||||
update.setStatus(completionType);
|
||||
Boolean hiddenLog = taskEntity.getVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + taskEntity.getTaskDefinitionKey(), Boolean.class);
|
||||
if (Objects.equals(hiddenLog, Boolean.TRUE)) {
|
||||
update.setStatus(HIDDEN.getStatus());
|
||||
}
|
||||
} else {
|
||||
// 多实例除操作人以外的任务,直接删除日志, 例如一个节点有两个人或签,A 人驳回了,那么 B 人不再需要操作,任务自动删除。而会签也同理
|
||||
update.setStatus(DELETED.getStatus());// delete标志着是多实例删除
|
||||
needDelete = true;
|
||||
}
|
||||
}
|
||||
// 重置日志隐藏的标识为 false
|
||||
taskEntity.removeVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + taskEntity.getTaskDefinitionKey());
|
||||
update.setEndTime(new Date());
|
||||
|
||||
// 判断是否抄送节点,如果是的话,需要将抄送人集合放入对应字段
|
||||
|
||||
@ -0,0 +1,125 @@
|
||||
package cn.axzo.workflow.server.initializer;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||
import cn.axzo.workflow.core.engine.cmd.helper.CustomBpmnModelHelper;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord;
|
||||
import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
|
||||
|
||||
/**
|
||||
* 在框架提供 Web 服务前,恢复动态前后加签的流程实例的内存中的模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-10-17 17:43
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RecoverDynamicCounterSignProcess implements SmartLifecycle {
|
||||
private final ExtAxDynamicSignRecordService extAxDynamicSignRecordService;
|
||||
private final SpringProcessEngineConfiguration springProcessEngineConfiguration;
|
||||
private boolean isRunning = false;
|
||||
|
||||
public RecoverDynamicCounterSignProcess(ExtAxDynamicSignRecordService extAxDynamicSignRecordService,
|
||||
SpringProcessEngineConfiguration springProcessEngineConfiguration) {
|
||||
this.extAxDynamicSignRecordService = extAxDynamicSignRecordService;
|
||||
this.springProcessEngineConfiguration = springProcessEngineConfiguration;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// 恢复动态会签中的流程实例
|
||||
log.info("executing before web server start");
|
||||
// 查询有过加签的审批实例
|
||||
List<ExtAxDynamicSignRecord> list = extAxDynamicSignRecordService.list();
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RuntimeService runtimeService = springProcessEngineConfiguration.getRuntimeService();
|
||||
// 获取还在审批中的实例
|
||||
Set<String> processInstanceIds = list.stream().map(ExtAxDynamicSignRecord::getProcessInstanceId).collect(Collectors.toSet());
|
||||
Set<String> runningProcessIds = runtimeService.createProcessInstanceQuery()
|
||||
.processInstanceIds(processInstanceIds)
|
||||
.active()
|
||||
.list().stream().map(ProcessInstance::getProcessInstanceId).collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(runningProcessIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, List<ExtAxDynamicSignRecord>> grouped = list.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
ExtAxDynamicSignRecord::getProcessInstanceId,
|
||||
Collectors.collectingAndThen(
|
||||
Collectors.toList(),
|
||||
l -> {
|
||||
l.sort(Comparator.comparing(
|
||||
ExtAxDynamicSignRecord::getCreateAt,
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())
|
||||
));
|
||||
return l;
|
||||
}
|
||||
)
|
||||
));
|
||||
|
||||
RepositoryService repositoryService = springProcessEngineConfiguration.getRepositoryService();
|
||||
grouped.forEach((k, v) -> {
|
||||
if (runningProcessIds.contains(k)) {
|
||||
log.info("recover dynamic counter sign process instance id: {}", k);
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(v.get(0).getProcessDefinitionId());
|
||||
Process process = bpmnModel.getMainProcess();
|
||||
|
||||
v.forEach(sign -> {
|
||||
UserTask originalUserTask = (UserTask) process.getFlowElement(sign.getOriginalActivityId());
|
||||
BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR;
|
||||
if (StringUtils.hasText(sign.getTargetNodeMode())) {
|
||||
nodeMode = BpmnFlowNodeMode.valueOfType(sign.getTargetNodeMode());
|
||||
}
|
||||
// 创建加签节点
|
||||
UserTask newUserTask = CustomBpmnModelHelper.createUserTask(springProcessEngineConfiguration, originalUserTask, sign.getTargetActivityId(), nodeMode, sign.getAssignerList());
|
||||
process.addFlowElement(newUserTask);
|
||||
CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask, Objects.requireNonNull(BpmnCountersignTypeEnum.valueOfType(sign.getCounterSignType())));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPhase() {
|
||||
return Integer.MAX_VALUE - 2; // 确保在Web服务器启动前执行
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package cn.axzo.workflow.server.service;
|
||||
|
||||
import cn.axzo.workflow.server.common.util.RedisUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* form.html 页面授权码
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-11-19 10:51
|
||||
*/
|
||||
@Service
|
||||
public class AuthCodeService {
|
||||
private static final String AUTH_CODE_KEY_PREFIX = "we:auth_code";
|
||||
// 授权码有效期:1小时(可自定义)
|
||||
private static final long EXPIRE_HOURS = 1;
|
||||
|
||||
/**
|
||||
* 生成授权码(仅管理员可调用)
|
||||
*/
|
||||
public String generateAuthCode() {
|
||||
// 生成随机授权码(UUID简化)
|
||||
String authCode = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
|
||||
RedisUtils.setCacheObject(AUTH_CODE_KEY_PREFIX, authCode, Duration.ofMinutes(1));
|
||||
return authCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证授权码是否有效
|
||||
*/
|
||||
public boolean validateAuthCode(String authCode) {
|
||||
if (authCode == null || authCode.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
String key = RedisUtils.getCacheObject(AUTH_CODE_KEY_PREFIX);
|
||||
if (key == null || !Objects.equals(key, authCode)) {
|
||||
return false;
|
||||
}
|
||||
RedisUtils.deleteObject(AUTH_CODE_KEY_PREFIX);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
package cn.axzo.workflow.server.xxljob;
|
||||
|
||||
import cn.axzo.infra.xxl220to250.XxlJobLogger;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessTaskService;
|
||||
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
|
||||
import cn.axzo.workflow.server.controller.web.bpmn.BpmnProcessInstanceController;
|
||||
import cn.axzo.workflow.server.controller.web.bpmn.BpmnProcessJobController;
|
||||
import cn.axzo.workflow.server.controller.web.bpmn.BpmnProcessTaskController;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.xxl.job.core.context.XxlJobHelper;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
|
||||
|
||||
/**
|
||||
* 危险操作,操作审批中的行为
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-11-18 14:08
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DangerSuperOperationJobHandler extends IJobHandler {
|
||||
@Resource
|
||||
private RuntimeService runtimeService;
|
||||
@Resource
|
||||
private BpmnProcessInstanceController instanceController;
|
||||
@Resource
|
||||
private BpmnProcessTaskController taskController;
|
||||
@Resource
|
||||
private BpmnProcessTaskService taskService;
|
||||
@Resource
|
||||
private BpmnProcessJobController jobController;
|
||||
@Resource
|
||||
private ExtAxProcessLogService processLogService;
|
||||
|
||||
@Override
|
||||
@XxlJob("DangerSuperOperationJobHandler")
|
||||
public void execute() throws Exception {
|
||||
String paramStr = XxlJobHelper.getJobParam();
|
||||
log.info("#DangerSuperOperationJobHandler#param_({})", paramStr);
|
||||
XxlJobLogger.log("#DangerSuperOperationJobHandler#param_({})", paramStr);
|
||||
DangerOperationJobParam dangerOperationJobParam = JSON.parseObject(paramStr, DangerOperationJobParam.class);
|
||||
|
||||
String processInstanceId = dangerOperationJobParam.getProcessInstanceId();
|
||||
if (!StringUtils.hasText(processInstanceId)) {
|
||||
log.warn("缺少 processInstanceId 参数,无法撤回流程实例");
|
||||
XxlJobLogger.log("缺少 processInstanceId 参数,无法撤回流程实例");
|
||||
return;
|
||||
}
|
||||
switch (dangerOperationJobParam.getOperationType()) {
|
||||
case CANCEL:
|
||||
cancelProcessInstance(dangerOperationJobParam);
|
||||
break;
|
||||
case APPROVE:
|
||||
approveTask(dangerOperationJobParam);
|
||||
break;
|
||||
case REJECT:
|
||||
rejectTask(dangerOperationJobParam);
|
||||
break;
|
||||
case ABORT:
|
||||
abortProcessInstance(dangerOperationJobParam);
|
||||
break;
|
||||
case RESUMER_DEADLINE_JOB:
|
||||
resumerDeadlineJob(dangerOperationJobParam);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void resumerDeadlineJob(DangerOperationJobParam dangerOperationJobParam) {
|
||||
jobController.executeDeadLetterJobAction("", dangerOperationJobParam.getProcessInstanceId());
|
||||
}
|
||||
|
||||
private void abortProcessInstance(DangerOperationJobParam dangerOperationJobParam) {
|
||||
instanceController.abortProcessInstance(BpmnProcessInstanceAbortDTO.builder()
|
||||
.processInstanceId(dangerOperationJobParam.getProcessInstanceId())
|
||||
.advice(dangerOperationJobParam.getComment())
|
||||
.build());
|
||||
}
|
||||
|
||||
private void rejectTask(DangerOperationJobParam dangerOperationJobParam) {
|
||||
String personId = dangerOperationJobParam.getPersonId();
|
||||
if (!StringUtils.hasText(personId)) {
|
||||
log.warn("缺少 personId 参数,无法驳回任务");
|
||||
XxlJobLogger.log("缺少 personId 参数,无法驳回任务");
|
||||
}
|
||||
String taskId = taskService.findTaskIdByInstanceIdAndPersonId(dangerOperationJobParam.getProcessInstanceId(), dangerOperationJobParam.getPersonId());
|
||||
|
||||
ExtAxProcessLog query = new ExtAxProcessLog();
|
||||
query.setProcessInstanceId(dangerOperationJobParam.getProcessInstanceId());
|
||||
query.setTaskId(taskId);
|
||||
query.setStatus(PROCESSING.getStatus());
|
||||
List<ExtAxProcessLog> logs = processLogService.genericQuery(query);
|
||||
if (CollectionUtils.isEmpty(logs)) {
|
||||
log.warn("未找到可操作的任务日志,无法驳回任务,processInstanceId={}, personId={}", dangerOperationJobParam.getProcessInstanceId(), dangerOperationJobParam.getPersonId());
|
||||
XxlJobLogger.log("未找到可操作的任务日志,无法驳回任务,processInstanceId={}, personId={}", dangerOperationJobParam.getProcessInstanceId(), dangerOperationJobParam.getPersonId());
|
||||
return;
|
||||
}
|
||||
|
||||
taskController.rejectTask(BpmnTaskAuditDTO.builder()
|
||||
.processInstanceId(dangerOperationJobParam.getProcessInstanceId())
|
||||
.advice(dangerOperationJobParam.getComment())
|
||||
.approver(logs.get(0).getAssigneeFull().get(0))
|
||||
.async(false)
|
||||
.build());
|
||||
}
|
||||
|
||||
private void approveTask(DangerOperationJobParam dangerOperationJobParam) {
|
||||
String personId = dangerOperationJobParam.getPersonId();
|
||||
if (!StringUtils.hasText(personId)) {
|
||||
log.warn("缺少 personId 参数,无法驳回任务");
|
||||
XxlJobLogger.log("缺少 personId 参数,无法驳回任务");
|
||||
}
|
||||
|
||||
String taskId = taskService.findTaskIdByInstanceIdAndPersonId(dangerOperationJobParam.getProcessInstanceId(), dangerOperationJobParam.getPersonId());
|
||||
|
||||
ExtAxProcessLog query = new ExtAxProcessLog();
|
||||
query.setProcessInstanceId(dangerOperationJobParam.getProcessInstanceId());
|
||||
query.setTaskId(taskId);
|
||||
query.setStatus(PROCESSING.getStatus());
|
||||
List<ExtAxProcessLog> logs = processLogService.genericQuery(query);
|
||||
if (CollectionUtils.isEmpty(logs)) {
|
||||
log.warn("未找到可操作的任务日志,无法驳回任务,processInstanceId={}, personId={}", dangerOperationJobParam.getProcessInstanceId(), dangerOperationJobParam.getPersonId());
|
||||
XxlJobLogger.log("未找到可操作的任务日志,无法驳回任务,processInstanceId={}, personId={}", dangerOperationJobParam.getProcessInstanceId(), dangerOperationJobParam.getPersonId());
|
||||
return;
|
||||
}
|
||||
|
||||
taskController.approveTask(BpmnTaskAuditDTO.builder()
|
||||
.processInstanceId(dangerOperationJobParam.getProcessInstanceId())
|
||||
.advice(dangerOperationJobParam.getComment())
|
||||
.approver(logs.get(0).getAssigneeFull().get(0))
|
||||
.async(false)
|
||||
.build());
|
||||
}
|
||||
|
||||
private void cancelProcessInstance(DangerOperationJobParam dangerOperationJobParam) {
|
||||
String processInstanceId = dangerOperationJobParam.getProcessInstanceId();
|
||||
BpmnTaskDelegateAssigner assigner = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(processInstanceId, INTERNAL_INITIATOR));
|
||||
BpmnProcessInstanceCancelDTO cancelDTO = new BpmnProcessInstanceCancelDTO();
|
||||
cancelDTO.setProcessInstanceId(processInstanceId);
|
||||
cancelDTO.setInitiator(assigner);
|
||||
cancelDTO.setReason(dangerOperationJobParam.getComment());
|
||||
cancelDTO.setAsync(false);
|
||||
instanceController.cancelProcessInstance(cancelDTO);
|
||||
log.info("撤回操作完成");
|
||||
XxlJobLogger.log("撤回操作完成");
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
public static class DangerOperationJobParam implements Serializable {
|
||||
@NotNull(message = "操作类型不能为空")
|
||||
private OperationEnumType operationType;
|
||||
@NotBlank(message = "流程实例ID不能为空")
|
||||
private String processInstanceId;
|
||||
private String personId;
|
||||
private String comment;
|
||||
}
|
||||
|
||||
public static enum OperationEnumType {
|
||||
CANCEL, // 撤销任务
|
||||
APPROVE, // 同意任务
|
||||
REJECT, // 拒绝任务
|
||||
ABORT, // 中止实例
|
||||
RESUMER_DEADLINE_JOB, // 一般是因为二方计算人异常导致卡节点
|
||||
}
|
||||
}
|
||||
@ -2,3 +2,10 @@ arthas:
|
||||
app-name: ${spring.application.name}
|
||||
agent-id: ${ARTHAS_AGENT_ID:${spring.profiles.active}-${spring.application.name}}
|
||||
tunnel-server: ${ARTHAS_TUNNEL_SERVER:ws://localhost:7777/ws}
|
||||
spring:
|
||||
thymeleaf:
|
||||
mode: LEGACYHTML5
|
||||
cache: false
|
||||
encoding: UTF-8
|
||||
prefix: classpath:/templates/
|
||||
suffix: .html
|
||||
@ -0,0 +1 @@
|
||||
{}
|
||||
BIN
workflow-engine-server/src/main/resources/static/favicon.ico
Normal file
BIN
workflow-engine-server/src/main/resources/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user