diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfProcessController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfProcessController.java index 5748172..bc51597 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfProcessController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfProcessController.java @@ -73,7 +73,12 @@ public class WfProcessController extends BaseController { return processService.selectPageHandbookList(processQuery, pageQuery); } - + /** + * 获得我发起的流程的详细信息的列表, pageQuery中可以指定标题名和负责人名字字段,如果能够匹配则 + * 返回这些信息,如果无法匹配返回为空。 + * @author zhanli + * @since 2024-07-22 + */ @SaCheckPermission("workflow:process:ownList") @GetMapping(value = "/ownInfoList") public TableDataInfo ownProcessInfoList(ProcessQuery processQuery, PageQuery pageQuery) { @@ -204,7 +209,7 @@ public class WfProcessController extends BaseController { * * @param definitionId 流程定义id * @param deployId 流程部署id - * @param procInsId 这个参数可选 + * @param procInsId 这个参数可选, 如果流程的实例Id存在,那么就会把数值变量信息也返回 */ @SaCheckPermission("workflow:process:start") @GetMapping("/getProcessForm") @@ -215,7 +220,7 @@ public class WfProcessController extends BaseController { } /** - * 根据流程定义id启动流程实例 + * 根据流程定义id启动流程实例, 实际上启动流程只需要流程的定义Id和传递的参数就行 * * @param processDefId 流程定义id * @param variables 变量集合,json对象 @@ -244,6 +249,13 @@ public class WfProcessController extends BaseController { processService.deleteProcessByIds(instanceIds); return R.ok(); } + @SaCheckPermission("workflow:process:start") + @PostMapping("/updateHistory/{processInsId}") + public R updateHistory(@PathVariable(value = "processInsId") String processInsId, @RequestBody Map variables) { + // 删除的时候先要获取流程的实体Id + processService.editProcessByIds(processInsId, variables); + return R.ok(); + } /** * 读取xml文件 @@ -264,7 +276,11 @@ public class WfProcessController extends BaseController { public R detail(String procInsId, String taskId) { return R.ok(processService.queryProcessDetail(procInsId, taskId)); } - + /** + * zqjia: 批量查询流程实例详情 + * + * @param procInsIds 流程实例ID列表 + */ @PostMapping("/details") public TableDataInfo details(@RequestBody List procInsIds) { List processDetails = new ArrayList<>(); diff --git a/ruoyi-admin/src/main/resources/logback-plus.xml b/ruoyi-admin/src/main/resources/logback-plus.xml index 40fa33b..829f33f 100644 --- a/ruoyi-admin/src/main/resources/logback-plus.xml +++ b/ruoyi-admin/src/main/resources/logback-plus.xml @@ -13,6 +13,7 @@ + ${log.path}/sys-console.log diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/factory/FlowServiceFactory.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/factory/FlowServiceFactory.java index 76f2e8f..6a9595c 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/factory/FlowServiceFactory.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/factory/FlowServiceFactory.java @@ -16,12 +16,19 @@ import javax.annotation.Resource; @Getter public class FlowServiceFactory { + /** + * 提供了管理与控制部署(deployments)与流程定义(process definitions)的操作 + */ @Resource protected RepositoryService repositoryService; @Resource protected RuntimeService runtimeService; + /** + * 用于管理(创建,更新,删除,查询……)组与用户,Flowable实际上在运行时并不做任 + * 何用户检查。例如任务可以分派给任何用户,而引擎并不会验证系统中是否存在该用户 + */ @Resource protected IdentityService identityService; @@ -30,10 +37,20 @@ public class FlowServiceFactory { @Resource protected FormService formService; - + /** + * 暴露Flowable引擎收集的所有历史数据。当执行流程时,引擎会保存许多数据(可配置), + * 例如流程实例启动时间、谁在执行哪个任务、完成任务花费的事件、每个流程实例的执行路 + * 径,等等。这个服务主要提供查询这些数据的能力。 + */ @Resource protected HistoryService historyService; + /** + * 暴露通常在用Flowable编写用户应用时不需要使用。它可以读取数据库表与表原始数据的信 + * 息,也提供了对作业(job)的查询与管理操作。Flowable中很多地方都使用作业,例如定时 + * 器(timer),异步操作(asynchronous continuation),延时暂停/激活(delayed + * suspension/activation)等等 + */ @Resource protected ManagementService managementService; diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/listener/TestTaskListener.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/listener/TestTaskListener.java new file mode 100644 index 0000000..fc6c911 --- /dev/null +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/listener/TestTaskListener.java @@ -0,0 +1,14 @@ +package com.ruoyi.flowable.listener; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; + +public class TestTaskListener implements ExecutionListener { + /** + * 注入字段(名称与流程设计时字段名称一致) + */ + // private FixedValue field; + @Override + public void notify(DelegateExecution execution) { + System.out.println("执行任务监听器..."); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfProcessService.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfProcessService.java index efacdc5..93ba589 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfProcessService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfProcessService.java @@ -125,4 +125,6 @@ public interface IWfProcessService { TableDataInfo selectPageOwnProcessInfoList(ProcessQuery processQuery, PageQuery pageQuery); String startProcessByDefId_(String processDefId, Map variables); + + void editProcessByIds(String procInsId, Map variables); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java index f3f1d4f..f76fe73 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java @@ -42,10 +42,17 @@ import lombok.RequiredArgsConstructor; import org.flowable.bpmn.constants.BpmnXMLConstants; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.HistoryService; +import org.flowable.engine.ProcessEngine; +import org.flowable.engine.ProcessEngineConfiguration; import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricActivityInstanceQuery; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntity; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.repository.ProcessDefinitionQuery; @@ -199,6 +206,7 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce taskVo.setFinishTime(hisIns.getEndTime()); taskVo.setProcInsId(hisIns.getId()); + // 计算耗时 if (Objects.nonNull(hisIns.getEndTime())) { taskVo.setDuration(DateUtils.getDatePoor(hisIns.getEndTime(), hisIns.getStartTime())); @@ -708,6 +716,82 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce historyService.bulkDeleteHistoricProcessInstances(ids); } + public void editProcessByIds(String procInsId, Map variables) { + // 更改前先获得历史信息 + HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery() + .processInstanceId(procInsId) + .includeProcessVariables() + .singleResult(); + + // ---------------------------------- 新建流程 ------------------------------------- // + // 从历史实体中获取流程定义 + String procDefId = historicProcIns.getProcessDefinitionId(); + ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(procDefId).singleResult(); + + // 检查流程定义是否正常 + if (ObjectUtil.isNotNull(procDef) && procDef.isSuspended()) { + throw new ServiceException("流程已被挂起,请先激活流程"); + } + + // 设置流程发起人Id到流程中 + String userIdStr = TaskUtils.getUserId(); + identityService.setAuthenticatedUserId(userIdStr); + variables.put(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR, userIdStr); + + // 设置流程状态为完成 + variables.put(ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.COMPLETED.getStatus()); + // 根据流程的定义发起流程实例 + ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDef.getId(), variables); + // 第一个用户任务为发起人,则自动完成任务 + wfTaskService.startFirstTask(processInstance, variables); + + + // 直接修改数据库的方法 +// processEngine.getProcessEngineConfiguration().getDataSource(); +// // 获取数据库连接 +// DataSource dataSource = processEngineConfiguration.getDataSource(); +// try (Connection connection = dataSource.getConnection(); +// Statement statement = connection.createStatement()) { +// +// // 更新历史流程实例的名称 +// String sql = "UPDATE ACT_HI_PROCINST SET NAME_ = 'newName' WHERE ID_ = 'processInstanceId'"; +// statement.executeUpdate(sql); +// +// } catch (SQLException e) { +// e.printStackTrace(); +// } + +// HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() +// .processInstanceId("processInstanceId") +// .singleResult(); +// ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration +// .createProcessEngineConfigurationFromResourceDefault(); +// // 将查询结果转换为实体类,以便进行修改 +// if (historicProcessInstance instanceof HistoricProcessInstanceEntity) { +// HistoricProcessInstanceEntity processInstanceEntity = (HistoricProcessInstanceEntity) historicProcessInstance; +// +// // 修改流程实例名称 +// processInstanceEntity.setName("newProcessName"); +// +// // 保存修改 +// processEngineConfiguration.getCommandExecutor().execute(new Command() { +// @Override +// public Void execute(CommandContext commandContext) { +// +// return null; +// } +// }); +// } + + + // -------------------------------- 删除历史流程 ---------------------------------- // + // 历史流程实例不能编辑只能删除,因此编辑=删除+新建 + historyService.deleteHistoricProcessInstance(procInsId); + } + + + /** * 读取xml文件 * @param processDefId 流程定义ID @@ -910,6 +994,7 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce @Deprecated private void buildStartFormData(HistoricProcessInstance historicProcIns, Process process, String deployId, List procFormList) { procFormList = procFormList == null ? new ArrayList<>() : procFormList; + HistoricActivityInstance startInstance = historyService.createHistoricActivityInstanceQuery() .processInstanceId(historicProcIns.getId()) .activityId(historicProcIns.getStartActivityId()) diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java index 2ba790a..716ed9d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java @@ -84,9 +84,17 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ // 获取模型信息 String localScopeValue = ModelUtils.getUserTaskAttributeValue(bpmnModel, task.getTaskDefinitionKey(), ProcessConstants.PROCESS_FORM_LOCAL_SCOPE); boolean localScope = Convert.toBool(localScopeValue, false); - taskService.complete(taskBo.getTaskId(), taskBo.getVariables(), localScope); + Map mapTmp = taskBo.getVariables(); + mapTmp.put("review", "1"); + if (!StringUtils.isNotBlank(taskBo.getNextUserIds())) { + taskService.complete(taskBo.getTaskId(), mapTmp, localScope); + } } else { - taskService.complete(taskBo.getTaskId()); + Map mapTmp = new HashMap<>(); + mapTmp.put("review", "1"); + if (!StringUtils.isNotBlank(taskBo.getNextUserIds())) { + taskService.complete(taskBo.getTaskId(), mapTmp); + } } } // 设置任务节点名称 @@ -330,6 +338,7 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ taskService.setOwner(bo.getTaskId(), TaskUtils.getUserId()); // 执行委派 taskService.delegateTask(bo.getTaskId(), bo.getUserId()); + // 设置任务节点名称 bo.setTaskName(task.getName()); // 处理抄送用户 diff --git a/ruoyi-ui/src/api/scientific/application.js b/ruoyi-ui/src/api/scientific/application.js new file mode 100644 index 0000000..3456e94 --- /dev/null +++ b/ruoyi-ui/src/api/scientific/application.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询项目申报列表 +export function listApplication(query) { + return request({ + url: '/scientific/application/list', + method: 'get', + params: query + }) +} + +// 查询项目申报详细 +export function getApplication(projectId) { + return request({ + url: '/scientific/application/' + projectId, + method: 'get' + }) +} + +// 新增项目申报 +export function addApplication(data) { + return request({ + url: '/scientific/application', + method: 'post', + data: data + }) +} + +// 修改项目申报 +export function updateApplication(data) { + return request({ + url: '/scientific/application', + method: 'put', + data: data + }) +} + +// 删除项目申报 +export function delApplication(projectId) { + return request({ + url: '/scientific/application/' + projectId, + method: 'delete' + }) +} diff --git a/ruoyi-ui/src/api/scientific/handbook.js b/ruoyi-ui/src/api/scientific/handbook.js new file mode 100644 index 0000000..13d2a6d --- /dev/null +++ b/ruoyi-ui/src/api/scientific/handbook.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询项目申报v2列表 +export function listHandbook(query) { + return request({ + url: '/scientific/handbook/list', + method: 'get', + params: query + }) +} + +// 查询项目申报v2详细 +export function getHandbook(handbookId) { + return request({ + url: '/scientific/handbook/' + handbookId, + method: 'get' + }) +} + +// 新增项目申报v2 +export function addHandbook(data) { + return request({ + url: '/scientific/handbook', + method: 'post', + data: data + }) +} + +// 修改项目申报v2 +export function updateHandbook(data) { + return request({ + url: '/scientific/handbook', + method: 'put', + data: data + }) +} + +// 删除项目申报v2 +export function delHandbook(handbookId) { + return request({ + url: '/scientific/handbook/' + handbookId, + method: 'delete' + }) +} diff --git a/ruoyi-ui/src/api/workflow/process.js b/ruoyi-ui/src/api/workflow/process.js index b0c0ee6..a59d412 100644 --- a/ruoyi-ui/src/api/workflow/process.js +++ b/ruoyi-ui/src/api/workflow/process.js @@ -35,6 +35,14 @@ export function startProcess_(processDefId, data) { }) } +export function updateProcess(processInsId, data) { + return request({ + url: '/workflow/process/updateHistory/' + processInsId, + method: 'post', + data: data + }) +} + // 删除流程实例 export function delProcess(ids) { return request({ diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js index 788a8a4..0801cb3 100644 --- a/ruoyi-ui/src/router/index.js +++ b/ruoyi-ui/src/router/index.js @@ -187,11 +187,25 @@ export const dynamicRoutes = [ name: 'WorkStart', meta: { title: '发起流程', icon: '' } }, + // logzhan:这里注册项目信息更新模块 + { + path: 'update/:deployId([\\w|\\-]+)', + component: () => import('@/views/workflow/work/update'), + name: 'WorkUpdate', + meta: { title: '更新信息', icon: '' } + }, { path: 'detail/:procInsId([\\w|\\-]+)', component: () => import('@/views/workflow/work/detail'), name: 'WorkDetail', meta: { title: '流程详情', activeMenu: '/work/own' } + }, + // logzhan:这里用于项目的信息变更如预算追加、更换负责人等等 + { + path: 'proj_update/:deployId([\\w|\\-]+)', + component: () => import('@/views/workflow/work/proj_update'), + name: 'ProjectInfoUpdate', + meta: { title: '项目信息变更', icon: ''} } ] }, @@ -209,9 +223,23 @@ export const dynamicRoutes = [ }, { path: 'handbookProjectQuery/:handbookId([\\w|\\-]+)', - component: () => import('@/views/scientific/handbookProject_query'), + component: () => import('@/views/scientific/project/index'), name: 'handbookProjectQuery', - meta: { title: '已申报项目' } + meta: { title: '指南项目' } + // meta: { title: '已申报项目', activeMenu: '/work/own' } + }, + { + path: 'handbookList', + component: () => import('@/views/scientific/handbook/index'), + name: 'handbookList', + meta: { title: '申报指南' } + // meta: { title: '已申报项目', activeMenu: '/work/own' } + }, + { + path: 'handbook/detail/:handbookProcId([\\w|\\-]+)', + component: () => import('@/views/scientific/handbook/detail'), + name: 'handbookDetail', + meta: { title: '申报计划' } // meta: { title: '已申报项目', activeMenu: '/work/own' } } ] diff --git a/ruoyi-ui/src/views/project/application/declare.vue b/ruoyi-ui/src/views/project/application/declare.vue new file mode 100644 index 0000000..5824eea --- /dev/null +++ b/ruoyi-ui/src/views/project/application/declare.vue @@ -0,0 +1,524 @@ + + + diff --git a/ruoyi-ui/src/views/project/application/index.vue b/ruoyi-ui/src/views/project/application/index.vue index 8a2a2f6..89e8e7f 100644 --- a/ruoyi-ui/src/views/project/application/index.vue +++ b/ruoyi-ui/src/views/project/application/index.vue @@ -73,8 +73,8 @@ icon="el-icon-plus" size="mini" @click="handleAdd" - v-hasPermi="['project:application:add']" - >新增 + v-hasPermi="['scientific:application:add']" + >项目填写 修改 @@ -95,7 +95,7 @@ size="mini" :disabled="multiple" @click="handleDelete" - v-hasPermi="['project:application:remove']" + v-hasPermi="['scientific:application:remove']" >删除 @@ -105,7 +105,7 @@ icon="el-icon-download" size="mini" @click="handleExport" - v-hasPermi="['project:application:export']" + v-hasPermi="['scientific:application:export']" >导出 @@ -113,9 +113,26 @@ - - - + + + + + + + + + + + + + + - + - - + + @@ -165,12 +188,18 @@ @pagination="getList" /> - + + + + + + @@ -190,9 +219,6 @@ placeholder="请选择申报结束日期"> - - - @@ -209,8 +235,8 @@ + diff --git a/ruoyi-ui/src/views/scientific/handbook/index.vue b/ruoyi-ui/src/views/scientific/handbook/index.vue new file mode 100644 index 0000000..d7dcba7 --- /dev/null +++ b/ruoyi-ui/src/views/scientific/handbook/index.vue @@ -0,0 +1,534 @@ + + + diff --git a/ruoyi-ui/src/views/scientific/handbook_apply.vue b/ruoyi-ui/src/views/scientific/handbook_apply.vue index 8accffc..858463c 100644 --- a/ruoyi-ui/src/views/scientific/handbook_apply.vue +++ b/ruoyi-ui/src/views/scientific/handbook_apply.vue @@ -15,10 +15,11 @@ diff --git a/ruoyi-ui/src/views/scientific/handbook_query.vue b/ruoyi-ui/src/views/scientific/handbook_query.vue index 5ffd618..1078ae7 100644 --- a/ruoyi-ui/src/views/scientific/handbook_query.vue +++ b/ruoyi-ui/src/views/scientific/handbook_query.vue @@ -73,11 +73,13 @@ - + + + - + @@ -245,6 +259,7 @@ export default { return new Promise((resolve,reject)=>{ this.showList = []; this.loading = true; + // 先列出所有的指南流程 listHandbook(this.addDateRange(this.queryParams, this.dateRange)).then(response => { this.handbookList = response.rows; this.total = response.total; @@ -268,9 +283,9 @@ export default { res.rows.forEach(row => { let processForm = row.processFormList[0]; let formData = []; - this.initFormData(processForm.fields, formData); + // 从原始表单中筛选解析的数据显示 + this.parseFormData(processForm.fields, formData); formData["procInsId"] = row.procInsId; - this.showList.push(formData); }) }) @@ -281,9 +296,11 @@ export default { getCategoryList() { listAllCategory().then(response => this.categoryOptions = response.data) }, - - - initFormData(componentList, formData) { + /** + * 从原始的流程表单中解析字段数据 + * @author zqjia + */ + parseFormData(componentList, formData) { componentList.forEach(cur => { this.buildOptionMethod(cur) const config = cur.__config__; @@ -294,14 +311,11 @@ export default { else { formData[cur.__vModel__] = config.defaultValue; } - } - if (config.children) { - this.initFormData(config.children, formData); + this.parseFormData(config.children, formData); } }) - }, // 特殊处理的 Option diff --git a/ruoyi-ui/src/views/scientific/handbook_query_bak.vue b/ruoyi-ui/src/views/scientific/handbook_query_bak.vue deleted file mode 100644 index 792bbb6..0000000 --- a/ruoyi-ui/src/views/scientific/handbook_query_bak.vue +++ /dev/null @@ -1,472 +0,0 @@ - - - - - - diff --git a/ruoyi-ui/src/views/scientific/project/index.vue b/ruoyi-ui/src/views/scientific/project/index.vue index fb57c5c..f25c188 100644 --- a/ruoyi-ui/src/views/scientific/project/index.vue +++ b/ruoyi-ui/src/views/scientific/project/index.vue @@ -1,46 +1,64 @@ + + diff --git a/ruoyi-ui/src/views/scientific/handbook_apply_bak.vue b/ruoyi-ui/src/views/workflow/work/update.vue similarity index 50% rename from ruoyi-ui/src/views/scientific/handbook_apply_bak.vue rename to ruoyi-ui/src/views/workflow/work/update.vue index f72b60a..4d39b9a 100644 --- a/ruoyi-ui/src/views/scientific/handbook_apply_bak.vue +++ b/ruoyi-ui/src/views/workflow/work/update.vue @@ -2,11 +2,16 @@
- {{ processName }} + + {{ "processName" }}
- +
+ + + +
@@ -15,9 +20,7 @@