@@ -100,6 +100,10 @@ public class BpmModelMetaInfoVO {
|
|||||||
@Schema(description = "任务后置通知设置", example = "{}")
|
@Schema(description = "任务后置通知设置", example = "{}")
|
||||||
private HttpRequestSetting taskAfterTriggerSetting;
|
private HttpRequestSetting taskAfterTriggerSetting;
|
||||||
|
|
||||||
|
@Schema(description = "自定义打印模板设置", example = "{}")
|
||||||
|
@Valid
|
||||||
|
private PrintTemplateSetting printTemplateSetting;
|
||||||
|
|
||||||
@Schema(description = "流程 ID 规则")
|
@Schema(description = "流程 ID 规则")
|
||||||
@Data
|
@Data
|
||||||
@Valid
|
@Valid
|
||||||
@@ -180,4 +184,17 @@ public class BpmModelMetaInfoVO {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Schema(description = "自定义打印模板设置")
|
||||||
|
@Data
|
||||||
|
public static class PrintTemplateSetting {
|
||||||
|
|
||||||
|
@Schema(description = "是否自定义打印模板", example = "false")
|
||||||
|
@NotNull(message = "是否自定义打印模板不能为空")
|
||||||
|
private Boolean enable;
|
||||||
|
|
||||||
|
@Schema(description = "打印模板", example = "<p></p>")
|
||||||
|
private String template;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,4 +196,12 @@ public class BpmProcessInstanceController {
|
|||||||
return success(processInstanceService.getProcessInstanceBpmnModelView(id));
|
return success(processInstanceService.getProcessInstanceBpmnModelView(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-print-data")
|
||||||
|
@Operation(summary = "获得打印数据")
|
||||||
|
@Parameter(name = "id", description = "流程实例的编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
|
||||||
|
public CommonResult<BpmProcessPrintDataRespVO> getPrintData(@RequestParam("processInstanceId") String processInstanceId) {
|
||||||
|
return success(processInstanceService.getPrintData(getLoginUserId(), processInstanceId));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 打印数据 Response VO")
|
||||||
|
@Data
|
||||||
|
public class BpmProcessPrintDataRespVO {
|
||||||
|
|
||||||
|
private Boolean printTemplateEnable;
|
||||||
|
|
||||||
|
private Integer processStatus;
|
||||||
|
|
||||||
|
private String processStatusShow;
|
||||||
|
|
||||||
|
private String processInstanceId;
|
||||||
|
|
||||||
|
private String processBusinessKey;
|
||||||
|
|
||||||
|
private String processName;
|
||||||
|
|
||||||
|
private String startUser;
|
||||||
|
|
||||||
|
private String startUserDept;
|
||||||
|
|
||||||
|
private String startTime;
|
||||||
|
|
||||||
|
private List<ApproveNode> approveNodes;
|
||||||
|
|
||||||
|
private List<FormField> formFields;
|
||||||
|
|
||||||
|
private String printTemplateHtml;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ApproveNode {
|
||||||
|
|
||||||
|
private String nodeName;
|
||||||
|
|
||||||
|
private String nodeDesc;
|
||||||
|
|
||||||
|
private String signUrl;
|
||||||
|
|
||||||
|
private String nodeId;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class FormField {
|
||||||
|
|
||||||
|
private String formId;
|
||||||
|
|
||||||
|
private String formName;
|
||||||
|
|
||||||
|
private String formType;
|
||||||
|
|
||||||
|
private String formValue;
|
||||||
|
|
||||||
|
private String formValueShow;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -224,4 +224,10 @@ public class BpmProcessDefinitionInfoDO extends BaseDO {
|
|||||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
private BpmModelMetaInfoVO.HttpRequestSetting taskAfterTriggerSetting;
|
private BpmModelMetaInfoVO.HttpRequestSetting taskAfterTriggerSetting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义打印模板设置
|
||||||
|
*/
|
||||||
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
|
private BpmModelMetaInfoVO.PrintTemplateSetting printTemplateSetting;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.enums.task;
|
package cn.iocoder.yudao.module.bpm.enums.task;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@@ -47,4 +48,8 @@ public enum BpmProcessInstanceStatusEnum implements ArrayValuable<Integer> {
|
|||||||
APPROVE.getStatus(), REJECT.getStatus(), CANCEL.getStatus());
|
APPROVE.getStatus(), REJECT.getStatus(), CANCEL.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BpmProcessInstanceStatusEnum valueOf(Integer status) {
|
||||||
|
return ArrayUtil.firstMatch(item -> item.getStatus().equals(status), values());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.enums.task;
|
package cn.iocoder.yudao.module.bpm.enums.task;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@@ -68,4 +69,8 @@ public enum BpmTaskStatusEnum {
|
|||||||
return ObjUtil.equal(status, CANCEL.getStatus());
|
return ObjUtil.equal(status, CANCEL.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BpmTaskStatusEnum valueOf(Integer status) {
|
||||||
|
return ArrayUtil.firstMatch(item -> item.getStatus().equals(status), values());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,14 @@ public interface BpmProcessInstanceService {
|
|||||||
*/
|
*/
|
||||||
BpmProcessInstanceBpmnModelViewRespVO getProcessInstanceBpmnModelView(String id);
|
BpmProcessInstanceBpmnModelViewRespVO getProcessInstanceBpmnModelView(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程打印所需数据
|
||||||
|
* @param loginUserId 打印人
|
||||||
|
* @param processInstanceId 流程实例id
|
||||||
|
* @return 打印所需数据
|
||||||
|
*/
|
||||||
|
BpmProcessPrintDataRespVO getPrintData(Long loginUserId, String processInstanceId);
|
||||||
|
|
||||||
// ========== Update 写入相关方法 ==========
|
// ========== Update 写入相关方法 ==========
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ package cn.iocoder.yudao.module.bpm.service.task;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.collection.ListUtil;
|
import cn.hutool.core.collection.ListUtil;
|
||||||
|
import cn.hutool.core.date.DatePattern;
|
||||||
|
import cn.hutool.core.date.DateTime;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.*;
|
import cn.hutool.core.util.*;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||||
@@ -57,6 +61,10 @@ import org.flowable.engine.runtime.ProcessInstance;
|
|||||||
import org.flowable.engine.runtime.ProcessInstanceBuilder;
|
import org.flowable.engine.runtime.ProcessInstanceBuilder;
|
||||||
import org.flowable.task.api.Task;
|
import org.flowable.task.api.Task;
|
||||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
import org.jsoup.nodes.Element;
|
||||||
|
import org.jsoup.select.Elements;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -726,6 +734,141 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||||||
userMap, deptMap);
|
userMap, deptMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BpmProcessPrintDataRespVO getPrintData(Long loginUserId, String processInstanceId) {
|
||||||
|
// TODO 方法抽离
|
||||||
|
// 流程实例
|
||||||
|
HistoricProcessInstance historicProcessInstance = getHistoricProcessInstance(processInstanceId);
|
||||||
|
if (historicProcessInstance == null) {
|
||||||
|
throw exception(PROCESS_INSTANCE_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
// 准备数据
|
||||||
|
BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService
|
||||||
|
.getProcessDefinitionInfo(historicProcessInstance.getProcessDefinitionId());
|
||||||
|
BpmModelMetaInfoVO.PrintTemplateSetting printTemplateSetting = processDefinitionInfo.getPrintTemplateSetting();
|
||||||
|
List<String> formFieldList = processDefinitionInfo.getFormFields();
|
||||||
|
List<JSONObject> formFieldObjList = formFieldList.stream().map(JSONUtil::parseObj).toList();
|
||||||
|
List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery()
|
||||||
|
.finished()
|
||||||
|
.includeTaskLocalVariables()
|
||||||
|
.processInstanceId(processInstanceId)
|
||||||
|
.taskVariableValueNotEquals(BpmnVariableConstants.TASK_VARIABLE_STATUS,
|
||||||
|
BpmTaskStatusEnum.CANCEL.getStatus())
|
||||||
|
.orderByHistoricTaskInstanceStartTime().asc().list();
|
||||||
|
Set<Long> userIds = convertSet(tasks, item -> Long.valueOf(item.getAssignee()));
|
||||||
|
userIds.add(loginUserId);
|
||||||
|
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
|
||||||
|
HashMap<String, String> printDataMap = new HashMap<>(8 + formFieldList.size());
|
||||||
|
// 返回打印所需数据
|
||||||
|
BpmProcessPrintDataRespVO printData = new BpmProcessPrintDataRespVO();
|
||||||
|
// 打印模板是否开启
|
||||||
|
printData.setPrintTemplateEnable(printTemplateSetting != null && Boolean.TRUE.equals(printTemplateSetting.getEnable()));
|
||||||
|
// 流程相关数据
|
||||||
|
printData.setProcessStatus(FlowableUtils.getProcessInstanceStatus(historicProcessInstance));
|
||||||
|
printData.setProcessStatusShow(BpmProcessInstanceStatusEnum.valueOf(printData.getProcessStatus()).getDesc());
|
||||||
|
printData.setProcessInstanceId(historicProcessInstance.getId());
|
||||||
|
printData.setProcessName(historicProcessInstance.getName());
|
||||||
|
printData.setProcessBusinessKey(historicProcessInstance.getBusinessKey());
|
||||||
|
printData.setStartTime(DatePattern.NORM_DATETIME_MINUTE_FORMAT.format(historicProcessInstance.getStartTime()));
|
||||||
|
// 发起人
|
||||||
|
AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(historicProcessInstance.getStartUserId()));
|
||||||
|
DeptRespDTO dept = deptApi.getDept(startUser.getDeptId());
|
||||||
|
printData.setStartUser(startUser.getNickname());
|
||||||
|
printData.setStartUserDept(dept.getName());
|
||||||
|
// 审批历史
|
||||||
|
List<BpmProcessPrintDataRespVO.ApproveNode> approveNodes = new ArrayList<>(tasks.size());
|
||||||
|
tasks.forEach(item -> {
|
||||||
|
Map<String, Object> taskLocalVariables = item.getTaskLocalVariables();
|
||||||
|
BpmProcessPrintDataRespVO.ApproveNode approveNode = new BpmProcessPrintDataRespVO.ApproveNode();
|
||||||
|
approveNode.setNodeName(item.getName());
|
||||||
|
approveNode.setNodeId(item.getId());
|
||||||
|
approveNode.setSignUrl((String) taskLocalVariables.getOrDefault(BpmnVariableConstants.TASK_SIGN_PIC_URL, ""));
|
||||||
|
approveNode.setNodeDesc(StrUtil.format("{} / {} / {} / {} / {}",
|
||||||
|
userMap.get(Long.valueOf(item.getAssignee())).getNickname(),
|
||||||
|
item.getName(),
|
||||||
|
DateUtil.formatDateTime(item.getEndTime()),
|
||||||
|
BpmTaskStatusEnum.valueOf((Integer) taskLocalVariables.get(BpmnVariableConstants.TASK_VARIABLE_STATUS)).getName(),
|
||||||
|
taskLocalVariables.get(BpmnVariableConstants.TASK_VARIABLE_REASON)));
|
||||||
|
approveNodes.add(approveNode);
|
||||||
|
});
|
||||||
|
printData.setApproveNodes(approveNodes);
|
||||||
|
// 表单数据
|
||||||
|
Map<String, Object> processVariables = historicProcessInstance.getProcessVariables();
|
||||||
|
List<BpmProcessPrintDataRespVO.FormField> formFields = new ArrayList<>(formFieldList.size());
|
||||||
|
formFieldObjList.forEach(item -> {
|
||||||
|
BpmProcessPrintDataRespVO.FormField formField = new BpmProcessPrintDataRespVO.FormField();
|
||||||
|
formField.setFormName(item.getStr("title"));
|
||||||
|
formField.setFormType(item.getStr("type"));
|
||||||
|
formField.setFormId(item.getStr("field"));
|
||||||
|
formField.setFormValue(processVariables.getOrDefault(item.getStr("field"), "").toString());
|
||||||
|
// TODO 根据不同类型的表单展示,下面为图片和输入框示例
|
||||||
|
if (formField.getFormType().equals("input")) {
|
||||||
|
formField.setFormValueShow(processVariables.getOrDefault(item.getStr("field"), "").toString());
|
||||||
|
} else if (formField.getFormType().equals("UploadImg")) {
|
||||||
|
formField.setFormValueShow("<img style=\"max-width: 600px\" src=\"" + processVariables.getOrDefault(item.getStr("field"), "").toString() + "\" />");
|
||||||
|
} else {
|
||||||
|
formField.setFormValueShow("此类型表单展示未完善");
|
||||||
|
}
|
||||||
|
printDataMap.put(formField.getFormId(), formField.getFormValueShow());
|
||||||
|
formFields.add(formField);
|
||||||
|
});
|
||||||
|
printData.setFormFields(formFields);
|
||||||
|
// 数据映射
|
||||||
|
printDataMap.put("processName", printData.getProcessName());
|
||||||
|
printDataMap.put("printUsername", userMap.get(loginUserId).getNickname());
|
||||||
|
printDataMap.put("processNum", printData.getProcessInstanceId());
|
||||||
|
printDataMap.put("printTime", DatePattern.NORM_DATETIME_MINUTE_FORMAT.format(new DateTime()));
|
||||||
|
printDataMap.put("startUser", printData.getStartUser());
|
||||||
|
printDataMap.put("startTime", printData.getStartTime());
|
||||||
|
printDataMap.put("startUserDept", printData.getStartUserDept());
|
||||||
|
printDataMap.put("processStatus", printData.getProcessStatusShow());
|
||||||
|
// 自定义模板
|
||||||
|
if (printData.getPrintTemplateEnable() && printTemplateSetting != null) {
|
||||||
|
Document document = Jsoup.parse(printTemplateSetting.getTemplate());
|
||||||
|
// 添加table的border
|
||||||
|
Elements tables = document.select("table");
|
||||||
|
tables.forEach(item -> {
|
||||||
|
item.attr("border", "1");
|
||||||
|
});
|
||||||
|
// 替换所有mention
|
||||||
|
Elements mention = document.getElementsByAttributeValue("data-w-e-type", "mention");
|
||||||
|
mention.forEach(item -> {
|
||||||
|
String mentionId = JSONUtil.parseObj(URLUtil.decode(item.attr("data-info"))).getStr("id");
|
||||||
|
item.html(printDataMap.get(mentionId));
|
||||||
|
});
|
||||||
|
// 替换流程记录
|
||||||
|
Elements processRecords = document.getElementsByAttributeValue("data-w-e-type", "process-record");
|
||||||
|
Element processRecordElement = null;
|
||||||
|
if (!processRecords.isEmpty()) {
|
||||||
|
processRecordElement = new Element("table", "")
|
||||||
|
.attr("style", "width:100%;")
|
||||||
|
.attr("border", "1");
|
||||||
|
Element tbody = new Element("tbody", "");
|
||||||
|
Element rowHead = new Element("tr", "");
|
||||||
|
rowHead.appendChild(new Element("td", "")
|
||||||
|
.attr("colspan", "2")
|
||||||
|
.attr("width", "auto")
|
||||||
|
.attr("style", "text-align: center;")
|
||||||
|
.html("流程节点"));
|
||||||
|
tbody.appendChild(rowHead);
|
||||||
|
for (BpmProcessPrintDataRespVO.ApproveNode item : printData.getApproveNodes()) {
|
||||||
|
Element row = new Element("tr", "");
|
||||||
|
row.appendChild(new Element("td", "")
|
||||||
|
.html(item.getNodeName()));
|
||||||
|
row.appendChild(new Element("td", "")
|
||||||
|
.html(item.getNodeDesc()));
|
||||||
|
tbody.appendChild(row);
|
||||||
|
}
|
||||||
|
processRecordElement.appendChild(tbody);
|
||||||
|
}
|
||||||
|
for (Element item : processRecords) {
|
||||||
|
item.html(processRecordElement.outerHtml());
|
||||||
|
}
|
||||||
|
printData.setPrintTemplateHtml(document.html());
|
||||||
|
}
|
||||||
|
return printData;
|
||||||
|
}
|
||||||
|
|
||||||
// ========== Update 写入相关方法 ==========
|
// ========== Update 写入相关方法 ==========
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user