From 00e15a5c2c312335463760cbd03423e1ed81efd7 Mon Sep 17 00:00:00 2001 From: zhujiqian <924931408@qq.com> Date: Sun, 5 Sep 2021 22:46:01 +0800 Subject: [PATCH 01/60] =?UTF-8?q?1=E3=80=81=E9=9B=86=E6=88=90Activiti7?= =?UTF-8?q?=E7=89=88=E6=9C=AC=EF=BC=8Cyudao-dependencies=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=96=B0=E5=A2=9Eactiviti=E4=BE=9D=E8=B5=96=E5=8C=85=EF=BC=9B?= =?UTF-8?q?=202=E3=80=81=E6=B5=81=E7=A8=8B=E6=96=87=E4=BB=B6=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E9=83=A8=E7=BD=B2API=E5=90=8E=E7=AB=AF=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=AE=9E=E7=8E=B0=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/process/ProcessService.java | 18 ++++ .../process/impl/ProcessServiceImpl.java | 85 +++++++++++++++++++ .../src/main/resources/application-local.yaml | 21 ++++- yudao-dependencies/pom.xml | 9 ++ yudao-framework/pom.xml | 1 + .../pom.xml | 58 +++++++++++++ .../framework/activiti/package-info.java | 1 + 7 files changed, 189 insertions(+), 4 deletions(-) create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/ProcessService.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java create mode 100644 yudao-framework/yudao-spring-boot-starter-activiti/pom.xml create mode 100644 yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/package-info.java diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/ProcessService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/ProcessService.java new file mode 100644 index 000000000..4ef499658 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/ProcessService.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.service.process; + +import org.springframework.web.multipart.MultipartFile; + +/** + * 流程基础管理 + * + * @author ZJQ + * @date 2021/9/5 21:00 + */ +public interface ProcessService { + + /** + * 上传流程文件,进行流程部署 + * @param multipartFile 上传文件 + */ + void deployProcess(MultipartFile multipartFile); +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java new file mode 100644 index 000000000..aa4e134f7 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.service.process.impl; + +import cn.iocoder.yudao.adminserver.modules.activiti.service.process.ProcessService; +import lombok.extern.slf4j.Slf4j; +import org.activiti.engine.RepositoryService; +import org.activiti.engine.repository.Deployment; +import org.activiti.engine.repository.ProcessDefinition; +import org.apache.commons.io.FilenameUtils; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.zip.ZipInputStream; +import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.FILE_UPLOAD_FAILED; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + +/** + * 流程基础管理 + * + * @author ZJQ + * @date 2021/9/5 21:04 + */ +@Service +@Slf4j +public class ProcessServiceImpl implements ProcessService { + + private static final String BPMN20_XML = "bpmn20.xml"; + + @Resource + private RepositoryService repositoryService; + + /** + * 上传流程文件,进行流程部署 + * @param multipartFile 上传文件 + */ + @Override + public void deployProcess(MultipartFile multipartFile) { + String fileName = multipartFile.getOriginalFilename(); + try (InputStream inputStream = multipartFile.getInputStream()){ + Deployment deployment = getDeplymentByType(inputStream,fileName); + //获取部署成功的流程模型 + List processDefinitions = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list(); + processDefinitions.forEach((processDefinition)->{ + //设置线上部署流程模型名字 + String proDefId= processDefinition.getId(); + repositoryService.setProcessDefinitionCategory(proDefId,fileName); + log.info("流程文件部署成功,流程ID="+proDefId); + }); + } catch (IOException e) { + log.error("流程部署出现异常"+e); + } + } + + + /** + * 根据上传文件类型对应实现不同方式的流程部署 + * @param inputStream 文件输入流 + * @param fileName 文件名 + * @return 文件部署流程 + */ + public Deployment getDeplymentByType(InputStream inputStream,String fileName){ + Deployment deployment; + String type = FilenameUtils.getExtension(fileName); + switch (type){ + case "bpmn": + String baseName = FilenameUtils.getBaseName(fileName); + deployment = repositoryService.createDeployment().addInputStream(baseName+"."+BPMN20_XML,inputStream).deploy(); + break; + case "png": + deployment = repositoryService.createDeployment().addInputStream(fileName,inputStream).deploy(); + break; + case "zip": + case "bar": + ZipInputStream zipInputStream = new ZipInputStream(inputStream); + deployment = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy(); + break; + default: + throw exception(FILE_UPLOAD_FAILED); + } + return deployment; + } +} diff --git a/yudao-admin-server/src/main/resources/application-local.yaml b/yudao-admin-server/src/main/resources/application-local.yaml index 53ab06560..ef485e083 100644 --- a/yudao-admin-server/src/main/resources/application-local.yaml +++ b/yudao-admin-server/src/main/resources/application-local.yaml @@ -43,17 +43,30 @@ spring: primary: master datasource: master: - name: ruoyi-vue-pro + name: ruoyi_vue_pro url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT driver-class-name: com.mysql.jdbc.Driver username: root - password: 123456 + password: root slave: # 模拟从库,可根据自己需要修改 - name: ruoyi-vue-pro + name: ruoyi_vue_pro url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT driver-class-name: com.mysql.jdbc.Driver username: root - password: 123456 + password: root + + + activiti: + #1.false:默认值,activiti启动时,对比数据库表中保存的版本,如果不匹配。将抛出异常 + #2.true:启动时会对数据库中所有表进行更新操作,如果表存在,不做处理,反之,自动创建表 + #3.create_drop:启动时自动创建表,关闭时自动删除表 + #4.drop_create:启动时,删除旧表,再创建新表 + database-schema-update: true + #activiti7默认不生成历史信息表,需手动设置开启 + db-history-used: true + check-process-definitions: true + history-level: full + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 redis: diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 42adcdf8a..e2989e6e2 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -396,6 +396,15 @@ ${aliyun-java-sdk-dysmsapi.version} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-activiti + ${revision} + + diff --git a/yudao-framework/pom.xml b/yudao-framework/pom.xml index 635dc7cf6..e9ff025f5 100644 --- a/yudao-framework/pom.xml +++ b/yudao-framework/pom.xml @@ -28,6 +28,7 @@ yudao-spring-boot-starter-biz-operatelog yudao-spring-boot-starter-biz-dict yudao-spring-boot-starter-biz-sms + yudao-spring-boot-starter-activiti yudao-framework diff --git a/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml b/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml new file mode 100644 index 000000000..f3acec5e2 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml @@ -0,0 +1,58 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-activiti + jar + + ${artifactId} + Activiti 拓展 + https://github.com/YunaiV/ruoyi-vue-pro + + + + 7.1.0.M6 + + + + + cn.iocoder.boot + yudao-common + + + + + org.activiti.dependencies + activiti-dependencies + ${activiti.version} + pom + + + + org.activiti + activiti-spring-boot-starter + ${activiti.version} + + + de.odysseus.juel + juel-api + + + de.odysseus.juel + juel-spi + + + org.mybatis + mybatis + + + + + + diff --git a/yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/package-info.java b/yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/package-info.java new file mode 100644 index 000000000..c49d90f93 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.framework.activiti; From b8ff47e832fc9e27e8a7d228b63370b1d8d71cd4 Mon Sep 17 00:00:00 2001 From: zhujiqian <924931408@qq.com> Date: Sun, 5 Sep 2021 22:57:38 +0800 Subject: [PATCH 02/60] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-admin-server/src/main/resources/application-local.yaml | 5 +++-- yudao-framework/yudao-spring-boot-starter-activiti/pom.xml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/yudao-admin-server/src/main/resources/application-local.yaml b/yudao-admin-server/src/main/resources/application-local.yaml index ef485e083..9676da09c 100644 --- a/yudao-admin-server/src/main/resources/application-local.yaml +++ b/yudao-admin-server/src/main/resources/application-local.yaml @@ -43,13 +43,13 @@ spring: primary: master datasource: master: - name: ruoyi_vue_pro + name: ruoyi-vue-pro url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT driver-class-name: com.mysql.jdbc.Driver username: root password: root slave: # 模拟从库,可根据自己需要修改 - name: ruoyi_vue_pro + name: ruoyi-vue-pro url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT driver-class-name: com.mysql.jdbc.Driver username: root @@ -65,6 +65,7 @@ spring: #activiti7默认不生成历史信息表,需手动设置开启 db-history-used: true check-process-definitions: true + #full:保存历史数据的最高级别,可保存全部流程相关细节,包括流程流转各节点参数 history-level: full diff --git a/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml b/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml index f3acec5e2..e9cee07f1 100644 --- a/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml @@ -33,7 +33,7 @@ ${activiti.version} pom - + org.activiti activiti-spring-boot-starter From e8b3f355e674e4f72c70cd1bb26c814a49ee2bdf Mon Sep 17 00:00:00 2001 From: zhujiqian <924931408@qq.com> Date: Sun, 5 Sep 2021 23:12:32 +0800 Subject: [PATCH 03/60] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activiti/service/process/impl/ProcessServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java index aa4e134f7..baebe8700 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java @@ -45,7 +45,7 @@ public class ProcessServiceImpl implements ProcessService { List processDefinitions = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list(); processDefinitions.forEach((processDefinition)->{ //设置线上部署流程模型名字 - String proDefId= processDefinition.getId(); + String proDefId = processDefinition.getId(); repositoryService.setProcessDefinitionCategory(proDefId,fileName); log.info("流程文件部署成功,流程ID="+proDefId); }); From 1bb10d007efc68e59864519d00f5edc6b242f895 Mon Sep 17 00:00:00 2001 From: zhujiqian <924931408@qq.com> Date: Tue, 7 Sep 2021 23:40:18 +0800 Subject: [PATCH 04/60] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=AE=9E=E4=BD=93=E6=BF=80=E6=B4=BB=E6=88=96?= =?UTF-8?q?=E6=8C=82=E8=B5=B7=E5=90=8E=E7=AB=AF=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../process/ProcessDefinitionDO.java | 29 +++++++++++++++++++ .../service/process/ProcessService.java | 13 ++++++++- .../process/impl/ProcessServiceImpl.java | 24 +++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/dataobject/process/ProcessDefinitionDO.java diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/dataobject/process/ProcessDefinitionDO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/dataobject/process/ProcessDefinitionDO.java new file mode 100644 index 000000000..7913d1ee6 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/dataobject/process/ProcessDefinitionDO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.process; + +/** + * 流程模型实体类 映射 activiti ProcessDefinition接口 + * + * @author ZJQ + * @date 2021/9/7 23:23 + */ +public class ProcessDefinitionDO { + + private String id; + + private String category; + + private String key; + + private String name; + + private String version; + + private String resourceName; + + private String deploymentId; + + private String diagramResourceName; + + private boolean suspended; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/ProcessService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/ProcessService.java index 4ef499658..bd829353d 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/ProcessService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/ProcessService.java @@ -11,8 +11,19 @@ import org.springframework.web.multipart.MultipartFile; public interface ProcessService { /** - * 上传流程文件,进行流程部署 + * 上传流程文件,进行流程模型部署 * @param multipartFile 上传文件 */ void deployProcess(MultipartFile multipartFile); + + + /** + * 激活或者挂起流程模型实体 + * @param processDefinitionId 流程模型实体id + * @param type 类型 + * @return 状态 + */ + String setActivOrHang(String processDefinitionId,String type); + + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java index baebe8700..2e3d04b1d 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/process/impl/ProcessServiceImpl.java @@ -54,6 +54,30 @@ public class ProcessServiceImpl implements ProcessService { } } + /** + * 激活或者挂起流程模型实体 + * @param processDefinitionId 流程模型实体id + * @param type 类型 + * @return 提示 + */ + @Override + public String setActivOrHang(String processDefinitionId, String type) { + String result = "无操作"; + switch (type){ + case "active": + repositoryService.activateProcessDefinitionById(processDefinitionId,true,null); + result = "已激活ID为【"+processDefinitionId+"】的流程模型实例"; + break; + case "suspend": + repositoryService.suspendProcessDefinitionById(processDefinitionId,true,null); + result = "已挂起ID为【"+processDefinitionId+"】的流程模型实例"; + break; + default: + break; + } + return result; + } + /** * 根据上传文件类型对应实现不同方式的流程部署 From ee8dcd08882f0bcd05c82760bf7ede0adee280bb Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Wed, 13 Oct 2021 23:43:03 +0800 Subject: [PATCH 05/60] =?UTF-8?q?1.=E5=AE=9E=E7=8E=B0=E4=BA=86=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E5=BC=95=E6=93=8E=20=E4=B8=AD=20=E8=AF=B7?= =?UTF-8?q?=E5=81=87=E6=B5=81=E7=A8=8Bdemo=EF=BC=88=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=9C=A8=20resources/leave.bpmn)=202.=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E4=B8=80=E7=BA=A7=E8=8F=9C=E5=8D=95=20OA=20?= =?UTF-8?q?=E5=8A=9E=E5=85=AC=20=E4=B8=8B=E9=9D=A2=E4=B8=A4=E4=B8=AA?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=EF=BC=9A=20=E8=AF=B7=E5=81=87=E7=94=B3?= =?UTF-8?q?=E8=AF=B7=EF=BC=8C=E5=BE=85=E5=8A=9E=E4=BB=BB=E5=8A=A1=203.?= =?UTF-8?q?=E6=9A=82=E6=97=B6=E4=B8=8D=E7=9F=A5=E5=A6=82=E4=BD=95=E6=89=BE?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E9=A2=86=E5=AF=BC=EF=BC=8C=20=E6=9A=82?= =?UTF-8?q?=E6=97=B6=E5=86=99=E6=AD=BB=E4=B8=BA=20admin=204.activity=20?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=BB=84=E4=BD=BF=E7=94=A8=20=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=B2=97=E4=BD=8D=E6=9D=A5=E4=BB=A3=E6=9B=BF=E3=80=82?= =?UTF-8?q?=205.=E6=96=B0=E5=A2=9E=E4=B8=80=E4=B8=AA=E7=94=A8=E6=88=B7=20h?= =?UTF-8?q?radmin=EF=BC=8C=20=E5=AF=86=E7=A0=81=20123456=20=20=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E6=98=AF=20=E4=BA=BA=E5=8A=9B=E8=B5=84=E6=BA=90=206.?= =?UTF-8?q?=E6=BC=94=E7=A4=BA=E6=B5=81=E7=A8=8B=E3=80=82=20=20=20a.=20admi?= =?UTF-8?q?n=20=E7=99=BB=E9=99=86=20=E7=94=B3=E8=AF=B7=E8=AF=B7=E5=81=87?= =?UTF-8?q?=20=20=20b.=20admin=20=E5=BE=85=E5=8A=9E=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=EF=BC=88=E5=AE=A1=E6=89=B9=EF=BC=89=20=20=20c.=20hradmin=20?= =?UTF-8?q?=E7=99=BB=E9=99=86=20=E5=BE=85=E5=8A=9E=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=EF=BC=88=E5=AE=A1=E6=89=B9=EF=BC=89=20=20=20d.=20admin=20?= =?UTF-8?q?=E7=99=BB=E9=99=86=20=E5=BE=85=E5=8A=9E=E4=BB=BB=E5=8A=A1=20?= =?UTF-8?q?=EF=BC=88=E7=A1=AE=E8=AE=A4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/ruoyi-vue-pro.sql | 43 +++ yudao-admin-server/pom.xml | 7 + .../controller/oa/OaLeaveController.java | 104 ++++++ .../controller/oa/vo/OaLeaveBaseVO.java | 48 +++ .../controller/oa/vo/OaLeaveCreateReqVO.java | 14 + .../controller/oa/vo/OaLeaveExcelVO.java | 44 +++ .../controller/oa/vo/OaLeaveExportReqVO.java | 54 +++ .../controller/oa/vo/OaLeavePageReqVO.java | 56 +++ .../controller/oa/vo/OaLeaveRespVO.java | 16 + .../controller/oa/vo/OaLeaveUpdateReqVO.java | 18 + .../controller/workflow/TaskController.java | 57 +++ .../controller/workflow/vo/TaskHandleVO.java | 19 + .../workflow/vo/TaskQueryReqVO.java | 15 + .../controller/workflow/vo/TaskReqVO.java | 17 + .../controller/workflow/vo/TaskStepVO.java | 22 ++ .../workflow/vo/TodoTaskPageReqVO.java | 16 + .../workflow/vo/TodoTaskRespVO.java | 30 ++ .../activiti/convert/oa/OaLeaveConvert.java | 34 ++ .../convert/workflow/TodoTaskConvert.java | 9 + .../activiti/dal/dataobject/oa/OaLeaveDO.java | 60 +++ .../activiti/dal/mysql/oa/OaLeaveMapper.java | 46 +++ .../activiti/enums/OaErrorCodeConstants.java | 13 + .../config/UserGroupManagerService.java | 61 +++ .../service/config/UserGroupsProvider.java | 31 ++ .../activiti/service/oa/OaLeaveService.java | 76 ++++ .../service/oa/ReportBackEndProcessor.java | 30 ++ .../service/oa/impl/OaLeaveServiceImpl.java | 112 ++++++ .../service/workflow/TaskService.java | 23 ++ .../workflow/impl/TaskServiceImpl.java | 264 +++++++++++++ .../service/auth/impl/SysAuthServiceImpl.java | 21 +- .../src/main/resources/application.yaml | 19 +- .../mybatis-config/mybatis-config.xml | 52 +++ .../src/main/resources/processes/leave.bpmn | 130 +++++++ yudao-admin-ui/src/api/oa/leave.js | 54 +++ yudao-admin-ui/src/api/oa/todo.js | 75 ++++ yudao-admin-ui/src/utils/dict.js | 3 + yudao-admin-ui/src/views/oa/leave/index.vue | 347 ++++++++++++++++++ yudao-admin-ui/src/views/oa/todo/index.vue | 284 ++++++++++++++ .../pom.xml | 25 +- .../config/YudaoActivitiConfiguration.java | 32 ++ .../pom.xml | 12 + .../framework/security/core/LoginUser.java | 22 +- .../core/util/SecurityFrameworkUtils.java | 7 +- 43 files changed, 2405 insertions(+), 17 deletions(-) create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/OaLeaveController.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveBaseVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveCreateReqVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveExcelVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveExportReqVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeavePageReqVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveRespVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveUpdateReqVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/TaskController.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskHandleVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskQueryReqVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskReqVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskStepVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskPageReqVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskRespVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/convert/oa/OaLeaveConvert.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/convert/workflow/TodoTaskConvert.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/dataobject/oa/OaLeaveDO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/mysql/oa/OaLeaveMapper.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/enums/OaErrorCodeConstants.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/config/UserGroupManagerService.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/config/UserGroupsProvider.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/OaLeaveService.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/ReportBackEndProcessor.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/impl/OaLeaveServiceImpl.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/TaskService.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/impl/TaskServiceImpl.java create mode 100644 yudao-admin-server/src/main/resources/mybatis-config/mybatis-config.xml create mode 100644 yudao-admin-server/src/main/resources/processes/leave.bpmn create mode 100644 yudao-admin-ui/src/api/oa/leave.js create mode 100644 yudao-admin-ui/src/api/oa/todo.js create mode 100644 yudao-admin-ui/src/views/oa/leave/index.vue create mode 100644 yudao-admin-ui/src/views/oa/todo/index.vue create mode 100644 yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/config/YudaoActivitiConfiguration.java diff --git a/sql/ruoyi-vue-pro.sql b/sql/ruoyi-vue-pro.sql index 35b521bb1..866c46b56 100644 --- a/sql/ruoyi-vue-pro.sql +++ b/sql/ruoyi-vue-pro.sql @@ -1108,6 +1108,12 @@ INSERT INTO `sys_dict_data` VALUES (76, 2, '接收失败', '20', 'sys_sms_receiv INSERT INTO `sys_dict_data` VALUES (77, 0, '调试(钉钉)', 'DEBUG_DING_TALK', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-13 00:20:37', '1', '2021-04-13 00:20:37', b'0'); INSERT INTO `sys_dict_data` VALUES (78, 1, '自动生成', '1', 'sys_error_code_type', 0, NULL, '1', '2021-04-21 00:06:48', '1', '2021-04-13 22:06:44', b'0'); INSERT INTO `sys_dict_data` VALUES (79, 2, '手动编辑', '2', 'sys_error_code_type', 0, NULL, '1', '2021-04-21 00:07:14', '1', '2021-04-13 22:06:49', b'0'); +INSERT INTO `sys_dict_data` VALUES (80,0,'病假','1','oa_leave_type',0,NULL,'1','2021-09-21 22:35:28','1','2021-09-21 14:59:27',0x00); +INSERT INTO `sys_dict_data` VALUES (81,1,'事假','2','oa_leave_type',0,NULL,'1','2021-09-21 22:36:11','1','2021-09-21 14:59:27',0x00); +INSERT INTO `sys_dict_data` VALUES (82,2,'婚假','3','oa_leave_type',0,NULL,'1','2021-09-21 22:36:38','1','2021-09-21 14:59:27',0x00); +INSERT INTO `sys_dict_data` VALUES (83,0,'处理中','1','oa_leave_status',0,NULL,'1','2021-09-21 22:46:46','1','2021-10-12 22:12:20',0x00); +INSERT INTO `sys_dict_data` VALUES (84,1,'流程结束','2','oa_leave_status',0,NULL,'1','2021-09-21 22:47:03','1','2021-10-12 22:12:58',0x00); +INSERT INTO `sys_dict_data` VALUES (85,2,'完成','3','oa_leave_status',0,NULL,'1','2021-09-21 22:47:25','1','2021-10-12 14:13:06',0x01); COMMIT; -- ---------------------------- @@ -1155,6 +1161,9 @@ INSERT INTO `sys_dict_type` VALUES (112, '短信模板的类型', 'sys_sms_templ INSERT INTO `sys_dict_type` VALUES (113, '短信发送状态', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:03', '1', '2021-04-11 09:30:02', b'0'); INSERT INTO `sys_dict_type` VALUES (114, '短信接收状态', 'sys_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:14', '1', '2021-04-11 20:27:14', b'0'); INSERT INTO `sys_dict_type` VALUES (115, '错误码的类型', 'sys_error_code_type', 0, NULL, '1', '2021-04-21 00:06:30', '1', '2021-04-13 22:07:12', b'0'); +INSERT INTO `sys_dict_type` VALUES (116,'请假类型','oa_leave_type',0,NULL,'1','2021-09-21 22:34:33','1','2021-09-21 15:00:38',0x00); +INSERT INTO `sys_dict_type` VALUES (117,'请假流程状态','oa_leave_status',0,NULL,'1','2021-09-21 22:46:04','1','2021-09-21 15:00:38',0x00); + COMMIT; -- ---------------------------- @@ -1357,6 +1366,7 @@ INSERT INTO `sys_menu` VALUES (1, '系统管理', '', 1, 1, 0, '/system', 'syste INSERT INTO `sys_menu` VALUES (2, '基础设施', '', 1, 2, 0, '/infra', 'monitor', NULL, 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:18:35', b'0'); INSERT INTO `sys_menu` VALUES (3, '研发工具', '', 1, 3, 0, '/tool', 'tool', NULL, 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-06 12:44:42', b'0'); INSERT INTO `sys_menu` VALUES (4, '若依官网', '', 1, 4, 0, 'http://ruoyi.vip', 'guide', NULL, 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 21:54:28', b'1'); +INSERT INTO `sys_menu` VALUES (5,'OA 办公','',1,4,0,'/oa','people',NULL,0,'admin','2021-09-20 16:26:19','1','2021-09-20 13:55:54',0x00); INSERT INTO `sys_menu` VALUES (100, '用户管理', 'system:user:list', 2, 1, 1, 'user', 'user', 'system/user/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0'); INSERT INTO `sys_menu` VALUES (101, '角色管理', '', 2, 2, 1, 'role', 'peoples', 'system/role/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:04:49', b'0'); INSERT INTO `sys_menu` VALUES (102, '菜单管理', '', 2, 3, 1, 'menu', 'tree-table', 'system/menu/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:04:28', b'0'); @@ -1485,6 +1495,14 @@ INSERT INTO `sys_menu` VALUES (1113, '错误码更新', 'system:error-code:updat INSERT INTO `sys_menu` VALUES (1114, '错误码删除', 'system:error-code:delete', 3, 4, 1110, '', '', '', 0, '', '2021-04-13 21:46:42', '', '2021-04-13 22:09:51', b'0'); INSERT INTO `sys_menu` VALUES (1115, '错误码导出', 'system:error-code:export', 3, 5, 1110, '', '', '', 0, '', '2021-04-13 21:46:42', '', '2021-04-13 22:09:55', b'0'); INSERT INTO `sys_menu` VALUES (1116, '日志中心', '', 2, 8, 2, 'log-center', 'log', 'infra/skywalking/log', 0, '1', '2021-04-26 22:35:45', '1', '2021-04-26 22:37:25', b'0'); +INSERT INTO `sys_menu` VALUES (1118,'请假申请','',2,0,5,'oa/leave','user','oa/leave/index',0,'','2021-09-20 08:51:03','1','2021-10-12 22:19:02',0x00); +INSERT INTO `sys_menu` VALUES (1119,'请假申请查询','oa:leave:query',3,1,1118,'','','',0,'','2021-09-20 08:51:03','','2021-09-20 08:51:03',0x00); +INSERT INTO `sys_menu` VALUES (1120,'请假申请创建','oa:leave:create',3,2,1118,'','','',0,'','2021-09-20 08:51:03','','2021-09-20 08:51:03',0x00); +INSERT INTO `sys_menu` VALUES (1121,'请假申请更新','oa:leave:update',3,3,1118,'','','',0,'','2021-09-20 08:51:03','','2021-09-20 08:51:03',0x00); +INSERT INTO `sys_menu` VALUES (1122,'请假申请删除','oa:leave:delete',3,4,1118,'','','',0,'','2021-09-20 08:51:03','','2021-09-20 08:51:03',0x00); +INSERT INTO `sys_menu` VALUES (1123,'请假申请导出','oa:leave:export',3,5,1118,'','','',0,'','2021-09-20 08:51:03','','2021-09-20 08:51:03',0x00); +INSERT INTO `sys_menu` VALUES (1124,'待办任务','',2,2,5,'todo','edit','oa/todo/index',0,'1','2021-09-20 22:10:09','1','2021-09-21 23:17:12',0x00); + COMMIT; -- ---------------------------- @@ -1958,6 +1976,7 @@ INSERT INTO `sys_user` VALUES (2, 'ry', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ul INSERT INTO `sys_user` VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 100, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '', NULL, '', '2021-01-07 09:07:17', '1', '2021-03-14 22:35:17', b'0'); INSERT INTO `sys_user` VALUES (103, 'yuanma', '', '源码', NULL, 100, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '', NULL, '', '2021-01-13 23:50:35', '', '2021-01-13 23:50:35', b'0'); INSERT INTO `sys_user` VALUES (104, 'test', '$2a$10$.TOFpaIiI3PzEwkGrNq0Eu6Cc3rOqJMxTb1DqeSEM8StxaGPBRKoi', '测试号', NULL, 100, '[]', '', '15601691200', 1, '', 0, '', NULL, '', '2021-01-21 02:13:53', '1', '2021-03-14 22:36:38', b'0'); +INSERT INTO `sys_user` VALUES (105,'hradmin','$2a$10$JEhJOL25X1eMnFfR3PILo.MoAljf29YukpL2w6H9GvVGjmqOCuh.O','hr-mgr','hr 管理员',100,'[3]','','',1,'',0,'',NULL,'1','2021-09-25 16:50:41','1','2021-09-25 01:14:09',0x00); COMMIT; -- ---------------------------- @@ -1987,6 +2006,7 @@ INSERT INTO `sys_user_role` VALUES (4, 100, 101, '', NULL, '', NULL, b'0'); INSERT INTO `sys_user_role` VALUES (5, 100, 1, '', NULL, '', NULL, b'0'); INSERT INTO `sys_user_role` VALUES (6, 100, 2, '', NULL, '', NULL, b'0'); INSERT INTO `sys_user_role` VALUES (7, 104, 101, '', NULL, '', NULL, b'0'); +INSERT INTO `sys_user_role` VALUES (8,105,1,'1','2021-09-25 16:51:44','1','2021-09-25 16:51:44',0x00); COMMIT; -- ---------------------------- @@ -2425,4 +2445,27 @@ INSERT INTO `tool_test_demo` VALUES (106, '老五1', 0, 1, 1, '牛逼哈2', '', INSERT INTO `tool_test_demo` VALUES (107, '哈哈哈哈', 1, 0, 1, 'biubiubui', '', '2021-02-06 14:00:54', '', '2021-02-06 14:00:54', b'0'); COMMIT; + +DROP TABLE IF EXISTS `oa_leave`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `oa_leave` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '请假表单主键', + `process_instance_id` varchar(64) DEFAULT NULL COMMENT '流程id', + `status` tinyint(4) NOT NULL COMMENT '状态', + `user_id` varchar(20) NOT NULL COMMENT '申请人id', + `start_time` datetime NOT NULL COMMENT '开始时间', + `end_time` datetime NOT NULL COMMENT '结束时间', + `leave_type` varchar(20) DEFAULT NULL COMMENT '请假类型', + `reason` varchar(2000) DEFAULT NULL COMMENT '原因', + `apply_time` datetime NOT NULL COMMENT '申请时间', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='请假申请表'; +/*!40101 SET character_set_client = @saved_cs_client */; + SET FOREIGN_KEY_CHECKS = 1; diff --git a/yudao-admin-server/pom.xml b/yudao-admin-server/pom.xml index 7a04d6647..624feb2a9 100644 --- a/yudao-admin-server/pom.xml +++ b/yudao-admin-server/pom.xml @@ -31,6 +31,11 @@ yudao-spring-boot-starter-biz-sms + + cn.iocoder.boot + yudao-spring-boot-starter-activiti + + cn.iocoder.boot @@ -107,6 +112,8 @@ yudao-spring-boot-starter-excel + + org.apache.velocity velocity-engine-core diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/OaLeaveController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/OaLeaveController.java new file mode 100644 index 000000000..e8dd527b9 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/OaLeaveController.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa; + +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; + +import io.swagger.annotations.*; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.*; +import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO; +import cn.iocoder.yudao.adminserver.modules.activiti.convert.oa.OaLeaveConvert; +import cn.iocoder.yudao.adminserver.modules.activiti.service.oa.OaLeaveService; + +@Api(tags = "请假申请") +@RestController +@RequestMapping("/oa/leave") +@Validated +public class OaLeaveController { + + @Resource + private OaLeaveService leaveService; + + @PostMapping("/create") + @ApiOperation("创建请假申请") + @PreAuthorize("@ss.hasPermission('oa:leave:create')") + public CommonResult createLeave(@Valid @RequestBody OaLeaveCreateReqVO createReqVO) { + return success(leaveService.createLeave(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新请假申请") + @PreAuthorize("@ss.hasPermission('oa:leave:update')") + public CommonResult updateLeave(@Valid @RequestBody OaLeaveUpdateReqVO updateReqVO) { + leaveService.updateLeave(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除请假申请") + @ApiImplicitParam(name = "id", value = "编号", required = true) + @PreAuthorize("@ss.hasPermission('oa:leave:delete')") + public CommonResult deleteLeave(@RequestParam("id") Long id) { + leaveService.deleteLeave(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得请假申请") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('oa:leave:query')") + public CommonResult getLeave(@RequestParam("id") Long id) { + OaLeaveDO leave = leaveService.getLeave(id); + return success(OaLeaveConvert.INSTANCE.convert(leave)); + } + + @GetMapping("/list") + @ApiOperation("获得请假申请列表") + @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class) + @PreAuthorize("@ss.hasPermission('oa:leave:query')") + public CommonResult> getLeaveList(@RequestParam("ids") Collection ids) { + List list = leaveService.getLeaveList(ids); + return success(OaLeaveConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/page") + @ApiOperation("获得请假申请分页") + @PreAuthorize("@ss.hasPermission('oa:leave:query')") + public CommonResult> getLeavePage(@Valid OaLeavePageReqVO pageVO) { + //值查询自己申请请假 + pageVO.setUserId(SecurityFrameworkUtils.getLoginUser().getUsername()); + PageResult pageResult = leaveService.getLeavePage(pageVO); + return success(OaLeaveConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/export-excel") + @ApiOperation("导出请假申请 Excel") + @PreAuthorize("@ss.hasPermission('oa:leave:export')") + @OperateLog(type = EXPORT) + public void exportLeaveExcel(@Valid OaLeaveExportReqVO exportReqVO, + HttpServletResponse response) throws IOException { + List list = leaveService.getLeaveList(exportReqVO); + // 导出 Excel + List datas = OaLeaveConvert.INSTANCE.convertList02(list); + ExcelUtils.write(response, "请假申请.xls", "数据", OaLeaveExcelVO.class, datas); + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveBaseVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveBaseVO.java new file mode 100644 index 000000000..ed7f458af --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveBaseVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** +* 请假申请 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class OaLeaveBaseVO { + + @ApiModelProperty(value = "流程id") + private String processInstanceId; + + @ApiModelProperty(value = "状态", required = true) + private Integer status; + + @ApiModelProperty(value = "申请人id", required = true) + private String userId; + + @ApiModelProperty(value = "开始时间", required = true) + @NotNull(message = "开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date startTime; + + @ApiModelProperty(value = "结束时间", required = true) + @NotNull(message = "结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date endTime; + + @ApiModelProperty(value = "请假类型") + private String leaveType; + + @ApiModelProperty(value = "原因") + private String reason; + + @ApiModelProperty(value = "申请时间", required = true) + @NotNull(message = "申请时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date applyTime; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveCreateReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveCreateReqVO.java new file mode 100644 index 000000000..29cede1ff --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +@ApiModel("请假申请创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OaLeaveCreateReqVO extends OaLeaveBaseVO { + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveExcelVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveExcelVO.java new file mode 100644 index 000000000..6c309c180 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveExcelVO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; + +import com.alibaba.excel.annotation.ExcelProperty; + +/** + * 请假申请 Excel VO + * + * @author 芋艿 + */ +@Data +public class OaLeaveExcelVO { + + @ExcelProperty("请假表单主键") + private Long id; + + @ExcelProperty("流程id") + private String processInstanceId; + + @ExcelProperty("状态") + private Integer status; + + @ExcelProperty("申请人id") + private String userId; + + @ExcelProperty("开始时间") + private Date startTime; + + @ExcelProperty("结束时间") + private Date endTime; + + @ExcelProperty("请假类型") + private String leaveType; + + @ExcelProperty("原因") + private String reason; + + @ExcelProperty("申请时间") + private Date applyTime; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveExportReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveExportReqVO.java new file mode 100644 index 000000000..811c50205 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveExportReqVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel(value = "请假申请 Excel 导出 Request VO", description = "参数和 OaLeavePageReqVO 是一致的") +@Data +public class OaLeaveExportReqVO { + + @ApiModelProperty(value = "流程id") + private String processInstanceId; + + @ApiModelProperty(value = "状态") + private Integer status; + + @ApiModelProperty(value = "申请人id") + private String userId; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始开始时间") + private Date beginStartTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束开始时间") + private Date endStartTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始结束时间") + private Date beginEndTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束结束时间") + private Date endEndTime; + + @ApiModelProperty(value = "请假类型") + private String leaveType; + + @ApiModelProperty(value = "原因") + private String reason; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始申请时间") + private Date beginApplyTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束申请时间") + private Date endApplyTime; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeavePageReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeavePageReqVO.java new file mode 100644 index 000000000..fe879c4ae --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeavePageReqVO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("请假申请分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OaLeavePageReqVO extends PageParam { + + @ApiModelProperty(value = "流程id") + private String processInstanceId; + + @ApiModelProperty(value = "状态") + private Integer status; + + @ApiModelProperty(value = "申请人id") + private String userId; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始开始时间") + private Date beginStartTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束开始时间") + private Date endStartTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始结束时间") + private Date beginEndTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束结束时间") + private Date endEndTime; + + @ApiModelProperty(value = "请假类型") + private String leaveType; + + @ApiModelProperty(value = "原因") + private String reason; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始申请时间") + private Date beginApplyTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束申请时间") + private Date endApplyTime; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveRespVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveRespVO.java new file mode 100644 index 000000000..7f359d7b1 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; + +@ApiModel("请假申请 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OaLeaveRespVO extends OaLeaveBaseVO { + + @ApiModelProperty(value = "请假表单主键", required = true) + private Long id; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveUpdateReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveUpdateReqVO.java new file mode 100644 index 000000000..dc81fa31e --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveUpdateReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +@ApiModel("请假申请更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OaLeaveUpdateReqVO extends OaLeaveBaseVO { + + @ApiModelProperty(value = "请假表单主键", required = true) + @NotNull(message = "请假表单主键不能为空") + private Long id; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/TaskController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/TaskController.java new file mode 100644 index 000000000..3a717f116 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/TaskController.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow; + +import cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo.*; +import cn.iocoder.yudao.adminserver.modules.activiti.service.workflow.TaskService; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "工作流待办任务") +@RestController +@RequestMapping("/workflow/task") +public class TaskController { + + @Resource + private TaskService taskService; + + + + @GetMapping("/todo/page") + @ApiOperation("获取待办任务分页") + public CommonResult> getTodoTaskPage(@Valid TodoTaskPageReqVO pageVO) { + return success(taskService.getTodoTaskPage(pageVO)); + } + + @GetMapping("/claim") + @ApiOperation("签收任务") + public CommonResult claimTask(@RequestParam("id") String taskId) { + taskService.claimTask(taskId); + return success(true); + } + + + @PostMapping("/task-steps") + public CommonResult getTaskSteps(@RequestBody TaskQueryReqVO taskQuery) { + return success( taskService.getTaskSteps(taskQuery)); + } + + @PostMapping("/complete") + public CommonResult complete(@RequestBody TaskReqVO taskReq) { + taskService.completeTask(taskReq); + return success(true); + } + + + @GetMapping("/process/history-steps") + public CommonResult> getHistorySteps(@RequestParam("id") String processInstanceId) { + return success( taskService.getHistorySteps(processInstanceId)); + } +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskHandleVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskHandleVO.java new file mode 100644 index 000000000..3ef40fa32 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskHandleVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo; + +import lombok.Data; +import lombok.ToString; + +import java.util.List; + +@Data +@ToString +public class TaskHandleVO { + + private Object formObject; + + + private List historyTask; + + + private String taskVariable; +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskQueryReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskQueryReqVO.java new file mode 100644 index 000000000..fab24a948 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskQueryReqVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo; + +import lombok.Data; +import lombok.ToString; + +@Data +@ToString +public class TaskQueryReqVO { + + private String processKey; + + private String taskId; + + private String businessKey; +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskReqVO.java new file mode 100644 index 000000000..8e3eb6079 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo; + +import lombok.Data; +import lombok.ToString; + +import java.util.Map; + +@Data +@ToString +public class TaskReqVO { + + private String taskId; + + private Map variables; + + private String comment; +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskStepVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskStepVO.java new file mode 100644 index 000000000..fe2335562 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskStepVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo; + +import lombok.Data; +import lombok.ToString; + +import java.util.Date; + +@Data +@ToString +public class TaskStepVO { + + private String stepName; + + private Date startTime; + + private Date endTime; + + private String assignee; + + private String comment; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskPageReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskPageReqVO.java new file mode 100644 index 000000000..b5dddbc61 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskPageReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ApiModel("待办任务申请分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class TodoTaskPageReqVO extends PageParam { + + private String assignee; +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskRespVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskRespVO.java new file mode 100644 index 000000000..5fef60eb5 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ApiModel("待办任务 Response VO") +@Data +@ToString +public class TodoTaskRespVO { + + private String id; + + /** + * 1:未签收 + * 2:已签收 + */ + private Integer status; + + + private String processName; + + + private String processKey; + + + private String businessKey; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/convert/oa/OaLeaveConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/convert/oa/OaLeaveConvert.java new file mode 100644 index 000000000..cabf892fe --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/convert/oa/OaLeaveConvert.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.convert.oa; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; +import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.*; +import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO; + +/** + * 请假申请 Convert + * + * @author 芋艿 + */ +@Mapper +public interface OaLeaveConvert { + + OaLeaveConvert INSTANCE = Mappers.getMapper(OaLeaveConvert.class); + + OaLeaveDO convert(OaLeaveCreateReqVO bean); + + OaLeaveDO convert(OaLeaveUpdateReqVO bean); + + OaLeaveRespVO convert(OaLeaveDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + List convertList02(List list); + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/convert/workflow/TodoTaskConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/convert/workflow/TodoTaskConvert.java new file mode 100644 index 000000000..787cbadd3 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/convert/workflow/TodoTaskConvert.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.convert.workflow; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface TodoTaskConvert { + TodoTaskConvert INSTANCE = Mappers.getMapper(TodoTaskConvert.class); +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/dataobject/oa/OaLeaveDO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/dataobject/oa/OaLeaveDO.java new file mode 100644 index 000000000..dc0aae769 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/dataobject/oa/OaLeaveDO.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa; + +import lombok.*; +import java.util.*; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 请假申请 DO + * + * @author 芋艿 + */ +@TableName("oa_leave") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OaLeaveDO extends BaseDO { + + /** + * 请假表单主键 + */ + @TableId + private Long id; + /** + * 流程id + */ + private String processInstanceId; + /** + * 状态 + */ + private Integer status; + /** + * 申请人id + */ + private String userId; + /** + * 开始时间 + */ + private Date startTime; + /** + * 结束时间 + */ + private Date endTime; + /** + * 请假类型 + */ + private String leaveType; + /** + * 原因 + */ + private String reason; + /** + * 申请时间 + */ + private Date applyTime; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/mysql/oa/OaLeaveMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/mysql/oa/OaLeaveMapper.java new file mode 100644 index 000000000..6a641c6c0 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/dal/mysql/oa/OaLeaveMapper.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.oa; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.*; + +/** + * 请假申请 Mapper + * + * @author 芋艿 + */ +@Mapper +public interface OaLeaveMapper extends BaseMapperX { + + default PageResult selectPage(OaLeavePageReqVO reqVO) { + return selectPage(reqVO, new QueryWrapperX() + .eqIfPresent("process_instance_id", reqVO.getProcessInstanceId()) + .eqIfPresent("status", reqVO.getStatus()) + .eqIfPresent("user_id", reqVO.getUserId()) + .betweenIfPresent("start_time", reqVO.getBeginStartTime(), reqVO.getEndStartTime()) + .betweenIfPresent("end_time", reqVO.getBeginEndTime(), reqVO.getEndEndTime()) + .eqIfPresent("leave_type", reqVO.getLeaveType()) + .eqIfPresent("reason", reqVO.getReason()) + .betweenIfPresent("apply_time", reqVO.getBeginApplyTime(), reqVO.getEndApplyTime()) + .orderByDesc("id") ); + } + + default List selectList(OaLeaveExportReqVO reqVO) { + return selectList(new QueryWrapperX() + .eqIfPresent("process_instance_id", reqVO.getProcessInstanceId()) + .eqIfPresent("status", reqVO.getStatus()) + .eqIfPresent("user_id", reqVO.getUserId()) + .betweenIfPresent("start_time", reqVO.getBeginStartTime(), reqVO.getEndStartTime()) + .betweenIfPresent("end_time", reqVO.getBeginEndTime(), reqVO.getEndEndTime()) + .eqIfPresent("leave_type", reqVO.getLeaveType()) + .eqIfPresent("reason", reqVO.getReason()) + .betweenIfPresent("apply_time", reqVO.getBeginApplyTime(), reqVO.getEndApplyTime()) + .orderByDesc("id") ); + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/enums/OaErrorCodeConstants.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/enums/OaErrorCodeConstants.java new file mode 100644 index 000000000..78a946112 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/enums/OaErrorCodeConstants.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +/** + * activiti 系统 错误码枚举类 + * + * 003 activiti + * 001 oa + * activiti 系统,使用 1-003-000-000 段 + */ +public interface OaErrorCodeConstants { + ErrorCode LEAVE_NOT_EXISTS = new ErrorCode(1003001001, "请假申请不存在"); +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/config/UserGroupManagerService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/config/UserGroupManagerService.java new file mode 100644 index 000000000..0b10f3c53 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/config/UserGroupManagerService.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.service.config; + +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO; +import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService; +import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService; +import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import org.activiti.api.runtime.shared.identity.UserGroupManager; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Service; + + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +import static java.util.Collections.singleton; + +@Service +public class UserGroupManagerService implements UserGroupManager { + + @Resource + private UserDetailsService userDetailsService; + + @Resource + private SysUserService userService; + + @Resource + private SysPostService sysPostService; + + /** + * 暂时使用岗位来代替 + * @param userId + * @return + */ + @Override + public List getUserGroups(String userId) { + final LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(userId); + final Long id = loginUser.getId(); + final SysUserDO user = userService.getUser(id); + return sysPostService.getPosts(user.getPostIds()).stream().map(post -> post.getCode()).collect(Collectors.toList()); + + } + + @Override + public List getUserRoles(String userId) { + return Arrays.asList("ROLE_ACTIVITI_USER"); + } + + @Override + public List getGroups() { + throw new UnsupportedOperationException("getGroups is now un supported"); + } + + @Override + public List getUsers() { + throw new UnsupportedOperationException("getGroups is now un supported"); + } +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/config/UserGroupsProvider.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/config/UserGroupsProvider.java new file mode 100644 index 000000000..3f8b55299 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/config/UserGroupsProvider.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.service.config; + +import cn.iocoder.yudao.framework.security.core.LoginUser; +import org.activiti.api.runtime.shared.security.PrincipalGroupsProvider; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +import java.security.Principal; +import java.util.Collections; +import java.util.List; + +@Service +public class UserGroupsProvider implements PrincipalGroupsProvider { + + @Override + public List getGroups(Principal principal) { + + if(principal instanceof Authentication){ + Authentication authentication = (Authentication) principal; + final Object user = authentication.getPrincipal(); + if( user instanceof LoginUser){ + return ((LoginUser) user).getGroups(); + }else{ + return Collections.emptyList(); + } + }else{ + return Collections.emptyList(); + } + + } +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/OaLeaveService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/OaLeaveService.java new file mode 100644 index 000000000..f5c84115a --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/OaLeaveService.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.service.oa; + + +import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeaveCreateReqVO; +import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeaveExportReqVO; +import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeavePageReqVO; +import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeaveUpdateReqVO; +import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 请假申请 Service 接口 + * + * @author 芋艿 + */ +public interface OaLeaveService { + + /** + * 创建请假申请 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createLeave(@Valid OaLeaveCreateReqVO createReqVO); + + /** + * 更新请假申请 + * + * @param updateReqVO 更新信息 + */ + void updateLeave(@Valid OaLeaveUpdateReqVO updateReqVO); + + /** + * 删除请假申请 + * + * @param id 编号 + */ + void deleteLeave(Long id); + + /** + * 获得请假申请 + * + * @param id 编号 + * @return 请假申请 + */ + OaLeaveDO getLeave(Long id); + + /** + * 获得请假申请列表 + * + * @param ids 编号 + * @return 请假申请列表 + */ + List getLeaveList(Collection ids); + + /** + * 获得请假申请分页 + * + * @param pageReqVO 分页查询 + * @return 请假申请分页 + */ + PageResult getLeavePage(OaLeavePageReqVO pageReqVO); + + /** + * 获得请假申请列表, 用于 Excel 导出 + * + * @param exportReqVO 查询条件 + * @return 请假申请列表 + */ + List getLeaveList(OaLeaveExportReqVO exportReqVO); + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/ReportBackEndProcessor.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/ReportBackEndProcessor.java new file mode 100644 index 000000000..05ed6fb7d --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/ReportBackEndProcessor.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.service.oa; + +import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO; +import cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.oa.OaLeaveMapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import org.activiti.engine.delegate.DelegateTask; +import org.activiti.engine.delegate.TaskListener; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; + +@Component +public class ReportBackEndProcessor implements TaskListener { + + @Resource + private OaLeaveMapper leaveMapper; + + + @Override + @Transactional(rollbackFor = Exception.class) + public void notify(DelegateTask delegateTask) { + final String businessKey = delegateTask.getExecution().getProcessInstanceBusinessKey(); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("id", Long.valueOf(businessKey)); + OaLeaveDO updateDo = new OaLeaveDO(); + updateDo.setStatus(2); + leaveMapper.update(updateDo, updateWrapper); + } +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/impl/OaLeaveServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/impl/OaLeaveServiceImpl.java new file mode 100644 index 000000000..c82e7a100 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/impl/OaLeaveServiceImpl.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.service.oa.impl; + +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import org.activiti.engine.RuntimeService; +import org.activiti.engine.runtime.ProcessInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import javax.annotation.Resource; + +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.util.*; +import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.*; +import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import cn.iocoder.yudao.adminserver.modules.activiti.convert.oa.OaLeaveConvert; +import cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.oa.OaLeaveMapper; +import cn.iocoder.yudao.adminserver.modules.activiti.service.oa.OaLeaveService; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.adminserver.modules.activiti.enums.OaErrorCodeConstants.*; + +/** + * 请假申请 Service 实现类 + * + * @author 芋艿 + */ +@Service +@Validated +public class OaLeaveServiceImpl implements OaLeaveService { + + @Resource + private OaLeaveMapper leaveMapper; + + @Resource + private RuntimeService runtimeService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createLeave(OaLeaveCreateReqVO createReqVO) { + // 插入 + OaLeaveDO leave = OaLeaveConvert.INSTANCE.convert(createReqVO); + leave.setStatus(1); + leave.setUserId(SecurityFrameworkUtils.getLoginUser().getUsername()); + leaveMapper.insert(leave); + + Map variables = new HashMap<>(); + //如何得到部门领导人, 暂时写死 + variables.put("deptLeader", "admin"); + final Long id = leave.getId(); + String businessKey = String.valueOf(id); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leave", businessKey, variables); + + final String processInstanceId = processInstance.getProcessInstanceId(); + + + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("id", id); + OaLeaveDO updateDo = new OaLeaveDO(); + updateDo.setProcessInstanceId(processInstanceId); + leaveMapper.update(updateDo, updateWrapper); + // 返回 + return id; + } + + @Override + public void updateLeave(OaLeaveUpdateReqVO updateReqVO) { + // 校验存在 + this.validateLeaveExists(updateReqVO.getId()); + // 更新 + OaLeaveDO updateObj = OaLeaveConvert.INSTANCE.convert(updateReqVO); + leaveMapper.updateById(updateObj); + } + + @Override + public void deleteLeave(Long id) { + // 校验存在 + this.validateLeaveExists(id); + // 删除 + leaveMapper.deleteById(id); + } + + private void validateLeaveExists(Long id) { + if (leaveMapper.selectById(id) == null) { + throw exception(LEAVE_NOT_EXISTS); + } + } + + @Override + public OaLeaveDO getLeave(Long id) { + return leaveMapper.selectById(id); + } + + @Override + public List getLeaveList(Collection ids) { + return leaveMapper.selectBatchIds(ids); + } + + @Override + public PageResult getLeavePage(OaLeavePageReqVO pageReqVO) { + return leaveMapper.selectPage(pageReqVO); + } + + @Override + public List getLeaveList(OaLeaveExportReqVO exportReqVO) { + return leaveMapper.selectList(exportReqVO); + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/TaskService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/TaskService.java new file mode 100644 index 000000000..ae0783b48 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/TaskService.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.service.workflow; + +import cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo.*; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +public interface TaskService { + + PageResult getTodoTaskPage(TodoTaskPageReqVO pageReqVO); + + void claimTask(String taskId); + + void getTaskHistory(String taskId); + + void completeTask(TaskReqVO taskReq); + +// void flowImage(String taskId, HttpServletResponse response); + TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery); + + List getHistorySteps(String processInstanceId); +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/impl/TaskServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/impl/TaskServiceImpl.java new file mode 100644 index 000000000..aae12755b --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/impl/TaskServiceImpl.java @@ -0,0 +1,264 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.service.workflow.impl; + +import cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo.*; +import cn.iocoder.yudao.adminserver.modules.activiti.convert.oa.OaLeaveConvert; +import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO; +import cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.oa.OaLeaveMapper; +import cn.iocoder.yudao.adminserver.modules.activiti.service.oa.OaLeaveService; +import cn.iocoder.yudao.adminserver.modules.activiti.service.workflow.TaskService; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.google.common.collect.ImmutableMap; +import org.activiti.api.process.runtime.ProcessRuntime; +import org.activiti.api.runtime.shared.query.Page; +import org.activiti.api.runtime.shared.query.Pageable; +import org.activiti.api.task.model.Task; +import org.activiti.api.task.model.builders.ClaimTaskPayloadBuilder; +import org.activiti.api.task.model.builders.GetTasksPayloadBuilder; +import org.activiti.api.task.model.builders.TaskPayloadBuilder; +import org.activiti.api.task.runtime.TaskRuntime; +import org.activiti.bpmn.model.BpmnModel; +import org.activiti.bpmn.model.Process; +import org.activiti.engine.HistoryService; +import org.activiti.engine.RepositoryService; +import org.activiti.engine.history.HistoricActivityInstance; +import org.activiti.engine.history.HistoricProcessInstance; +import org.activiti.engine.history.HistoricVariableInstance; +import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; +import org.activiti.engine.repository.ProcessDefinition; +import org.activiti.engine.task.Comment; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +@Service +public class TaskServiceImpl implements TaskService { + + @Resource + private TaskRuntime taskRuntime; + + @Resource + private org.activiti.engine.TaskService activitiTaskService; + + @Resource + private HistoryService historyService; + + @Resource + private RepositoryService repositoryService; + + @Resource + private OaLeaveMapper leaveMapper; + + private static Map taskVariable = ImmutableMap.builder() + .put("deptLeaderVerify","deptLeaderApproved") + .put("hrVerify","hrApproved") + .build(); + + public TaskServiceImpl() { + + } + + @Override + public PageResult getTodoTaskPage(TodoTaskPageReqVO pageReqVO) { + final LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + final Pageable pageable = Pageable.of((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize(), pageReqVO.getPageSize()); + Page pageTasks = taskRuntime.tasks(pageable); + List tasks = pageTasks.getContent(); + int totalItems = pageTasks.getTotalItems(); + final List respVOList = tasks.stream().map(task -> { + TodoTaskRespVO respVO = new TodoTaskRespVO(); + respVO.setId(task.getId()); + final ProcessDefinition definition = repositoryService.getProcessDefinition(task.getProcessDefinitionId()); + respVO.setProcessName(definition.getName()); + respVO.setProcessKey(definition.getKey()); + respVO.setBusinessKey(task.getBusinessKey()); + respVO.setStatus(task.getAssignee() == null ? 1 : 2); + return respVO; + }).collect(Collectors.toList()); + return new PageResult(respVOList, Long.valueOf(totalItems)); + } + + + @Override + public void claimTask(String taskId) { + taskRuntime.claim(new ClaimTaskPayloadBuilder() + .withTaskId(taskId) + .withAssignee(SecurityFrameworkUtils.getLoginUser().getUsername()) + .build()); + } + + @Override + public void getTaskHistory(String taskId) { + + final List list = historyService.createHistoricProcessInstanceQuery(). + processInstanceId("8e2801fc-1a38-11ec-98ce-74867a13730f").list(); + + } + + @Override + @Transactional + public void completeTask(TaskReqVO taskReq) { + final Task task = taskRuntime.task(taskReq.getTaskId()); + + final Map variables = taskReq.getVariables(); + + activitiTaskService.addComment(taskReq.getTaskId(), task.getProcessInstanceId(), taskReq.getComment()); + + taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskReq.getTaskId()) + .withVariables(taskReq.getVariables()) + .build()); + + if(variables.containsValue(Boolean.FALSE)){ + final String businessKey = task.getBusinessKey(); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("id", Long.valueOf(businessKey)); + OaLeaveDO updateDo = new OaLeaveDO(); + updateDo.setStatus(2); + leaveMapper.update(updateDo, updateWrapper); + } + + } + +// @Override +// public void flowImage(String taskId, HttpServletResponse response) { +// +// final Task task = taskRuntime.task(taskId); +// BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId()); +// final Process process = bpmnModel.getMainProcess(); +// ProcessDefinitionEntity processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult(); +// List activeActivityIds = runtimeService.getActiveActivityIds(executionId); +// List highLightedFlows = getHighLightedFlows(processDefinition, processInstance.getId()); +// ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator(); +// InputStream imageStream =diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds, highLightedFlows); +// +// // 输出资源内容到相应对象 +// byte[] b = new byte[1024]; +// int len; +// while ((len = imageStream.read(b, 0, 1024)) != -1) { +// response.getOutputStream().write(b, 0, len); +// } +// } + + @Override + public TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery) { + TaskHandleVO handleVO = new TaskHandleVO(); + + String processKey = taskQuery.getProcessKey(); + if ("leave".equals(processKey)) { + String businessKey = taskQuery.getBusinessKey(); + final OaLeaveDO leave = leaveMapper.selectById(Long.valueOf(businessKey)); + handleVO.setFormObject( OaLeaveConvert.INSTANCE.convert(leave)); + } + + final Task task = taskRuntime.task(taskQuery.getTaskId()); + final String taskDefKey = task.getTaskDefinitionKey(); + final String variableName = Optional.ofNullable(taskVariable.get(taskDefKey)).orElse(""); + + + handleVO.setTaskVariable(variableName); + List steps = getTaskSteps(task.getProcessInstanceId()); + + handleVO.setHistoryTask(steps); + return handleVO; + } + + + private List getTaskSteps(String processInstanceId) { + + List steps = new ArrayList<>(); + + List finished = historyService + .createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId) + .activityType("userTask") + .finished() + .orderByHistoricActivityInstanceStartTime().asc().list(); + + finished.forEach(instance->{ + TaskStepVO step = new TaskStepVO(); + step.setStepName(instance.getActivityName()); + step.setStartTime(instance.getStartTime()); + step.setEndTime(instance.getEndTime()); + step.setAssignee(instance.getAssignee()); + final List comments = activitiTaskService.getTaskComments(instance.getTaskId()); + if(comments.size()>0){ + step.setComment(comments.get(0).getFullMessage()); + }else{ + step.setComment(""); + } + steps.add(step); + }); + + List unfinished = historyService + .createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId) + .activityType("userTask") + .unfinished().list(); + + if(unfinished.size()>0) { + + final HistoricActivityInstance unFinishedActiviti = unfinished.get(0); + TaskStepVO step = new TaskStepVO(); + step.setStepName(unFinishedActiviti.getActivityName()); + step.setStartTime(unFinishedActiviti.getStartTime()); + step.setEndTime(unFinishedActiviti.getEndTime()); + step.setAssignee(Optional.ofNullable(unFinishedActiviti.getAssignee()).orElse("")); + step.setComment(""); + steps.add(step); + } + return steps; + } + + + @Override + public List getHistorySteps(String processInstanceId) { + + return getTaskSteps(processInstanceId); + } + + + +// private List getHighLightedFlows(ProcessDefinitionEntity processDefinition, String processInstanceId) { +// +// List highLightedFlows = new ArrayList(); +// List historicActivityInstances = historyService +// .createHistoricActivityInstanceQuery() +// .processInstanceId(processInstanceId) +// .orderByHistoricActivityInstanceStartTime().asc().list(); +// +// List historicActivityInstanceList = new ArrayList(); +// for (HistoricActivityInstance hai : historicActivityInstances) { +// historicActivityInstanceList.add(hai.getActivityId()); +// } + +// // add current activities to list +// List highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId); +// historicActivityInstanceList.addAll(highLightedActivities); + + // activities and their sequence-flows +// for (ActivityImpl activity : processDefinition.getActivities()) { +// int index = historicActivityInstanceList.indexOf(activity.getId()); +// +// if (index >= 0 && index + 1 < historicActivityInstanceList.size()) { +// List pvmTransitionList = activity +// .getOutgoingTransitions(); +// for (PvmTransition pvmTransition : pvmTransitionList) { +// String destinationFlowId = pvmTransition.getDestination().getId(); +// if (destinationFlowId.equals(historicActivityInstanceList.get(index + 1))) { +// highLightedFlows.add(pvmTransition.getId()); +// } +// } +// } +// } +// return highLightedFlows; +// } +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java index f69c96736..63869170d 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.adminserver.modules.system.service.auth.impl; +import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.security.core.LoginUser; @@ -31,10 +32,14 @@ import org.springframework.stereotype.Service; import org.springframework.util.Assert; import javax.annotation.Resource; +import java.util.List; +import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*; +import static java.util.Collections.EMPTY_LIST; import static java.util.Collections.singleton; /** @@ -59,6 +64,8 @@ public class SysAuthServiceImpl implements SysAuthService { private SysLoginLogService loginLogService; @Resource private SysUserSessionService userSessionService; + @Resource + private SysPostService sysPostService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { @@ -68,7 +75,9 @@ public class SysAuthServiceImpl implements SysAuthService { throw new UsernameNotFoundException(username); } // 创建 LoginUser 对象 - return SysAuthConvert.INSTANCE.convert(user); + LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); + loginUser.setPostIds(user.getPostIds()); + return loginUser; } @Override @@ -92,11 +101,18 @@ public class SysAuthServiceImpl implements SysAuthService { // 使用账号密码,进行登陆。 LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword()); loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表 - + loginUser.setGroups(this.getUserPosts(loginUser.getPostIds())); // 缓存登陆用户到 Redis 中,返回 sessionId 编号 return userSessionService.createUserSession(loginUser, userIp, userAgent); } + + private List getUserPosts(Set postIds) { + return Optional.ofNullable(postIds).map(ids-> + sysPostService.getPosts(ids).stream().map(post -> post.getCode()).collect(Collectors.toList()) + ).orElse(EMPTY_LIST); + } + private void verifyCaptcha(String username, String captchaUUID, String captchaCode) { String code = captchaService.getCaptchaCode(captchaUUID); // 验证码不存在 @@ -122,6 +138,7 @@ public class SysAuthServiceImpl implements SysAuthService { // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证 // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息 authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); + // org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username); } catch (BadCredentialsException badCredentialsException) { this.createLoginLog(username, SysLoginResultEnum.BAD_CREDENTIALS); throw exception(AUTH_LOGIN_BAD_CREDENTIALS); diff --git a/yudao-admin-server/src/main/resources/application.yaml b/yudao-admin-server/src/main/resources/application.yaml index 486d4a487..49cfaa44a 100644 --- a/yudao-admin-server/src/main/resources/application.yaml +++ b/yudao-admin-server/src/main/resources/application.yaml @@ -22,9 +22,10 @@ spring: # MyBatis Plus 的配置项 mybatis-plus: - configuration: - map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印日志 +# 在 mybatis-config/mybatis-config.xml 中设置 +# configuration: +# map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 +# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印日志 global-config: db-config: id-type: AUTO # 自增 ID @@ -32,6 +33,18 @@ mybatis-plus: logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) mapper-locations: classpath*:mapper/*.xml type-aliases-package: ${yudao.info.base-package}.modules.*.dal.dataobject + config-location: classpath:mybatis-config/mybatis-config.xml + configuration-properties: + prefix: "" + wildcardEscapeClause: "" + limitBefore: "" + limitAfter: "LIMIT #{maxResults} OFFSET #{firstResult}" + limitBetween: "" + limitOuterJoinBetween: "" + limitBeforeNativeQuery: "" + orderBy: "order by ${orderByColumns}" + blobType: "BLOB" + boolValue: "TRUE" --- #################### 芋道相关配置 #################### diff --git a/yudao-admin-server/src/main/resources/mybatis-config/mybatis-config.xml b/yudao-admin-server/src/main/resources/mybatis-config/mybatis-config.xml new file mode 100644 index 000000000..4f290bc98 --- /dev/null +++ b/yudao-admin-server/src/main/resources/mybatis-config/mybatis-config.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/yudao-admin-server/src/main/resources/processes/leave.bpmn b/yudao-admin-server/src/main/resources/processes/leave.bpmn new file mode 100644 index 000000000..34eeea0a5 --- /dev/null +++ b/yudao-admin-server/src/main/resources/processes/leave.bpmn @@ -0,0 +1,130 @@ + + + + 请假流程演示 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/yudao-admin-ui/src/api/oa/leave.js b/yudao-admin-ui/src/api/oa/leave.js new file mode 100644 index 000000000..3fb0f806c --- /dev/null +++ b/yudao-admin-ui/src/api/oa/leave.js @@ -0,0 +1,54 @@ +import request from '@/utils/request' + +// 创建请假申请 +export function createLeave(data) { + return request({ + url: '/oa/leave/create', + method: 'post', + data: data + }) +} + +// 更新请假申请 +export function updateLeave(data) { + return request({ + url: '/oa/leave/update', + method: 'put', + data: data + }) +} + +// 删除请假申请 +export function deleteLeave(id) { + return request({ + url: '/oa/leave/delete?id=' + id, + method: 'delete' + }) +} + +// 获得请假申请 +export function getLeave(id) { + return request({ + url: '/oa/leave/get?id=' + id, + method: 'get' + }) +} + +// 获得请假申请分页 +export function getLeavePage(query) { + return request({ + url: '/oa/leave/page', + method: 'get', + params: query + }) +} + +// 导出请假申请 Excel +export function exportLeaveExcel(query) { + return request({ + url: '/oa/leave/export-excel', + method: 'get', + params: query, + responseType: 'blob' + }) +} diff --git a/yudao-admin-ui/src/api/oa/todo.js b/yudao-admin-ui/src/api/oa/todo.js new file mode 100644 index 000000000..35f857988 --- /dev/null +++ b/yudao-admin-ui/src/api/oa/todo.js @@ -0,0 +1,75 @@ +import request from '@/utils/request' + +// 创建请假申请 +export function createLeave(data) { + return request({ + url: '/oa/leave/create', + method: 'post', + data: data + }) +} + +// 更新请假申请 +export function updateLeave(data) { + return request({ + url: '/oa/leave/update', + method: 'put', + data: data + }) +} + +// 删除请假申请 +export function deleteLeave(id) { + return request({ + url: '/oa/leave/delete?id=' + id, + method: 'delete' + }) +} + +// 获得请假申请 +export function getLeave(id) { + return request({ + url: '/oa/leave/get?id=' + id, + method: 'get' + }) +} + +// 获得待办任务分页 +export function getTodoTaskPage(query) { + return request({ + url: '/workflow/task/todo/page', + method: 'get', + params: query + }) +} + +// 签收任务 +export function claimTask(id) { + return request({ + url: '/workflow/task/claim?id=' + id, + method: 'get' + }) +} + +export function completeTask(data) { + return request({ + url: '/workflow/task/complete', + method: 'post', + data: data + }) +} + +export function taskSteps(data) { + return request({ + url: '/workflow/task/task-steps', + method: 'post', + data: data + }) +} + +export function processHistorySteps(id) { + return request({ + url: '/workflow/task/process/history-steps?id='+id, + method: 'get' + }) +} diff --git a/yudao-admin-ui/src/utils/dict.js b/yudao-admin-ui/src/utils/dict.js index 17d5bd00e..b29c00359 100644 --- a/yudao-admin-ui/src/utils/dict.js +++ b/yudao-admin-ui/src/utils/dict.js @@ -29,6 +29,9 @@ export const DICT_TYPE = { INF_API_ERROR_LOG_PROCESS_STATUS: 'inf_api_error_log_process_status', TOOL_CODEGEN_TEMPLATE_TYPE: 'tool_codegen_template_type', + + OA_LEAVE_STATUS: 'oa_leave_status', + OA_LEAVE_TYPE: 'oa_leave_type' } /** diff --git a/yudao-admin-ui/src/views/oa/leave/index.vue b/yudao-admin-ui/src/views/oa/leave/index.vue new file mode 100644 index 000000000..d14706383 --- /dev/null +++ b/yudao-admin-ui/src/views/oa/leave/index.vue @@ -0,0 +1,347 @@ + + + diff --git a/yudao-admin-ui/src/views/oa/todo/index.vue b/yudao-admin-ui/src/views/oa/todo/index.vue new file mode 100644 index 000000000..0d4107624 --- /dev/null +++ b/yudao-admin-ui/src/views/oa/todo/index.vue @@ -0,0 +1,284 @@ + + + diff --git a/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml b/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml index e9cee07f1..b1c08492a 100644 --- a/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-activiti/pom.xml @@ -19,20 +19,29 @@ 7.1.0.M6 - + + + + org.activiti.dependencies + activiti-dependencies + ${activiti.version} + import + pom + + + cn.iocoder.boot yudao-common - - org.activiti.dependencies - activiti-dependencies - ${activiti.version} - pom + org.mybatis + mybatis + true + org.activiti @@ -51,6 +60,10 @@ org.mybatis mybatis + + el-api + javax.el + diff --git a/yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/config/YudaoActivitiConfiguration.java b/yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/config/YudaoActivitiConfiguration.java new file mode 100644 index 000000000..6e7355db9 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/config/YudaoActivitiConfiguration.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.framework.activiti.config; + +import org.activiti.api.runtime.shared.identity.UserGroupManager; +import org.activiti.spring.SpringProcessEngineConfiguration; +import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer; +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +@Configuration +public class YudaoActivitiConfiguration { + + + + + @Component + public static class SqlSessionFactoryProcessEngineConfigurationConfigurer + implements ProcessEngineConfigurationConfigurer { + + private final SqlSessionFactory sqlSessionFactory; + public SqlSessionFactoryProcessEngineConfigurationConfigurer(SqlSessionFactory sessionFactory) { + this.sqlSessionFactory = sessionFactory; + } + + @Override + public void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) { + springProcessEngineConfiguration.setSqlSessionFactory(sqlSessionFactory); + } + } + + +} diff --git a/yudao-framework/yudao-spring-boot-starter-security/pom.xml b/yudao-framework/yudao-spring-boot-starter-security/pom.xml index 4a2b1878a..bdc69f264 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-security/pom.xml @@ -39,6 +39,18 @@ spring-boot-starter-security + + org.activiti + activiti-engine + 7.1.0.M6 + + + * + * + + + true + diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java index 2c2ff8914..f6c5acad1 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java @@ -4,11 +4,10 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; -import java.util.Collection; -import java.util.Date; -import java.util.Set; +import java.util.*; /** * 登陆用户信息 @@ -48,6 +47,18 @@ public class LoginUser implements UserDetails { */ private Integer status; + + /** + * 所属岗位 + */ + private Set postIds; + + /** + * group 目前指岗位代替 + */ + private List groups; + + @Override @JsonIgnore// 避免序列化 public String getPassword() { @@ -55,7 +66,6 @@ public class LoginUser implements UserDetails { } @Override - @JsonIgnore public String getUsername() { return username; } @@ -69,7 +79,9 @@ public class LoginUser implements UserDetails { @Override @JsonIgnore// 避免序列化 public Collection getAuthorities() { - return null; + List list = new ArrayList<>(1); + list.add(new SimpleGrantedAuthority("ROLE_ACTIVITI_USER")); + return list; } @Override diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java index a8360c490..f63a9b7ba 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java @@ -90,13 +90,18 @@ public class SecurityFrameworkUtils { public static void setLoginUser(LoginUser loginUser, HttpServletRequest request) { // 创建 UsernamePasswordAuthenticationToken 对象 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( - loginUser, null, null); + loginUser, null, loginUser.getAuthorities()); authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); // 设置到上下文 + //何时调用 SecurityContextHolder.clearContext. spring security filter 应该会调用 clearContext SecurityContextHolder.getContext().setAuthentication(authenticationToken); // 额外设置到 request 中,用于 ApiAccessLogFilter 可以获取到用户编号; // 原因是,Spring Security 的 Filter 在 ApiAccessLogFilter 后面,在它记录访问日志时,线上上下文已经没有用户编号等信息 WebFrameworkUtils.setLoginUserId(request, loginUser.getId()); + + org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername()); + + } } From d16185f87d06885df206946b2b949d7a7c78c3a7 Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Thu, 28 Oct 2021 00:51:57 +0800 Subject: [PATCH 06/60] =?UTF-8?q?=20=E4=BF=AE=E6=94=B9=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E4=B8=BA=E5=A4=96=E7=BD=AE=E8=A1=A8=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/ruoyi-vue-pro.sql | 3 +- .../controller/oa/OaLeaveController.java | 8 + .../controller/oa/vo/OaLeaveCreateReqVO.java | 1 + .../controller/oa/vo/OaLeaveUpdateReqVO.java | 7 + .../workflow/ProcessDefinitionController.java | 34 +++ .../controller/workflow/TaskController.java | 5 + .../controller/workflow/vo/TaskStepVO.java | 2 + .../workflow/vo/TodoTaskRespVO.java | 3 + .../service/oa/ReportBackEndProcessor.java | 19 +- .../service/oa/impl/OaLeaveServiceImpl.java | 34 ++- .../service/workflow/TaskService.java | 2 + .../workflow/impl/TaskServiceImpl.java | 59 ++--- .../resources/processes/leave-formkey.bpmn | 152 +++++++++++++ .../src/main/resources/processes/leave.bpmn | 130 ----------- yudao-admin-ui/src/api/oa/flow.js | 9 + yudao-admin-ui/src/api/oa/leave.js | 8 + yudao-admin-ui/src/api/oa/todo.js | 8 + yudao-admin-ui/src/router/index.js | 70 ++++++ yudao-admin-ui/src/views/oa/flow/index.vue | 36 +++ .../src/views/oa/leave/apply/index.vue | 93 ++++++++ .../src/views/oa/leave/approve-hr/index.vue | 190 ++++++++++++++++ .../views/oa/leave/approve-leader/index.vue | 190 ++++++++++++++++ .../src/views/oa/leave/confirm/index.vue | 137 ++++++++++++ yudao-admin-ui/src/views/oa/leave/index.vue | 64 ++++-- .../src/views/oa/leave/modify/index.vue | 211 ++++++++++++++++++ yudao-admin-ui/src/views/oa/todo/index.vue | 25 ++- 更新日志.md | 11 + 27 files changed, 1328 insertions(+), 183 deletions(-) create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/ProcessDefinitionController.java create mode 100644 yudao-admin-server/src/main/resources/processes/leave-formkey.bpmn delete mode 100644 yudao-admin-server/src/main/resources/processes/leave.bpmn create mode 100644 yudao-admin-ui/src/api/oa/flow.js create mode 100644 yudao-admin-ui/src/views/oa/flow/index.vue create mode 100644 yudao-admin-ui/src/views/oa/leave/apply/index.vue create mode 100644 yudao-admin-ui/src/views/oa/leave/approve-hr/index.vue create mode 100644 yudao-admin-ui/src/views/oa/leave/approve-leader/index.vue create mode 100644 yudao-admin-ui/src/views/oa/leave/confirm/index.vue create mode 100644 yudao-admin-ui/src/views/oa/leave/modify/index.vue diff --git a/sql/ruoyi-vue-pro.sql b/sql/ruoyi-vue-pro.sql index 2b9c359dd..f42642e2b 100644 --- a/sql/ruoyi-vue-pro.sql +++ b/sql/ruoyi-vue-pro.sql @@ -733,13 +733,14 @@ INSERT INTO `sys_menu` VALUES (1113, '错误码更新', 'system:error-code:updat INSERT INTO `sys_menu` VALUES (1114, '错误码删除', 'system:error-code:delete', 3, 4, 1110, '', '', '', 0, '', '2021-04-13 21:46:42', '', '2021-04-13 22:09:51', b'0'); INSERT INTO `sys_menu` VALUES (1115, '错误码导出', 'system:error-code:export', 3, 5, 1110, '', '', '', 0, '', '2021-04-13 21:46:42', '', '2021-04-13 22:09:55', b'0'); INSERT INTO `sys_menu` VALUES (1116, '日志中心', '', 2, 8, 2, 'log-center', 'log', 'infra/skywalking/log', 0, '1', '2021-04-26 22:35:45', '1', '2021-04-26 22:37:25', b'0'); -INSERT INTO `sys_menu` VALUES (1118,'请假申请','',2,0,5,'oa/leave','user','oa/leave/index',0,'','2021-09-20 08:51:03','1','2021-10-12 22:19:02',0x00); +INSERT INTO `sys_menu` VALUES (1118,'请假查询','',2,0,5,'oa/leave','user','oa/leave/index',0,'','2021-09-20 08:51:03','1','2021-10-12 22:19:02',0x00); INSERT INTO `sys_menu` VALUES (1119,'请假申请查询','oa:leave:query',3,1,1118,'','','',0,'','2021-09-20 08:51:03','','2021-09-20 08:51:03',0x00); INSERT INTO `sys_menu` VALUES (1120,'请假申请创建','oa:leave:create',3,2,1118,'','','',0,'','2021-09-20 08:51:03','','2021-09-20 08:51:03',0x00); INSERT INTO `sys_menu` VALUES (1121,'请假申请更新','oa:leave:update',3,3,1118,'','','',0,'','2021-09-20 08:51:03','','2021-09-20 08:51:03',0x00); INSERT INTO `sys_menu` VALUES (1122,'请假申请删除','oa:leave:delete',3,4,1118,'','','',0,'','2021-09-20 08:51:03','','2021-09-20 08:51:03',0x00); INSERT INTO `sys_menu` VALUES (1123,'请假申请导出','oa:leave:export',3,5,1118,'','','',0,'','2021-09-20 08:51:03','','2021-09-20 08:51:03',0x00); INSERT INTO `sys_menu` VALUES (1124,'待办任务','',2,2,5,'todo','edit','oa/todo/index',0,'1','2021-09-20 22:10:09','1','2021-09-21 23:17:12',0x00); +INSERT INTO `sys_menu` VALUES (1125,'流程申请','',2,3,5,'flow','form','oa/flow/index',0,'1','2021-10-23 22:10:09','1','2021-10-23 23:17:12',0x00); COMMIT; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/OaLeaveController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/OaLeaveController.java index e8dd527b9..679c667da 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/OaLeaveController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/OaLeaveController.java @@ -41,6 +41,14 @@ public class OaLeaveController { @ApiOperation("创建请假申请") @PreAuthorize("@ss.hasPermission('oa:leave:create')") public CommonResult createLeave(@Valid @RequestBody OaLeaveCreateReqVO createReqVO) { + createReqVO.setProcessKey("leave"); + return success(leaveService.createLeave(createReqVO)); + } + + @PostMapping("/form-key/create") + @ApiOperation("创建外置请假申请") + public CommonResult createFormKeyLeave(@Valid @RequestBody OaLeaveCreateReqVO createReqVO) { + createReqVO.setProcessKey("leave-formkey"); return success(leaveService.createLeave(createReqVO)); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveCreateReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveCreateReqVO.java index 29cede1ff..ccbb70d71 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveCreateReqVO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveCreateReqVO.java @@ -11,4 +11,5 @@ import javax.validation.constraints.*; @ToString(callSuper = true) public class OaLeaveCreateReqVO extends OaLeaveBaseVO { + private String processKey; } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveUpdateReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveUpdateReqVO.java index dc81fa31e..17a229d5f 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveUpdateReqVO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/oa/vo/OaLeaveUpdateReqVO.java @@ -15,4 +15,11 @@ public class OaLeaveUpdateReqVO extends OaLeaveBaseVO { @NotNull(message = "请假表单主键不能为空") private Long id; + + private String taskId; + + private String comment; + + private Map variables; + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/ProcessDefinitionController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/ProcessDefinitionController.java new file mode 100644 index 000000000..d5241263c --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/ProcessDefinitionController.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import org.activiti.api.process.runtime.ProcessRuntime; +import org.activiti.engine.RepositoryService; +import org.activiti.engine.repository.ProcessDefinition; +import org.activiti.engine.repository.ProcessDefinitionQuery; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@RestController +@RequestMapping("/workflow/process/definition") +public class ProcessDefinitionController { + + @Resource + private RepositoryService repositoryService; + + @Resource + private ProcessRuntime processRuntime; + + + @GetMapping(value = "/getStartForm") + public CommonResult getStartForm(@RequestParam("processKey") String processKey){ + //这样查似乎有问题??, 暂时写死 +// final ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery(). +// processDefinitionKey(processKey).latestVersion().singleResult(); +// processRuntime.processDefinition(processDefinition.getId()).getFormKey(); + return CommonResult.success("/flow/leave/apply"); + } +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/TaskController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/TaskController.java index 3a717f116..9309cca9e 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/TaskController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/TaskController.java @@ -43,6 +43,11 @@ public class TaskController { return success( taskService.getTaskSteps(taskQuery)); } + @PostMapping("/formKey") + public CommonResult getTaskFormKey(@RequestBody TaskQueryReqVO taskQuery) { + return success( taskService.getTaskFormKey(taskQuery)); + } + @PostMapping("/complete") public CommonResult complete(@RequestBody TaskReqVO taskReq) { taskService.completeTask(taskReq); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskStepVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskStepVO.java index fe2335562..b1bb93ac6 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskStepVO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TaskStepVO.java @@ -19,4 +19,6 @@ public class TaskStepVO { private String comment; + private Integer status; + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskRespVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskRespVO.java index 5fef60eb5..685324b1b 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskRespVO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/controller/workflow/vo/TodoTaskRespVO.java @@ -27,4 +27,7 @@ public class TodoTaskRespVO { private String businessKey; + + private String formKey; + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/ReportBackEndProcessor.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/ReportBackEndProcessor.java index 05ed6fb7d..44991ec8c 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/ReportBackEndProcessor.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/ReportBackEndProcessor.java @@ -3,7 +3,9 @@ package cn.iocoder.yudao.adminserver.modules.activiti.service.oa; import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO; import cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.oa.OaLeaveMapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.delegate.DelegateTask; +import org.activiti.engine.delegate.ExecutionListener; import org.activiti.engine.delegate.TaskListener; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -11,16 +13,27 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; @Component -public class ReportBackEndProcessor implements TaskListener { +public class ReportBackEndProcessor implements ExecutionListener { @Resource private OaLeaveMapper leaveMapper; +// @Override +// @Transactional(rollbackFor = Exception.class) +// public void notify(DelegateTask delegateTask) { +// final String businessKey = delegateTask.getExecution().getProcessInstanceBusinessKey(); +// UpdateWrapper updateWrapper = new UpdateWrapper<>(); +// updateWrapper.eq("id", Long.valueOf(businessKey)); +// OaLeaveDO updateDo = new OaLeaveDO(); +// updateDo.setStatus(2); +// leaveMapper.update(updateDo, updateWrapper); +// } + @Override @Transactional(rollbackFor = Exception.class) - public void notify(DelegateTask delegateTask) { - final String businessKey = delegateTask.getExecution().getProcessInstanceBusinessKey(); + public void notify(DelegateExecution delegateExecution) { + final String businessKey = delegateExecution.getProcessInstanceBusinessKey(); UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("id", Long.valueOf(businessKey)); OaLeaveDO updateDo = new OaLeaveDO(); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/impl/OaLeaveServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/impl/OaLeaveServiceImpl.java index c82e7a100..0e78ef2b4 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/impl/OaLeaveServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/oa/impl/OaLeaveServiceImpl.java @@ -2,6 +2,9 @@ package cn.iocoder.yudao.adminserver.modules.activiti.service.oa.impl; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import org.activiti.api.task.model.Task; +import org.activiti.api.task.model.builders.TaskPayloadBuilder; +import org.activiti.api.task.runtime.TaskRuntime; import org.activiti.engine.RuntimeService; import org.activiti.engine.runtime.ProcessInstance; import org.springframework.beans.factory.annotation.Autowired; @@ -38,6 +41,12 @@ public class OaLeaveServiceImpl implements OaLeaveService { @Resource private RuntimeService runtimeService; + @Resource + private org.activiti.engine.TaskService activitiTaskService; + + @Resource + private TaskRuntime taskRuntime; + @Override @Transactional(rollbackFor = Exception.class) public Long createLeave(OaLeaveCreateReqVO createReqVO) { @@ -52,7 +61,7 @@ public class OaLeaveServiceImpl implements OaLeaveService { variables.put("deptLeader", "admin"); final Long id = leave.getId(); String businessKey = String.valueOf(id); - ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leave", businessKey, variables); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(createReqVO.getProcessKey(), businessKey, variables); final String processInstanceId = processInstance.getProcessInstanceId(); @@ -67,12 +76,29 @@ public class OaLeaveServiceImpl implements OaLeaveService { } @Override + @Transactional(rollbackFor = Exception.class) public void updateLeave(OaLeaveUpdateReqVO updateReqVO) { + // 校验存在 this.validateLeaveExists(updateReqVO.getId()); - // 更新 - OaLeaveDO updateObj = OaLeaveConvert.INSTANCE.convert(updateReqVO); - leaveMapper.updateById(updateObj); + + final Task task = taskRuntime.task(updateReqVO.getTaskId()); + activitiTaskService.addComment(task.getId(), task.getProcessInstanceId(), updateReqVO.getComment()); + Map variables = updateReqVO.getVariables(); + + //如何得到部门领导人, 暂时写死 + variables.put("deptLeader", "admin"); + taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()) + .withVariables(variables) + .build()); + final Object reApply = variables.get("reApply"); + if((reApply instanceof Boolean) && (Boolean)reApply){ + // 更新 表单 + OaLeaveDO updateObj = OaLeaveConvert.INSTANCE.convert(updateReqVO); + leaveMapper.updateById(updateObj); + } + + } @Override diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/TaskService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/TaskService.java index ae0783b48..2f2aca24d 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/TaskService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/TaskService.java @@ -20,4 +20,6 @@ public interface TaskService { TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery); List getHistorySteps(String processInstanceId); + + TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/impl/TaskServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/impl/TaskServiceImpl.java index aae12755b..44003e660 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/impl/TaskServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/activiti/service/workflow/impl/TaskServiceImpl.java @@ -117,14 +117,14 @@ public class TaskServiceImpl implements TaskService { .withVariables(taskReq.getVariables()) .build()); - if(variables.containsValue(Boolean.FALSE)){ - final String businessKey = task.getBusinessKey(); - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - updateWrapper.eq("id", Long.valueOf(businessKey)); - OaLeaveDO updateDo = new OaLeaveDO(); - updateDo.setStatus(2); - leaveMapper.update(updateDo, updateWrapper); - } +// if(variables.containsValue(Boolean.FALSE)){ +// final String businessKey = task.getBusinessKey(); +// UpdateWrapper updateWrapper = new UpdateWrapper<>(); +// updateWrapper.eq("id", Long.valueOf(businessKey)); +// OaLeaveDO updateDo = new OaLeaveDO(); +// updateDo.setStatus(2); +// leaveMapper.update(updateDo, updateWrapper); +// } } @@ -152,19 +152,19 @@ public class TaskServiceImpl implements TaskService { public TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery) { TaskHandleVO handleVO = new TaskHandleVO(); - String processKey = taskQuery.getProcessKey(); - if ("leave".equals(processKey)) { - String businessKey = taskQuery.getBusinessKey(); - final OaLeaveDO leave = leaveMapper.selectById(Long.valueOf(businessKey)); - handleVO.setFormObject( OaLeaveConvert.INSTANCE.convert(leave)); - } +// String processKey = taskQuery.getProcessKey(); +// if ("leave".equals(processKey)) { +// String businessKey = taskQuery.getBusinessKey(); +// final OaLeaveDO leave = leaveMapper.selectById(Long.valueOf(businessKey)); +// handleVO.setFormObject( OaLeaveConvert.INSTANCE.convert(leave)); +// } +// +// final String taskDefKey = task.getTaskDefinitionKey(); +// final String variableName = Optional.ofNullable(taskVariable.get(taskDefKey)).orElse(""); +// handleVO.setTaskVariable(variableName); final Task task = taskRuntime.task(taskQuery.getTaskId()); - final String taskDefKey = task.getTaskDefinitionKey(); - final String variableName = Optional.ofNullable(taskVariable.get(taskDefKey)).orElse(""); - - handleVO.setTaskVariable(variableName); List steps = getTaskSteps(task.getProcessInstanceId()); handleVO.setHistoryTask(steps); @@ -189,6 +189,7 @@ public class TaskServiceImpl implements TaskService { step.setStartTime(instance.getStartTime()); step.setEndTime(instance.getEndTime()); step.setAssignee(instance.getAssignee()); + step.setStatus(1); final List comments = activitiTaskService.getTaskComments(instance.getTaskId()); if(comments.size()>0){ step.setComment(comments.get(0).getFullMessage()); @@ -204,15 +205,14 @@ public class TaskServiceImpl implements TaskService { .activityType("userTask") .unfinished().list(); - if(unfinished.size()>0) { - - final HistoricActivityInstance unFinishedActiviti = unfinished.get(0); + for (HistoricActivityInstance instance : unfinished) { TaskStepVO step = new TaskStepVO(); - step.setStepName(unFinishedActiviti.getActivityName()); - step.setStartTime(unFinishedActiviti.getStartTime()); - step.setEndTime(unFinishedActiviti.getEndTime()); - step.setAssignee(Optional.ofNullable(unFinishedActiviti.getAssignee()).orElse("")); + step.setStepName(instance.getActivityName()); + step.setStartTime(instance.getStartTime()); + step.setEndTime(instance.getEndTime()); + step.setAssignee(Optional.ofNullable(instance.getAssignee()).orElse("")); step.setComment(""); + step.setStatus(0); steps.add(step); } return steps; @@ -225,6 +225,15 @@ public class TaskServiceImpl implements TaskService { return getTaskSteps(processInstanceId); } + @Override + public TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery) { + final Task task = taskRuntime.task(taskQuery.getTaskId()); + TodoTaskRespVO respVO = new TodoTaskRespVO(); + respVO.setFormKey(task.getFormKey()); + respVO.setBusinessKey(task.getBusinessKey()); + respVO.setId(task.getId()); + return respVO; + } // private List getHighLightedFlows(ProcessDefinitionEntity processDefinition, String processInstanceId) { diff --git a/yudao-admin-server/src/main/resources/processes/leave-formkey.bpmn b/yudao-admin-server/src/main/resources/processes/leave-formkey.bpmn new file mode 100644 index 000000000..d14ce9ba3 --- /dev/null +++ b/yudao-admin-server/src/main/resources/processes/leave-formkey.bpmn @@ -0,0 +1,152 @@ + + + + 外置表单 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 请求被驳回后员工可以选择继续申请,或者取消本次申请 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/yudao-admin-server/src/main/resources/processes/leave.bpmn b/yudao-admin-server/src/main/resources/processes/leave.bpmn deleted file mode 100644 index 34eeea0a5..000000000 --- a/yudao-admin-server/src/main/resources/processes/leave.bpmn +++ /dev/null @@ -1,130 +0,0 @@ - - - - 请假流程演示 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/yudao-admin-ui/src/api/oa/flow.js b/yudao-admin-ui/src/api/oa/flow.js new file mode 100644 index 000000000..3c28cb418 --- /dev/null +++ b/yudao-admin-ui/src/api/oa/flow.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + + +export function getStartForm(processKey) { + return request({ + url: '/workflow/process/definition/getStartForm?processKey='+processKey, + method: 'get' + }) +} diff --git a/yudao-admin-ui/src/api/oa/leave.js b/yudao-admin-ui/src/api/oa/leave.js index 3fb0f806c..afb4e03d9 100644 --- a/yudao-admin-ui/src/api/oa/leave.js +++ b/yudao-admin-ui/src/api/oa/leave.js @@ -43,6 +43,14 @@ export function getLeavePage(query) { }) } +export function createFormKeyLeave(data) { + return request({ + url: '/oa/leave/form-key/create', + method: 'post', + data: data + }) +} + // 导出请假申请 Excel export function exportLeaveExcel(query) { return request({ diff --git a/yudao-admin-ui/src/api/oa/todo.js b/yudao-admin-ui/src/api/oa/todo.js index 35f857988..1aed4b058 100644 --- a/yudao-admin-ui/src/api/oa/todo.js +++ b/yudao-admin-ui/src/api/oa/todo.js @@ -67,6 +67,14 @@ export function taskSteps(data) { }) } +export function getTaskFormKey(data) { + return request({ + url: '/workflow/task/formKey', + method: 'post', + data: data + }) +} + export function processHistorySteps(id) { return request({ url: '/workflow/task/process/history-steps?id='+id, diff --git a/yudao-admin-ui/src/router/index.js b/yudao-admin-ui/src/router/index.js index 63f44544b..5b24fa503 100644 --- a/yudao-admin-ui/src/router/index.js +++ b/yudao-admin-ui/src/router/index.js @@ -123,6 +123,76 @@ export const constantRoutes = [ meta: { title: '修改生成配置' } } ] + }, + { + path: '/flow', + component: Layout, + hidden: true, + redirect: 'noredirect', + children: [ + { + path: 'leave/apply', + component: (resolve) => require(['@/views/oa/leave/apply/index'], resolve), + name: '请假表单', + meta: { title: '请假表单', icon: 'form' } + } + ] + }, + { + path: '/flow', + component: Layout, + hidden: true, + redirect: 'noredirect', + children: [ + { + path: 'leave/approve-leader', + component: (resolve) => require(['@/views/oa/leave/approve-leader/index'], resolve), + name: '请假表单-部门领导审批', + meta: { title: '请假表单-部门领导审批', icon: 'form' } + } + ] + }, + { + path: '/flow', + component: Layout, + hidden: true, + redirect: 'noredirect', + children: [ + { + path: 'leave/approve-hr', + component: (resolve) => require(['@/views/oa/leave/approve-hr/index'], resolve), + name: '请假表单-人事审批', + meta: { title: '请假表单-人事审批', icon: 'form' } + } + ] + }, + { + path: '/flow', + component: Layout, + hidden: true, + redirect: 'noredirect', + children: [ + { + path: 'leave/confirm', + component: (resolve) => require(['@/views/oa/leave/confirm/index'], resolve), + name: '请假表单-确认', + meta: { title: '请假表单-确认', icon: 'form' } + } + ] + }, + { + path: '/flow', + component: Layout, + hidden: true, + redirect: 'noredirect', + children: [ + { + path: 'leave/modify', + component: (resolve) => require(['@/views/oa/leave/modify/index'], resolve), + name: '请假表单-修改', + meta: { title: '请假表单-修改', icon: 'form' } + } + ] } ] diff --git a/yudao-admin-ui/src/views/oa/flow/index.vue b/yudao-admin-ui/src/views/oa/flow/index.vue new file mode 100644 index 000000000..b0fb8f51e --- /dev/null +++ b/yudao-admin-ui/src/views/oa/flow/index.vue @@ -0,0 +1,36 @@ + + + diff --git a/yudao-admin-ui/src/views/oa/leave/apply/index.vue b/yudao-admin-ui/src/views/oa/leave/apply/index.vue new file mode 100644 index 000000000..41a3bd93a --- /dev/null +++ b/yudao-admin-ui/src/views/oa/leave/apply/index.vue @@ -0,0 +1,93 @@ + + + diff --git a/yudao-admin-ui/src/views/oa/leave/approve-hr/index.vue b/yudao-admin-ui/src/views/oa/leave/approve-hr/index.vue new file mode 100644 index 000000000..3016c96be --- /dev/null +++ b/yudao-admin-ui/src/views/oa/leave/approve-hr/index.vue @@ -0,0 +1,190 @@ + + + diff --git a/yudao-admin-ui/src/views/oa/leave/approve-leader/index.vue b/yudao-admin-ui/src/views/oa/leave/approve-leader/index.vue new file mode 100644 index 000000000..f47349c64 --- /dev/null +++ b/yudao-admin-ui/src/views/oa/leave/approve-leader/index.vue @@ -0,0 +1,190 @@ + + + diff --git a/yudao-admin-ui/src/views/oa/leave/confirm/index.vue b/yudao-admin-ui/src/views/oa/leave/confirm/index.vue new file mode 100644 index 000000000..b0d402565 --- /dev/null +++ b/yudao-admin-ui/src/views/oa/leave/confirm/index.vue @@ -0,0 +1,137 @@ + + + diff --git a/yudao-admin-ui/src/views/oa/leave/index.vue b/yudao-admin-ui/src/views/oa/leave/index.vue index d14706383..f0998a00a 100644 --- a/yudao-admin-ui/src/views/oa/leave/index.vue +++ b/yudao-admin-ui/src/views/oa/leave/index.vue @@ -28,9 +28,9 @@ @@ -49,10 +49,6 @@ - - 新增 - @@ -71,7 +67,7 @@ {{ parseTime(scope.row.endTime) }} - + + + \ No newline at end of file diff --git a/yudao-vue-ui/common/css/common.css b/yudao-vue-ui/common/css/common.css new file mode 100644 index 000000000..2f22c237e --- /dev/null +++ b/yudao-vue-ui/common/css/common.css @@ -0,0 +1,182 @@ +/* #ifndef APP-PLUS-NVUE */ +view, +scroll-view, +swiper, +swiper-item, +cover-view, +cover-image, +icon, +text, +rich-text, +progress, +button, +checkbox, +form, +input, +label, +radio, +slider, +switch, +textarea, +navigator, +audio, +camera, +image, +video { + box-sizing: border-box; +} +image{ + display: block; +} +text{ + line-height: 1; + /* font-family: Helvetica Neue, Helvetica, sans-serif; */ +} +button{ + padding: 0; + margin: 0; + background-color: rgba(0,0,0,0) !important; +} +button:after{ + border: 0; +} +.bottom-fill{ + height: constant(safe-area-inset-bottom); + height: env(safe-area-inset-bottom); +} +.fix-bot{ + box-sizing: content-box; + padding-bottom: constant(safe-area-inset-bottom); + padding-bottom: env(safe-area-inset-bottom); +} + +/* 边框 */ +.round{ + position: relative; + border-radius: 100rpx; +} +.round:after{ + content: ''; + position: absolute; + left: 0; + top: 0; + width: 200%; + height: 200%; + transform: scale(.5) translate(-50%,-50%); + border: 1px solid #878787; + border-radius: 100rpx; + box-sizing: border-box; +} +.b-b:after{ + position: absolute; + z-index: 3; + left: 0; + top: auto; + bottom: 0; + right: 0; + height: 0; + content: ''; + transform: scaleY(.5); + border-bottom: 1px solid #e0e0e0; +} +.b-t:before{ + position: absolute; + z-index: 3; + left: 0; + top: 0; + right: 0; + height: 0; + content: ''; + transform: scaleY(.5); + border-bottom: 1px solid #e5e5e5; +} +.b-r:after{ + position: absolute; + z-index: 3; + right: 0; + top: 0; + bottom: 0; + width: 0; + content: ''; + transform: scaleX(.5); + border-right: 1px solid #e5e5e5; +} +.b-l:before{ + position: absolute; + z-index: 3; + left: 0; + top: 0; + bottom: 0; + width: 0; + content: ''; + transform: scaleX(.5); + border-left: 1px solid #e5e5e5; +} +.b-b, .b-t, .b-l, .b-r{ + position: relative; +} +/* 点击态 */ +.hover-gray { + background: #fafafa !important; +} +.hover-dark { + background: #f0f0f0 !important; +} + +.hover-opacity { + opacity: 0.7; +} + +/* #endif */ + +.clamp { + /* #ifdef APP-PLUS-NVUE */ + lines: 1; + /* #endif */ + /* #ifndef APP-PLUS-NVUE */ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: block; + /* #endif */ +} +.clamp2 { + /* #ifdef APP-PLUS-NVUE */ + lines: 2; + /* #endif */ + /* #ifndef APP-PLUS-NVUE */ + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + /* #endif */ +} + +/* 布局 */ +.row{ + /* #ifndef APP-PLUS-NVUE */ + display:flex; + /* #endif */ + flex-direction:row; + align-items: center; +} +.column{ + /* #ifndef APP-PLUS-NVUE */ + display:flex; + /* #endif */ + flex-direction: column; +} +.center{ + /* #ifndef APP-PLUS-NVUE */ + display:flex; + /* #endif */ + align-items: center; + justify-content: center; +} +.fill{ + flex: 1; +} +/* input */ +.placeholder{ + color: #999 !important; +} \ No newline at end of file diff --git a/yudao-vue-ui/common/css/icon.css b/yudao-vue-ui/common/css/icon.css new file mode 100644 index 000000000..15a177608 --- /dev/null +++ b/yudao-vue-ui/common/css/icon.css @@ -0,0 +1,271 @@ +@font-face { + font-family: "mix-icon"; + font-weight: normal; + font-style: normal; + src: url('https://at.alicdn.com/t/font_1913318_2ui3nitf38x.ttf') format('truetype'); +} + +.mix-icon { + font-family: "mix-icon" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-fanhui:before { + content: "\e7d5"; +} + +.icon-shoujihaoma:before { + content: "\e7ec"; +} + +.icon-close:before { + content: "\e60f"; +} + +.icon-xingbie-nv:before { + content: "\e60e"; +} + +.icon-wuliuyunshu:before { + content: "\e7ed"; +} + +.icon-jingpin:before { + content: "\e608"; +} + +.icon-zhangdanmingxi01:before { + content: "\e637"; +} + +.icon-tixian1:before { + content: "\e625"; +} + +.icon-chongzhi:before { + content: "\e605"; +} + +.icon-wodezhanghu_zijinjilu:before { + content: "\e615"; +} + +.icon-tixian:before { + content: "\e6ab"; +} + +.icon-qianbao:before { + content: "\e6c4"; +} + +.icon-guanbi1:before { + content: "\e61a"; +} + +.icon-daipingjia:before { + content: "\e604"; +} + +.icon-daifahuo:before { + content: "\e6bd"; +} + +.icon-yue:before { + content: "\e600"; +} + +.icon-wxpay:before { + content: "\e602"; +} + +.icon-alipay:before { + content: "\e603"; +} + +.icon-tishi:before { + content: "\e662"; +} + +.icon-shoucang-1:before { + content: "\e607"; +} + +.icon-gouwuche:before { + content: "\e657"; +} + +.icon-shoucang:before { + content: "\e645"; +} + +.icon-home:before { + content: "\e60c"; +} + +.icon-bangzhu1:before { + content: "\e63d"; +} + +.icon-xingxing:before { + content: "\e70b"; +} + +.icon-shuxiangliebiao:before { + content: "\e635"; +} + +.icon-hengxiangliebiao:before { + content: "\e636"; +} + +.icon-guanbi2:before { + content: "\e7be"; +} + +.icon-down:before { + content: "\e65c"; +} + +.icon-arrow-top:before { + content: "\e63e"; +} + +.icon-xiaoxi:before { + content: "\e634"; +} + +.icon-saoma:before { + content: "\e655"; +} + +.icon-dizhi1:before { + content: "\e618"; +} + +.icon-ditu-copy:before { + content: "\e609"; +} + +.icon-lajitong:before { + content: "\e682"; +} + +.icon-bianji:before { + content: "\e60d"; +} + +.icon-yanzhengma1:before { + content: "\e613"; +} + +.icon-yanjing:before { + content: "\e65b"; +} + +.icon-mima:before { + content: "\e628"; +} + +.icon-biyan:before { + content: "\e633"; +} + +.icon-iconfontweixin:before { + content: "\e611"; +} + +.icon-shouye:before { + content: "\e626"; +} + +.icon-daifukuan:before { + content: "\e68f"; +} + +.icon-pinglun-copy:before { + content: "\e612"; +} + +.icon-lishijilu:before { + content: "\e6b9"; +} + +.icon-shoucang_xuanzhongzhuangtai:before { + content: "\e6a9"; +} + +.icon-share:before { + content: "\e656"; +} + +.icon-shezhi1:before { + content: "\e61d"; +} + +.icon-shouhoutuikuan:before { + content: "\e631"; +} + +.icon-dizhi:before { + content: "\e614"; +} + +.icon-yishouhuo:before { + content: "\e71a"; +} + +.icon-xuanzhong:before { + content: "\e632"; +} + +.icon-xiangzuo:before { + content: "\e653"; +} + +.icon-iconfontxingxing:before { + content: "\e6b0"; +} + +.icon-jia2:before { + content: "\e60a"; +} + +.icon-sousuo:before { + content: "\e7ce"; +} + +.icon-xiala:before { + content: "\e644"; +} + +.icon-xia:before { + content: "\e62d"; +} + +.icon--jianhao:before { + content: "\e60b"; +} + +.icon-you:before { + content: "\e606"; +} + +.icon-yk_yuanquan:before { + content: "\e601"; +} + +.icon-xing:before { + content: "\e627"; +} + +.icon-guanbi:before { + content: "\e71d"; +} + +.icon-loading:before { + content: "\e646"; +} + diff --git a/yudao-vue-ui/components/jyf-parser/jyf-parser.vue b/yudao-vue-ui/components/jyf-parser/jyf-parser.vue new file mode 100644 index 000000000..01484f9d2 --- /dev/null +++ b/yudao-vue-ui/components/jyf-parser/jyf-parser.vue @@ -0,0 +1,630 @@ + + + + + diff --git a/yudao-vue-ui/components/jyf-parser/libs/CssHandler.js b/yudao-vue-ui/components/jyf-parser/libs/CssHandler.js new file mode 100644 index 000000000..8000377d1 --- /dev/null +++ b/yudao-vue-ui/components/jyf-parser/libs/CssHandler.js @@ -0,0 +1,97 @@ +const cfg = require('./config.js'), + isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + +function CssHandler(tagStyle) { + var styles = Object.assign(Object.create(null), cfg.userAgentStyles); + for (var item in tagStyle) + styles[item] = (styles[item] ? styles[item] + ';' : '') + tagStyle[item]; + this.styles = styles; +} +CssHandler.prototype.getStyle = function(data) { + this.styles = new parser(data, this.styles).parse(); +} +CssHandler.prototype.match = function(name, attrs) { + var tmp, matched = (tmp = this.styles[name]) ? tmp + ';' : ''; + if (attrs.class) { + var items = attrs.class.split(' '); + for (var i = 0, item; item = items[i]; i++) + if (tmp = this.styles['.' + item]) + matched += tmp + ';'; + } + if (tmp = this.styles['#' + attrs.id]) + matched += tmp + ';'; + return matched; +} +module.exports = CssHandler; + +function parser(data, init) { + this.data = data; + this.floor = 0; + this.i = 0; + this.list = []; + this.res = init; + this.state = this.Space; +} +parser.prototype.parse = function() { + for (var c; c = this.data[this.i]; this.i++) + this.state(c); + return this.res; +} +parser.prototype.section = function() { + return this.data.substring(this.start, this.i); +} +// 状态机 +parser.prototype.Space = function(c) { + if (c == '.' || c == '#' || isLetter(c)) { + this.start = this.i; + this.state = this.Name; + } else if (c == '/' && this.data[this.i + 1] == '*') + this.Comment(); + else if (!cfg.blankChar[c] && c != ';') + this.state = this.Ignore; +} +parser.prototype.Comment = function() { + this.i = this.data.indexOf('*/', this.i) + 1; + if (!this.i) this.i = this.data.length; + this.state = this.Space; +} +parser.prototype.Ignore = function(c) { + if (c == '{') this.floor++; + else if (c == '}' && !--this.floor) this.state = this.Space; +} +parser.prototype.Name = function(c) { + if (cfg.blankChar[c]) { + this.list.push(this.section()); + this.state = this.NameSpace; + } else if (c == '{') { + this.list.push(this.section()); + this.Content(); + } else if (c == ',') { + this.list.push(this.section()); + this.Comma(); + } else if (!isLetter(c) && (c < '0' || c > '9') && c != '-' && c != '_') + this.state = this.Ignore; +} +parser.prototype.NameSpace = function(c) { + if (c == '{') this.Content(); + else if (c == ',') this.Comma(); + else if (!cfg.blankChar[c]) this.state = this.Ignore; +} +parser.prototype.Comma = function() { + while (cfg.blankChar[this.data[++this.i]]); + if (this.data[this.i] == '{') this.Content(); + else { + this.start = this.i--; + this.state = this.Name; + } +} +parser.prototype.Content = function() { + this.start = ++this.i; + if ((this.i = this.data.indexOf('}', this.i)) == -1) this.i = this.data.length; + var content = this.section(); + for (var i = 0, item; item = this.list[i++];) + if (this.res[item]) this.res[item] += ';' + content; + else this.res[item] = content; + this.list = []; + this.state = this.Space; +} diff --git a/yudao-vue-ui/components/jyf-parser/libs/MpHtmlParser.js b/yudao-vue-ui/components/jyf-parser/libs/MpHtmlParser.js new file mode 100644 index 000000000..8911e36d3 --- /dev/null +++ b/yudao-vue-ui/components/jyf-parser/libs/MpHtmlParser.js @@ -0,0 +1,534 @@ +/** + * html 解析器 + * @tutorial https://github.com/jin-yufeng/Parser + * @version 20200719 + * @author JinYufeng + * @listens MIT + */ +const cfg = require('./config.js'), + blankChar = cfg.blankChar, + CssHandler = require('./CssHandler.js'), + windowWidth = uni.getSystemInfoSync().windowWidth; +var emoji; + +function MpHtmlParser(data, options = {}) { + this.attrs = {}; + this.CssHandler = new CssHandler(options.tagStyle, windowWidth); + this.data = data; + this.domain = options.domain; + this.DOM = []; + this.i = this.start = this.audioNum = this.imgNum = this.videoNum = 0; + options.prot = (this.domain || '').includes('://') ? this.domain.split('://')[0] : 'http'; + this.options = options; + this.state = this.Text; + this.STACK = []; + // 工具函数 + this.bubble = () => { + for (var i = this.STACK.length, item; item = this.STACK[--i];) { + if (cfg.richOnlyTags[item.name]) { + if (item.name == 'table' && !Object.hasOwnProperty.call(item, 'c')) item.c = 1; + return false; + } + item.c = 1; + } + return true; + } + this.decode = (val, amp) => { + var i = -1, + j, en; + while (1) { + if ((i = val.indexOf('&', i + 1)) == -1) break; + if ((j = val.indexOf(';', i + 2)) == -1) break; + if (val[i + 1] == '#') { + en = parseInt((val[i + 2] == 'x' ? '0' : '') + val.substring(i + 2, j)); + if (!isNaN(en)) val = val.substr(0, i) + String.fromCharCode(en) + val.substr(j + 1); + } else { + en = val.substring(i + 1, j); + if (cfg.entities[en] || en == amp) + val = val.substr(0, i) + (cfg.entities[en] || '&') + val.substr(j + 1); + } + } + return val; + } + this.getUrl = url => { + if (url[0] == '/') { + if (url[1] == '/') url = this.options.prot + ':' + url; + else if (this.domain) url = this.domain + url; + } else if (this.domain && url.indexOf('data:') != 0 && !url.includes('://')) + url = this.domain + '/' + url; + return url; + } + this.isClose = () => this.data[this.i] == '>' || (this.data[this.i] == '/' && this.data[this.i + 1] == '>'); + this.section = () => this.data.substring(this.start, this.i); + this.parent = () => this.STACK[this.STACK.length - 1]; + this.siblings = () => this.STACK.length ? this.parent().children : this.DOM; +} +MpHtmlParser.prototype.parse = function() { + if (emoji) this.data = emoji.parseEmoji(this.data); + for (var c; c = this.data[this.i]; this.i++) + this.state(c); + if (this.state == this.Text) this.setText(); + while (this.STACK.length) this.popNode(this.STACK.pop()); + return this.DOM; +} +// 设置属性 +MpHtmlParser.prototype.setAttr = function() { + var name = this.attrName.toLowerCase(), + val = this.attrVal; + if (cfg.boolAttrs[name]) this.attrs[name] = 'T'; + else if (val) { + if (name == 'src' || (name == 'data-src' && !this.attrs.src)) this.attrs.src = this.getUrl(this.decode(val, 'amp')); + else if (name == 'href' || name == 'style') this.attrs[name] = this.decode(val, 'amp'); + else if (name.substr(0, 5) != 'data-') this.attrs[name] = val; + } + this.attrVal = ''; + while (blankChar[this.data[this.i]]) this.i++; + if (this.isClose()) this.setNode(); + else { + this.start = this.i; + this.state = this.AttrName; + } +} +// 设置文本节点 +MpHtmlParser.prototype.setText = function() { + var back, text = this.section(); + if (!text) return; + text = (cfg.onText && cfg.onText(text, () => back = true)) || text; + if (back) { + this.data = this.data.substr(0, this.start) + text + this.data.substr(this.i); + let j = this.start + text.length; + for (this.i = this.start; this.i < j; this.i++) this.state(this.data[this.i]); + return; + } + if (!this.pre) { + // 合并空白符 + var tmp = []; + for (let i = text.length, c; c = text[--i];) + if (!blankChar[c] || (!blankChar[tmp[0]] && (c = ' '))) tmp.unshift(c); + text = tmp.join(''); + } + this.siblings().push({ + type: 'text', + text: this.decode(text) + }); +} +// 设置元素节点 +MpHtmlParser.prototype.setNode = function() { + var node = { + name: this.tagName.toLowerCase(), + attrs: this.attrs + }, + close = cfg.selfClosingTags[node.name]; + this.attrs = {}; + if (!cfg.ignoreTags[node.name]) { + // 处理属性 + var attrs = node.attrs, + style = this.CssHandler.match(node.name, attrs, node) + (attrs.style || ''), + styleObj = {}; + if (attrs.id) { + if (this.options.compress & 1) attrs.id = void 0; + else if (this.options.useAnchor) this.bubble(); + } + if ((this.options.compress & 2) && attrs.class) attrs.class = void 0; + switch (node.name) { + case 'a': + case 'ad': // #ifdef APP-PLUS + case 'iframe': + // #endif + this.bubble(); + break; + case 'font': + if (attrs.color) { + styleObj['color'] = attrs.color; + attrs.color = void 0; + } + if (attrs.face) { + styleObj['font-family'] = attrs.face; + attrs.face = void 0; + } + if (attrs.size) { + var size = parseInt(attrs.size); + if (size < 1) size = 1; + else if (size > 7) size = 7; + var map = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large']; + styleObj['font-size'] = map[size - 1]; + attrs.size = void 0; + } + break; + case 'embed': + // #ifndef APP-PLUS + var src = node.attrs.src || '', + type = node.attrs.type || ''; + if (type.includes('video') || src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8')) + node.name = 'video'; + else if (type.includes('audio') || src.includes('.m4a') || src.includes('.wav') || src.includes('.mp3') || src.includes( + '.aac')) + node.name = 'audio'; + else break; + if (node.attrs.autostart) + node.attrs.autoplay = 'T'; + node.attrs.controls = 'T'; + // #endif + // #ifdef APP-PLUS + this.bubble(); + break; + // #endif + case 'video': + case 'audio': + if (!attrs.id) attrs.id = node.name + (++this[`${node.name}Num`]); + else this[`${node.name}Num`]++; + if (node.name == 'video') { + if (this.videoNum > 3) + node.lazyLoad = 1; + if (attrs.width) { + styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px'); + attrs.width = void 0; + } + if (attrs.height) { + styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px'); + attrs.height = void 0; + } + } + attrs.source = []; + if (attrs.src) { + attrs.source.push(attrs.src); + attrs.src = void 0; + } + this.bubble(); + break; + case 'td': + case 'th': + if (attrs.colspan || attrs.rowspan) + for (var k = this.STACK.length, item; item = this.STACK[--k];) + if (item.name == 'table') { + item.c = void 0; + break; + } + } + if (attrs.align) { + styleObj['text-align'] = attrs.align; + attrs.align = void 0; + } + // 压缩 style + var styles = style.split(';'); + style = ''; + for (var i = 0, len = styles.length; i < len; i++) { + var info = styles[i].split(':'); + if (info.length < 2) continue; + let key = info[0].trim().toLowerCase(), + value = info.slice(1).join(':').trim(); + if (value.includes('-webkit') || value.includes('-moz') || value.includes('-ms') || value.includes('-o') || value.includes( + 'safe')) + style += `;${key}:${value}`; + else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import')) + styleObj[key] = value; + } + if (node.name == 'img') { + if (attrs.src && !attrs.ignore) { + if (this.bubble()) + attrs.i = (this.imgNum++).toString(); + else attrs.ignore = 'T'; + } + if (attrs.ignore) { + style += ';-webkit-touch-callout:none'; + styleObj['max-width'] = '100%'; + } + var width; + if (styleObj.width) width = styleObj.width; + else if (attrs.width) width = attrs.width.includes('%') ? attrs.width : attrs.width + 'px'; + if (width) { + styleObj.width = width; + attrs.width = '100%'; + if (parseInt(width) > windowWidth) { + styleObj.height = ''; + if (attrs.height) attrs.height = void 0; + } + } + if (styleObj.height) { + attrs.height = styleObj.height; + styleObj.height = ''; + } else if (attrs.height && !attrs.height.includes('%')) + attrs.height += 'px'; + } + for (var key in styleObj) { + var value = styleObj[key]; + if (!value) continue; + if (key.includes('flex') || key == 'order' || key == 'self-align') node.c = 1; + // 填充链接 + if (value.includes('url')) { + var j = value.indexOf('('); + if (j++ != -1) { + while (value[j] == '"' || value[j] == "'" || blankChar[value[j]]) j++; + value = value.substr(0, j) + this.getUrl(value.substr(j)); + } + } + // 转换 rpx + else if (value.includes('rpx')) + value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px'); + else if (key == 'white-space' && value.includes('pre') && !close) + this.pre = node.pre = true; + style += `;${key}:${value}`; + } + style = style.substr(1); + if (style) attrs.style = style; + if (!close) { + node.children = []; + if (node.name == 'pre' && cfg.highlight) { + this.remove(node); + this.pre = node.pre = true; + } + this.siblings().push(node); + this.STACK.push(node); + } else if (!cfg.filter || cfg.filter(node, this) != false) + this.siblings().push(node); + } else { + if (!close) this.remove(node); + else if (node.name == 'source') { + var parent = this.parent(); + if (parent && (parent.name == 'video' || parent.name == 'audio') && node.attrs.src) + parent.attrs.source.push(node.attrs.src); + } else if (node.name == 'base' && !this.domain) this.domain = node.attrs.href; + } + if (this.data[this.i] == '/') this.i++; + this.start = this.i + 1; + this.state = this.Text; +} +// 移除标签 +MpHtmlParser.prototype.remove = function(node) { + var name = node.name, + j = this.i; + // 处理 svg + var handleSvg = () => { + var src = this.data.substring(j, this.i + 1); + if (!node.attrs.xmlns) src = ' xmlns="http://www.w3.org/2000/svg"' + src; + var i = j; + while (this.data[j] != '<') j--; + src = this.data.substring(j, i).replace("viewbox", "viewBox") + src; + var parent = this.parent(); + if (node.attrs.width == '100%' && parent && (parent.attrs.style || '').includes('inline')) + parent.attrs.style = 'width:300px;max-width:100%;' + parent.attrs.style; + this.siblings().push({ + name: 'img', + attrs: { + src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'), + style: (/vertical[^;]+/.exec(node.attrs.style) || []).shift(), + ignore: 'T' + } + }) + } + if (node.name == 'svg' && this.data[j] == '/') return handleSvg(this.i++); + while (1) { + if ((this.i = this.data.indexOf('', this.i)) == -1) this.i = this.data.length; + if (name == 'svg') handleSvg(); + return; + } + } +} +// 节点出栈处理 +MpHtmlParser.prototype.popNode = function(node) { + // 空白符处理 + if (node.pre) { + node.pre = this.pre = void 0; + for (let i = this.STACK.length; i--;) + if (this.STACK[i].pre) + this.pre = true; + } + var siblings = this.siblings(), + len = siblings.length, + childs = node.children; + if (node.name == 'head' || (cfg.filter && cfg.filter(node, this) == false)) + return siblings.pop(); + var attrs = node.attrs; + // 替换一些标签名 + if (cfg.blockTags[node.name]) node.name = 'div'; + else if (!cfg.trustTags[node.name]) node.name = 'span'; + // 去除块标签前后空串 + if (node.name == 'div' || node.name == 'p' || node.name[0] == 't') { + if (len > 1 && siblings[len - 2].text == ' ') + siblings.splice(--len - 1, 1); + if (childs.length && childs[childs.length - 1].text == ' ') + childs.pop(); + } + // 处理列表 + if (node.c && (node.name == 'ul' || node.name == 'ol')) { + if ((node.attrs.style || '').includes('list-style:none')) { + for (let i = 0, child; child = childs[i++];) + if (child.name == 'li') + child.name = 'div'; + } else if (node.name == 'ul') { + var floor = 1; + for (let i = this.STACK.length; i--;) + if (this.STACK[i].name == 'ul') floor++; + if (floor != 1) + for (let i = childs.length; i--;) + childs[i].floor = floor; + } else { + for (let i = 0, num = 1, child; child = childs[i++];) + if (child.name == 'li') { + child.type = 'ol'; + child.num = ((num, type) => { + if (type == 'a') return String.fromCharCode(97 + (num - 1) % 26); + if (type == 'A') return String.fromCharCode(65 + (num - 1) % 26); + if (type == 'i' || type == 'I') { + num = (num - 1) % 99 + 1; + var one = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'], + ten = ['X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'], + res = (ten[Math.floor(num / 10) - 1] || '') + (one[num % 10 - 1] || ''); + if (type == 'i') return res.toLowerCase(); + return res; + } + return num; + })(num++, attrs.type) + '.'; + } + } + } + // 处理表格的边框 + if (node.name == 'table') { + var padding = attrs.cellpadding, + spacing = attrs.cellspacing, + border = attrs.border; + if (node.c) { + this.bubble(); + attrs.style = (attrs.style || '') + ';display:table'; + if (!padding) padding = 2; + if (!spacing) spacing = 2; + } + if (border) attrs.style = `border:${border}px solid gray;${attrs.style || ''}`; + if (spacing) attrs.style = `border-spacing:${spacing}px;${attrs.style || ''}`; + if (border || padding || node.c) + (function f(ns) { + for (var i = 0, n; n = ns[i]; i++) { + if (n.type == 'text') continue; + var style = n.attrs.style || ''; + if (node.c && n.name[0] == 't') { + n.c = 1; + style += ';display:table-' + (n.name == 'th' || n.name == 'td' ? 'cell' : (n.name == 'tr' ? 'row' : 'row-group')); + } + if (n.name == 'th' || n.name == 'td') { + if (border) style = `border:${border}px solid gray;${style}`; + if (padding) style = `padding:${padding}px;${style}`; + } else f(n.children || []); + if (style) n.attrs.style = style; + } + })(childs) + if (this.options.autoscroll) { + var table = Object.assign({}, node); + node.name = 'div'; + node.attrs = { + style: 'overflow:scroll' + } + node.children = [table]; + } + } + this.CssHandler.pop && this.CssHandler.pop(node); + // 自动压缩 + if (node.name == 'div' && !Object.keys(attrs).length && childs.length == 1 && childs[0].name == 'div') + siblings[len - 1] = childs[0]; +} +// 状态机 +MpHtmlParser.prototype.Text = function(c) { + if (c == '<') { + var next = this.data[this.i + 1], + isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + if (isLetter(next)) { + this.setText(); + this.start = this.i + 1; + this.state = this.TagName; + } else if (next == '/') { + this.setText(); + if (isLetter(this.data[++this.i + 1])) { + this.start = this.i + 1; + this.state = this.EndTag; + } else this.Comment(); + } else if (next == '!' || next == '?') { + this.setText(); + this.Comment(); + } + } +} +MpHtmlParser.prototype.Comment = function() { + var key; + if (this.data.substring(this.i + 2, this.i + 4) == '--') key = '-->'; + else if (this.data.substring(this.i + 2, this.i + 9) == '[CDATA[') key = ']]>'; + else key = '>'; + if ((this.i = this.data.indexOf(key, this.i + 2)) == -1) this.i = this.data.length; + else this.i += key.length - 1; + this.start = this.i + 1; + this.state = this.Text; +} +MpHtmlParser.prototype.TagName = function(c) { + if (blankChar[c]) { + this.tagName = this.section(); + while (blankChar[this.data[this.i]]) this.i++; + if (this.isClose()) this.setNode(); + else { + this.start = this.i; + this.state = this.AttrName; + } + } else if (this.isClose()) { + this.tagName = this.section(); + this.setNode(); + } +} +MpHtmlParser.prototype.AttrName = function(c) { + if (c == '=' || blankChar[c] || this.isClose()) { + this.attrName = this.section(); + if (blankChar[c]) + while (blankChar[this.data[++this.i]]); + if (this.data[this.i] == '=') { + while (blankChar[this.data[++this.i]]); + this.start = this.i--; + this.state = this.AttrValue; + } else this.setAttr(); + } +} +MpHtmlParser.prototype.AttrValue = function(c) { + if (c == '"' || c == "'") { + this.start++; + if ((this.i = this.data.indexOf(c, this.i + 1)) == -1) return this.i = this.data.length; + this.attrVal = this.section(); + this.i++; + } else { + for (; !blankChar[this.data[this.i]] && !this.isClose(); this.i++); + this.attrVal = this.section(); + } + this.setAttr(); +} +MpHtmlParser.prototype.EndTag = function(c) { + if (blankChar[c] || c == '>' || c == '/') { + var name = this.section().toLowerCase(); + for (var i = this.STACK.length; i--;) + if (this.STACK[i].name == name) break; + if (i != -1) { + var node; + while ((node = this.STACK.pop()).name != name) this.popNode(node); + this.popNode(node); + } else if (name == 'p' || name == 'br') + this.siblings().push({ + name, + attrs: {} + }); + this.i = this.data.indexOf('>', this.i); + this.start = this.i + 1; + if (this.i == -1) this.i = this.data.length; + else this.state = this.Text; + } +} +module.exports = MpHtmlParser; diff --git a/yudao-vue-ui/components/jyf-parser/libs/config.js b/yudao-vue-ui/components/jyf-parser/libs/config.js new file mode 100644 index 000000000..1cfc111b5 --- /dev/null +++ b/yudao-vue-ui/components/jyf-parser/libs/config.js @@ -0,0 +1,93 @@ +/* 配置文件 */ +// #ifdef MP-WEIXIN +const canIUse = wx.canIUse('editor'); // 高基础库标识,用于兼容 +// #endif +module.exports = { + // 出错占位图 + errorImg: null, + // 过滤器函数 + filter: null, + // 代码高亮函数 + highlight: null, + // 文本处理函数 + onText: null, + // 实体编码列表 + entities: { + quot: '"', + apos: "'", + semi: ';', + nbsp: '\xA0', + ensp: '\u2002', + emsp: '\u2003', + ndash: '–', + mdash: '—', + middot: '·', + lsquo: '‘', + rsquo: '’', + ldquo: '“', + rdquo: '”', + bull: '•', + hellip: '…' + }, + blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'), + boolAttrs: makeMap('allowfullscreen,autoplay,autostart,controls,ignore,loop,muted'), + // 块级标签,将被转为 div + blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,section' + ( + // #ifdef MP-WEIXIN + canIUse ? '' : + // #endif + ',pre')), + // 将被移除的标签 + ignoreTags: makeMap( + 'area,base,canvas,frame,input,link,map,meta,param,script,source,style,svg,textarea,title,track,wbr' + // #ifdef MP-WEIXIN + + (canIUse ? ',rp' : '') + // #endif + // #ifndef APP-PLUS + + ',iframe' + // #endif + ), + // 只能被 rich-text 显示的标签 + richOnlyTags: makeMap('a,colgroup,fieldset,legend,table' + // #ifdef MP-WEIXIN + + (canIUse ? ',bdi,bdo,caption,rt,ruby' : '') + // #endif + ), + // 自闭合的标签 + selfClosingTags: makeMap( + 'area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr' + ), + // 信任的标签 + trustTags: makeMap( + 'a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video' + // #ifdef MP-WEIXIN + + (canIUse ? ',bdi,bdo,caption,pre,rt,ruby' : '') + // #endif + // #ifdef APP-PLUS + + ',embed,iframe' + // #endif + ), + // 默认的标签样式 + userAgentStyles: { + address: 'font-style:italic', + big: 'display:inline;font-size:1.2em', + blockquote: 'background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px', + caption: 'display:table-caption;text-align:center', + center: 'text-align:center', + cite: 'font-style:italic', + dd: 'margin-left:40px', + mark: 'background-color:yellow', + pre: 'font-family:monospace;white-space:pre;overflow:scroll', + s: 'text-decoration:line-through', + small: 'display:inline;font-size:0.8em', + u: 'text-decoration:underline' + } +} + +function makeMap(str) { + var map = Object.create(null), + list = str.split(','); + for (var i = list.length; i--;) + map[list[i]] = true; + return map; +} diff --git a/yudao-vue-ui/components/jyf-parser/libs/handler.wxs b/yudao-vue-ui/components/jyf-parser/libs/handler.wxs new file mode 100644 index 000000000..d3b1aaabe --- /dev/null +++ b/yudao-vue-ui/components/jyf-parser/libs/handler.wxs @@ -0,0 +1,22 @@ +var inline = { + abbr: 1, + b: 1, + big: 1, + code: 1, + del: 1, + em: 1, + i: 1, + ins: 1, + label: 1, + q: 1, + small: 1, + span: 1, + strong: 1, + sub: 1, + sup: 1 +} +module.exports = { + use: function(item) { + return !item.c && !inline[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1 + } +} diff --git a/yudao-vue-ui/components/jyf-parser/libs/trees.vue b/yudao-vue-ui/components/jyf-parser/libs/trees.vue new file mode 100644 index 000000000..8232aac14 --- /dev/null +++ b/yudao-vue-ui/components/jyf-parser/libs/trees.vue @@ -0,0 +1,500 @@ +