wanyuan 7 mesi fa
parent
commit
65dd3b26ef
55 ha cambiato i file con 3674 aggiunte e 16 eliminazioni
  1. 14 0
      02-script/sql/V1.1__20240725_createOrgIm.sql
  2. 24 4
      tc-service/tap-task/src/main/java/com/minto/app/task/manager/TaskByTypeManagerImpl.java
  3. 15 7
      tc-service/tap-task/src/main/java/com/minto/app/task/manager/TaskManagerImpl.java
  4. 22 4
      tc-service/tap-task/src/main/java/com/minto/app/task/manager/TaskMilestoneManagerImpl.java
  5. 7 0
      td-service/td-apps/src/main/java/com/minto/web/td/TdByTypeController.java
  6. 5 0
      tip-api/pom.xml
  7. 31 0
      tip-api/src/main/java/com/minto/app/organization/beans/OrgImBean.java
  8. 28 0
      tip-api/src/main/java/com/minto/app/organization/manager/IOrgImMapper.java
  9. 87 0
      tip-api/src/main/java/com/minto/app/organization/workpro/WorkProMessagePipeline.java
  10. 149 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/AbstractApi.java
  11. 47 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/AbstractListRApi.java
  12. 45 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/AbstractPRApi.java
  13. 48 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/IWorkProImApi.java
  14. 65 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/message/MessageSendMsg.java
  15. 83 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/message/MessageSendMsgFormview.java
  16. 91 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptCreate.java
  17. 48 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptDelete.java
  18. 74 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptDetail.java
  19. 69 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptSearch.java
  20. 91 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptSet.java
  21. 65 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptUserCreate.java
  22. 54 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptUserDelete.java
  23. 90 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsCreate.java
  24. 56 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsDel.java
  25. 101 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsExportUser.java
  26. 62 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsList.java
  27. 75 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsSet.java
  28. 78 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsTree.java
  29. 80 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/token/TokenCreate.java
  30. 59 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/token/TokenDelete.java
  31. 77 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/token/TokenGet.java
  32. 59 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/token/TokenRefresh.java
  33. 155 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersCreate.java
  34. 44 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersDelete.java
  35. 92 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersGet.java
  36. 54 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersGetId.java
  37. 84 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersGetUsers.java
  38. 94 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersSearch.java
  39. 89 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersSearchInner.java
  40. 154 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersSet.java
  41. 65 0
      tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersSetPwd.java
  42. 59 0
      tip-api/src/main/java/com/minto/app/organization/workpro/config/WorkProConfig.java
  43. 34 0
      tip-api/src/main/java/com/minto/app/organization/workpro/service/IWorkProService.java
  44. 417 0
      tip-api/src/main/java/com/minto/app/organization/workpro/service/impl/WorkProServiceImpl.java
  45. 42 0
      tip-api/src/main/java/com/minto/app/organization/workpro/utils/HttpUtil.java
  46. 120 0
      tip-api/src/main/java/com/minto/app/task/util/TaskImUtil.java
  47. 2 0
      tip-front/src/main/java/com/minto/app/organization/controller/OrgCorpController.java
  48. 126 0
      tip-front/src/main/java/com/minto/app/organization/workpro/controller/WorkproController.java
  49. 2 0
      tip-front/src/main/java/com/minto/web/tc/GeneralController.java
  50. 15 0
      tip-service/tip-common/src/main/java/com/minto/app/organization/beans/org_im.hbm.xml
  51. 20 0
      tip-service/tip-common/src/main/java/com/minto/app/organization/dao/IOrgImDao.java
  52. 28 0
      tip-service/tip-common/src/main/java/com/minto/app/organization/dao/OrgImDaoImpl.java
  53. 63 0
      tip-service/tip-common/src/main/java/com/minto/app/organization/manager/OrgImManagerImpl.java
  54. 6 1
      tip-service/tip-common/src/main/java/org/springframework/security/authentication/dao/TIPAuthenticationProvider.java
  55. 10 0
      tip-service/tip-common/src/main/java/org/springframework/security/web/authentication/logout/TIPLogoutSuccessHandler.java

+ 14 - 0
02-script/sql/V1.1__20240725_createOrgIm.sql

@@ -0,0 +1,14 @@
+CREATE TABLE "org_im"(
+    "id"          BIGINT        NOT NULL,
+    "im_id"       VARCHAR(64)   NOT NULL,
+    "minto_id"    VARCHAR(64)   NOT NULL,
+    "type"        VARCHAR(64)   NOT NULL,
+    "create_time" TIMESTAMP     NOT NULL,
+    "update_time" TIMESTAMP     NOT NULL,
+    CONSTRAINT    "org_im_pkey" NOT CLUSTER PRIMARY KEY ("id")
+);
+COMMENT ON COLUMN "org_im"."im_id"  IS  'IM系统内的数据id';
+COMMENT ON COLUMN "org_im"."minto_id" IS '系统内的数据id';
+COMMENT ON COLUMN "org_im"."type" IS '类型';
+COMMENT ON COLUMN "org_im"."create_time" IS '创建时间';
+COMMENT ON COLUMN "org_im"."update_time" IS '更新时间';

+ 24 - 4
tc-service/tap-task/src/main/java/com/minto/app/task/manager/TaskByTypeManagerImpl.java

@@ -2977,6 +2977,7 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
             } else {
                 receiverId = summary.getCreatorId();
             }
+            OrgPersonBean receiverPerson = orgManager.findPersonById(receiverId);
             ITaskInfoManager TaskInfoManager = AppContext.getBean(ITaskInfoManager.class);
             //修改发送显示事项责任人或单位签收 modify liusx 2018-5-15 19:41:45
             // 采用上报单位的部门,而不是当前人所在部门 Modifier: <Zhengyu.Hu> 2018/7/31 下午1:06 end.
@@ -3006,6 +3007,8 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
 
                 TaskByTypeUtil.sendTaskMessage(MessageResourceTypeEnum.Plan.getKey(),AppContext.currentUserId(), receiverId, message, String.valueOf(summary.getId()),
                         summary.getOrgCorporationId());
+                //发送IM消息
+                //TaskImUtil.sendMessage(summary, message, receiverPerson);
                 //添加消息分类 shan.wen 2020-1-6
                 TaskByTypeMsgUtil.sendTaskMessage4SpecificReceiver(summary.getTaskTypeId(),message,AppContext.currentUserId(),
                         Lists.<Long>newArrayList(receiverId), summary.getId(),summary.getOrgCorporationId(), MessageResourceTypeEnum.Plan.getKey());
@@ -3018,7 +3021,7 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
                     //发送者登录名
                     String senderName=AppContext.currentLoginName();
                     //接收者登录名
-                    String[] receiverName= new String[]{orgManager.findPersonById(receiverId).getUsername()};
+                    String[] receiverName= new String[]{receiverPerson.getUsername()};
                     //消息连接
                     String baseUrl = AppContext.getProperty("tc.baseUrl");
                     //String[] url=new String[]{"http://localhost:8080/jn_web/tw/home/ssologin/oa/?loginName="+receiverName[0]};
@@ -3207,6 +3210,7 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
             } else {
                 receiverId = summary.getCreatorId();
             }
+            OrgPersonBean receiverPerson = orgManager.findPersonById(receiverId);
             ITaskInfoManager TaskInfoManager = AppContext.getBean(ITaskInfoManager.class);
             //修改发送显示事项责任人或单位签收 modify liusx 2018-5-15 19:41:45
             Long did = AppContext.currentDepartmentId();
@@ -3238,6 +3242,8 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
 
             // todo 这里还需要给督办人发消息
             TaskByTypeUtil.sendTaskMessage(MessageResourceTypeEnum.Sign.getKey(), personId, receiverId, message, String.valueOf(summary.getId()),summary.getOrgCorporationId());
+            //发送IM消息
+            //TaskImUtil.sendMessage(summary, message, receiverPerson);
             // 给指定的消息接收人推送消息
             TaskByTypeMsgUtil.sendTaskMessage4SpecificReceiver(summary.getTaskTypeId(), message, AppContext.currentUserId(),
                     Lists.<Long>newArrayList(receiverId), summary.getId(), summary.getOrgCorporationId(), MessageResourceTypeEnum.Sign.getKey());
@@ -3250,7 +3256,7 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
                 //发送者登录名
                 String senderName = AppContext.currentLoginName();
                 //接收者登录名
-                String[] receiverName = new String[]{orgManager.findPersonById(receiverId).getUsername()};
+                String[] receiverName = new String[]{receiverPerson.getUsername()};
                 //消息连接
                 String baseUrl = AppContext.getProperty("tc.baseUrl");
                 //String[] url=new String[]{"http://localhost:8080/jn_web/tw/home/ssologin/oa/?loginName="+receiverName[0]};
@@ -8667,6 +8673,8 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
                         //推送消息给上报人
                         String message = person.getPname() + "退回了您在事项:<" + task.getTitle() + ">中汇报的内容";
                         TaskByTypeUtil.sendTaskMessage(MessageResourceTypeEnum.Supervise.getKey(),pid, taskReportBean.getCreateBy(), message, task.getId().toString(), person.getOrgCorporationId());
+                        //发送IM消息
+                        //TaskImUtil.sendMessage(task, message, creatPerson);
                         taskManager.updateTaskMemberPhaseReportConfigByTaskIdAndMemberIdAndPhaseId(taskReportBean, TaskEnum.TaskMemberPhaseReportConfigIsReportEnum.notNeported.getKey());
 
                     }
@@ -9047,6 +9055,7 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
             if (task!=null&&project!=null) {
                 Long pid = AppContext.currentUserId();
                 OrgPersonBean person = orgManager.findPersonById(pid);
+                OrgPersonBean projectCreatePerson = orgManager.findPersonById(project.getCreateBy());
                 task.setTstate(TaskSummaryStateEnum.BackState.getKey());
                 project.setSendBackMessage(content);
                 project.setUpdateDate(new Date());
@@ -9068,6 +9077,8 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
                 String message = person.getPname()+"打回了您上报的事项:<"+task.getTitle()+">";
                 TaskByTypeUtil.sendTaskMessage(MessageResourceTypeEnum.More.getKey(),pid,project.getCreateBy(),message,
                         id.toString(),person.getOrgCorporationId());
+                //发送IM消息
+                //TaskImUtil.sendMessage(task, message, projectCreatePerson);
             }
         } catch (Exception e) {
             throw new BusinessException(e);
@@ -12451,15 +12462,18 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
 
             //发送消息
             String message = "{0}给你分派了事项《{1}》";
+            String content = MessageFormat.format(message,AppContext.currentUserName(),taskSummaryBean.getTitle());
             AppContext.getBean(MessageService.class).sendBizMessages(
                     MessageEnum.MessageTypeEnum.System.getKey(),
                     personId,
                     MessageResourceTypeEnum.NewTask.getKey(),
                     taskSummaryBean.getId().toString(),
-                    MessageFormat.format(message,AppContext.currentUserName(),taskSummaryBean.getTitle()),
+                    content,
                     OrgUtil.getOrgEntityIdsByBeans(entities),
                     cid
             );
+            //发送IM消息
+            //TaskImUtil.sendMessage(taskSummaryBean, content, entities);
         }
     }
 
@@ -13007,15 +13021,21 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
                 );
                 // 推送消息
                 String msg = "{0}给你分派了事项《{1}》{2}";
+                String content = MessageFormat.format(msg, AppContext.currentUserName(), taskSummaryBean.getTitle(),
+                        ";" + "分派原因:" + desc);
                 AppContext.getBean(MessageService.class).sendBizMessages(
                         MessageEnum.MessageTypeEnum.System.getKey(),
                         pid,
                         MessageResourceTypeEnum.NewTask.getKey(),
                         taskSummaryBean.getId().toString(),
-                        MessageFormat.format(msg,AppContext.currentUserName(),taskSummaryBean.getTitle(),";分派原因:" + desc),
+                        content,
                         OrgUtil.getOrgEntityIdsByBeans(entities),
                         cid
                 );
+                //发送IM消息
+                //TaskImUtil.sendMessage(taskSummaryBean, content,
+                //        entities.stream().filter(e -> e instanceof OrgPersonBean).map(e -> (OrgPersonBean)e)
+                //                .collect(Collectors.toList()));
            // }
 
             //inspired 分派生成待办

+ 15 - 7
tc-service/tap-task/src/main/java/com/minto/app/task/manager/TaskManagerImpl.java

@@ -12461,7 +12461,8 @@ public class TaskManagerImpl implements ITaskManager {
 			if(bossIds != null && summarys != null){
 				Long pid = AppContext.currentUserId();
 				String userName = AppContext.currentUserName();
-				for (Long bossId : bossIds) {
+				List<OrgPersonBean> bossPersonList = orgManager.findPersonsById(List.of(bossIds));
+				for (OrgPersonBean boss : bossPersonList) {
 					for (TaskSummaryBean summary : summarys) {
 //						behManager.addBehavior(
 //								AppContext.currentLoginCorporation(),
@@ -12482,13 +12483,16 @@ public class TaskManagerImpl implements ITaskManager {
 						Map<String, Object> msgMap = new HashMap<>();
 						msgMap.put("name", userName);
 						//这里是领导名称
-						msgMap.put("operObject", orgManager.findPersonById(bossId).getPname());
+						msgMap.put("operObject", boss.getPname());
 						msgMap.put("operContent", summary.getTitle());
 						msgMap.put("notifyType", SmsEnum.MessageNotifyType.PushLeader.getKey());
 						msgMap.put("messageType", SmsEnum.TaskMessageType.Task.getKey());
 						msgMap.put("taskTypeId", summary.getTaskTypeId());
 						msg = taskManager.buildMessageInfo(msgMap, msg);
-						TaskByTypeUtil.sendTaskMessage(MessageResourceTypeEnum.NewTask.getKey(),pid,bossId,msg,summary.getId()+"",saveList.get(0).getOrgCorporationId());
+						TaskByTypeUtil.sendTaskMessage(MessageResourceTypeEnum.NewTask.getKey(),pid,boss.getId(),msg,
+								summary.getId()+"",saveList.get(0).getOrgCorporationId());
+						//发送IM消息
+						//TaskImUtil.sendMessage(summary, msg, boss);
 					}
 				}
 			}
@@ -12602,12 +12606,16 @@ public class TaskManagerImpl implements ITaskManager {
 			}
 
 			if(deleteList.size() > 0){
-				for (Long bossId : pidList) {
-					for (TaskSummaryBean summary : summarys) {
-						String msg = userName + "撤销了事项<"+summary.getTitle()+">";
-						TaskByTypeUtil.sendTaskMessage(pid,bossId,msg,summary.getId()+"",deleteList.get(0).getOrgCorporationId());
+				for(TaskSummaryBean summary : summarys){
+					String msg = userName + "撤销了事项<" + summary.getTitle() + ">";
+					for(Long bossId : pidList){
+						TaskByTypeUtil.sendTaskMessage(pid, bossId, msg, summary.getId() + "",
+								deleteList.get(0).getOrgCorporationId());
 					}
+					//发送IM消息
+					//TaskImUtil.sendMessage(summary, msg, pidList.toArray(new Long[0]));
 				}
+
 			}
 			taskMemberDao.deleteAll(deleteList);
 		} catch (Exception e) {

+ 22 - 4
tc-service/tap-task/src/main/java/com/minto/app/task/manager/TaskMilestoneManagerImpl.java

@@ -11,6 +11,7 @@ import com.minto.app.behavior.enums.BehaviorEnum;
 import com.minto.app.behavior.manager.IBehManager;
 import com.minto.app.task.dao.ITaskMilestoneDao;
 import com.minto.app.task.dto.WebTaskMilestone;
+import com.minto.app.task.util.TaskImUtil;
 import com.minto.app.task.util.TaskMemberAgentUtil;
 import com.minto.app.tc.knowledge.enums.KmEnum;
 import com.minto.app.organization.manager.IOrgManager;
@@ -352,15 +353,20 @@ public class TaskMilestoneManagerImpl implements ITaskMilestoneManager {
 
             // 给督办人
             if (CollectionUtil.isNotEmpty(supervisePersons)) {
+                String msgContent = MessageFormat.format(message,orgEntity.getName(), taskSummaryBean.getTitle());
                 getMessageManager().sendBizMessages(
                         MessageEnum.MessageTypeEnum.System.getKey(),
                         AppContext.currentUserId(),
                         ResourceEnum.ResourceTypeEnum.Task.getKey(),
                         taskMilestone.getTaskId().toString(),
-                        MessageFormat.format(message,orgEntity.getName(), taskSummaryBean.getTitle()),
+                        msgContent,
                         OrgUtil.getOrgEntityIdsByBeans(supervisePersons),
                         AppContext.currentLoginCorporation()
                 );
+                //发送IM消息
+                //TaskImUtil.sendMessage(taskSummaryBean, msgContent,
+                //        supervisePersons.stream().filter(e -> e instanceof OrgPersonBean).map(e -> (OrgPersonBean)e)
+                //                .collect(Collectors.toList()));
             }
         }
 
@@ -485,15 +491,18 @@ public class TaskMilestoneManagerImpl implements ITaskMilestoneManager {
         // 暂时不考虑承办单位为人的情况
         List<OrgPersonBean> orgPersonBeans = TaskMemberAgentUtil.getDepProxy(taskMemberBean.getResourceId(),taskMemberBean.getOrgCorporationId());
         if(CollectionUtil.isNotEmpty(orgPersonBeans)){
+            String msgContent = MessageFormat.format("您在事项《{0}》中的节点计划被退回.",taskSummaryBean.getTitle());
             getMessageManager().sendBizMessages(
                     MessageEnum.MessageTypeEnum.System.getKey(),
                     AppContext.currentUserId(),
                     ResourceEnum.ResourceTypeEnum.Task.getKey(),
                     taskMilestone.getTaskId().toString(),
-                    MessageFormat.format("您在事项《{0}》中的节点计划被退回.",taskSummaryBean.getTitle()),
+                    msgContent,
                     OrgUtil.getOrgPersonIdsByBeans(orgPersonBeans),
                     AppContext.currentLoginCorporation()
             );
+            //发送IM消息
+            //TaskImUtil.sendMessage(taskSummaryBean, msgContent, orgPersonBeans);
         }
         return result;
     }
@@ -702,15 +711,21 @@ public class TaskMilestoneManagerImpl implements ITaskMilestoneManager {
                 }
                 List<OrgEntity> orgEntitys = getOrgManager().findOrgEntities(builder.toString());
                 if (CollectionUtil.isNotEmpty(orgEntitys)) {
+                    String msgContent = MessageFormat.format("{0}在事项《{1}》中的汇报了节点计划.", orgEntity.getName(),
+                            taskSummaryBean.getTitle());
                     getMessageManager().sendBizMessages(
                             MessageEnum.MessageTypeEnum.System.getKey(),
                             AppContext.currentUserId(),
                             ResourceEnum.ResourceTypeEnum.Task.getKey(),
                             taskMilestone.getTaskId().toString(),
-                            MessageFormat.format("{0}在事项《{1}》中的汇报了节点计划.",orgEntity.getName(), taskSummaryBean.getTitle()),
+                            msgContent,
                             OrgUtil.getOrgEntityIdsByBeans(orgEntitys),
                             AppContext.currentLoginCorporation()
                     );
+                    //发送IM消息
+                    //TaskImUtil.sendMessage(taskSummaryBean, msgContent,
+                    //        orgEntitys.stream().filter(e -> e instanceof OrgPersonBean).map(e -> (OrgPersonBean)e)
+                    //                .collect(Collectors.toList()));
                 }
             }
         }
@@ -763,15 +778,18 @@ public class TaskMilestoneManagerImpl implements ITaskMilestoneManager {
             // 暂时不考虑承办单位为人的情况
             List<OrgPersonBean> orgPersonBeans = TaskMemberAgentUtil.getDepProxy(taskMemberBean.getResourceId(),taskMemberBean.getOrgCorporationId());
             if(CollectionUtil.isNotEmpty(orgPersonBeans)){
+                String msgContent = MessageFormat.format("您在事项《{0}》中的节点计划被锁定.",taskSummaryBean.getTitle());
                 getMessageManager().sendBizMessages(
                         MessageEnum.MessageTypeEnum.System.getKey(),
                         AppContext.currentUserId(),
                         ResourceEnum.ResourceTypeEnum.Task.getKey(),
                         taskMilestone.getTaskId().toString(),
-                        MessageFormat.format("您在事项《{0}》中的节点计划被锁定.",taskSummaryBean.getTitle()),
+                        msgContent,
                         OrgUtil.getOrgPersonIdsByBeans(orgPersonBeans),
                         AppContext.currentLoginCorporation()
                 );
+                //发送IM消息
+                //TaskImUtil.sendMessage(taskSummaryBean, msgContent, orgPersonBeans);
             }
         }
 

+ 7 - 0
td-service/td-apps/src/main/java/com/minto/web/td/TdByTypeController.java

@@ -105,6 +105,7 @@ import com.minto.web.td.util.TaskPackUtil;
 import com.minto.web.td.util.TdBaseEnum;
 import com.minto.web.td.util.TdTaskProcessUtil;
 import io.swagger.v3.oas.annotations.Operation;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.hibernate.criterion.Criterion;
 import org.hibernate.criterion.Restrictions;
@@ -3605,6 +3606,7 @@ public class TdByTypeController extends TdBaseController {
                 Long cid = token.getDftCid();
                 String content = ReqUtil.getString(request, "content");
                 String deptIds[] = departmentId.split(",");
+                List<OrgPersonBean> personBeans = new ArrayList<>();
                 for (String deptId : deptIds) {
                     OrgUnitBean orgDepartmentBean = TdHelper.orgManager.findDepartmentById(Long.valueOf(deptId));
                     if (orgDepartmentBean != null) {
@@ -3620,6 +3622,11 @@ public class TdByTypeController extends TdBaseController {
                         }
                     }
                 }
+                if(CollectionUtils.isNotEmpty(personBeans)){
+                    TaskSummaryBean summary = taskManager.findTaskSummaryBeanById(taskId);
+                    //发送IM消息
+                    //TaskImUtil.sendMessage(summary, content, personBeans);
+                }
             } catch (Exception e) {
                 log.error(ExceptionUtil.printExceptionStackTrace(e));
                 responseBean = ResponseBean.createResponseBean(null, "服务器异常,获取失败,请重试", ERROR);

+ 5 - 0
tip-api/pom.xml

@@ -19,6 +19,11 @@
     <artifactId>minto-tip-api</artifactId>
 
     <dependencies>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.9</version>
+        </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>

+ 31 - 0
tip-api/src/main/java/com/minto/app/organization/beans/OrgImBean.java

@@ -0,0 +1,31 @@
+package com.minto.app.organization.beans;
+
+import java.util.Date;
+
+import com.minto.core.po.BasePO;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/25
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class OrgImBean extends BasePO{
+
+    private String imId;
+
+    private String mintoId;
+
+    private String type;
+
+    private Date createTime;
+
+    private Date updateTime;
+}

+ 28 - 0
tip-api/src/main/java/com/minto/app/organization/manager/IOrgImMapper.java

@@ -0,0 +1,28 @@
+package com.minto.app.organization.manager;
+
+import java.util.List;
+
+import com.minto.app.organization.beans.OrgImBean;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/25
+ */
+public interface IOrgImMapper{
+
+    public OrgImBean create(String imId, String mintoId, String type);
+
+    public void updateByMintoId(String mintoId, String imId);
+
+
+    public int deleteByImId(String imId);
+
+    public OrgImBean findByMintoId(String mintoId);
+
+    public List<OrgImBean> findByType(String type);
+
+}
+

+ 87 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/WorkProMessagePipeline.java

@@ -0,0 +1,87 @@
+package com.minto.app.organization.workpro;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.minto.app.message.beans.MessageBean;
+import com.minto.app.message.enums.MessageResourceTypeEnum;
+import com.minto.app.message.pipeline.MessagePipeline;
+import com.minto.app.organization.workpro.config.WorkProConfig;
+import com.minto.app.resource.enums.ResourceEnum;
+import com.minto.app.task.beans.TaskSummaryBean;
+import com.minto.app.task.manager.ITaskManager;
+import com.minto.app.task.util.TaskImUtil;
+import com.minto.core.po.BasePO;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/27
+ */
+@Component
+public class WorkProMessagePipeline implements MessagePipeline{
+    @Autowired
+    private ITaskManager taskManager;
+
+
+    private static Set<Integer> set = new HashSet<>();
+
+    static{
+        set.add(MessageResourceTypeEnum.Sign.getKey());
+        set.add(MessageResourceTypeEnum.Comment.getKey());
+        set.add(MessageResourceTypeEnum.More.getKey());
+        set.add(MessageResourceTypeEnum.Plan.getKey());
+        set.add(MessageResourceTypeEnum.Report.getKey());
+        set.add(MessageResourceTypeEnum.Supervise.getKey());
+        set.add(MessageResourceTypeEnum.End.getKey());
+        set.add(MessageResourceTypeEnum.Overdue.getKey());
+        set.add(MessageResourceTypeEnum.NewTask.getKey());
+        set.add(MessageResourceTypeEnum.GoalUrgeMessage.getKey());
+        set.add(MessageResourceTypeEnum.GoalUrgeAdminMessage.getKey());
+        //list.add(MessageResourceTypeEnum.Vedio.getKey());
+        set.add(ResourceEnum.ResourceTypeEnum.Task.getKey());
+        set.add(ResourceEnum.ResourceTypeEnum.msgc.getKey());
+        set.add(ResourceEnum.MessageResourceTypeEnum.NoticeOfSupervision.getKey());
+        set.add(ResourceEnum.MessageResourceTypeEnum.batch.getKey());
+
+        //list.add(ResourceEnum.MessageResourceTypeEnum.DataServerSpace.getKey());
+    }
+
+    @Override
+    public String getName(){
+        return " WorkPro";
+    }
+
+    @Override
+    public void sendMessage(List<MessageBean> messages){
+        List<MessageBean> collect = messages.stream()
+                .filter(e -> set.contains(e.getResourceType()) && StringUtils.isNotBlank(e.getResourceId()) && (
+                        "0".equals(e.getResourceId()) || NumberUtils.toLong(e.getResourceId()) != 0L))
+                .collect(Collectors.toList());
+        List<Long> taskIds = collect.stream().map(e -> Long.valueOf(e.getResourceId())).collect(Collectors.toList());
+        List<TaskSummaryBean> taskSummarys = taskManager.findTaskSummaryBeanByIds(taskIds);
+        Map<Long, TaskSummaryBean> taskMap = taskSummarys.stream().collect(Collectors.toMap(BasePO::getId, e -> e));
+        for(MessageBean message : collect){
+            TaskSummaryBean task = taskMap.get(Long.valueOf(message.getResourceId()));
+            if(task == null){
+                continue;
+            }
+            TaskImUtil.sendMessage(task, message.getSendTime(), message.getMessage(), message.getReceiverId());
+        }
+    }
+
+    @Override
+    public boolean isEnabled(){
+        WorkProConfig config = WorkProConfig.getInstance();
+        return config.isEnable();
+    }
+}

+ 149 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/AbstractApi.java

@@ -0,0 +1,149 @@
+package com.minto.app.organization.workpro.api;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import cn.hutool.core.util.HexUtil;
+import cn.hutool.crypto.digest.DigestUtil;
+import cn.hutool.http.HttpGlobalConfig;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.Method;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.minto.app.organization.workpro.config.WorkProConfig;
+import com.minto.core.util.JsonUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/17
+ */
+public abstract class AbstractApi<P, R> implements IWorkProImApi<P, R>{
+
+    private static final Logger log = LoggerFactory.getLogger(AbstractApi.class);
+
+    //@Getter
+    //private static final List<Class<? extends IWorkProImApi>> GET_TOKEN_API_CLASS_LIST = new ArrayList<>();
+
+    static{
+        //getTokenClassMap.add(GetToken.class);
+        //getTokenClassMap.add(GetStableToken.class);
+        //getTokenClassMap.add(com.kingtom.kirin.app.wechat.base.pubnum.api.token.GetToken.class);
+        //getTokenClassMap.add(com.kingtom.kirin.app.wechat.base.pubnum.api.token.GetStableToken.class);
+    }
+
+    protected JSONObject response;
+
+    private String name;
+
+    private String url;
+
+    private Method method;
+
+    private Map<String, String> header;
+
+    private int retry = 0;
+
+    protected AbstractApi(String name, String url, Method method){
+        this.name = name;
+        this.url = url;
+        this.method = method;
+        this.header = new HashMap<>();
+    }
+
+    @Override
+    public String getName(){
+        return name;
+    }
+
+    @Override
+    public String getUrl(){
+        return url;
+    }
+
+    @Override
+    public Method getMethod(){
+        return method;
+    }
+
+    @Override
+    public Map<String, String> getHeader(){
+        return header;
+    }
+
+    @Override
+    public JSONObject getResponse(){
+        return response;
+    }
+
+    @Override
+    public int getRetry(){
+        return retry;
+    }
+
+    @Override
+    public int findAndAddRetry(){
+        int r = retry;
+        retry++;
+        return r;
+    }
+
+    @Override
+    public void call(WorkProConfig config, String uid){
+        String appId = config.getAppid();
+        String appSecret = config.getAppSecret();
+        String timestamp = String.valueOf(System.currentTimeMillis());
+        String strToHash = appId + appSecret + timestamp;
+        byte[] hashBytes = DigestUtil.sha256(strToHash);
+        String hashHex = HexUtil.encodeHexStr(hashBytes);
+
+        getHeader().put("Content-Type", "application/json; charset=UTF-8");
+        getHeader().put("uid", uid != null ? uid : config.getUserId());
+        getHeader().put("lang", "zh-cn");
+        getHeader().put("appid", appId);
+        getHeader().put("timestamp", timestamp);
+        getHeader().put("authen", hashHex);
+        //log.info("workPro IM 接口[{}]开始发送,json={}", getName(), JsonUtil.toJSONString(this));
+        String body = null;
+        try(HttpResponse execute = HttpRequest.of(config.getUrl() + getUrl()).method(getMethod())
+                .headerMap(getHeader(), true).timeout(HttpGlobalConfig.getTimeout())
+                .body(JsonUtil.toJSONString(getParam()), getContentType()).execute()){
+            body = execute.body();
+        }
+        response = JSONUtil.parseObj(body);
+
+        if(isResponseOk()){
+            log.info("workPro IM 接口[{}]执行成功,json={}", getName(), JsonUtil.toJSONString(this));
+        } else{
+            log.error("workPro IM 接口[{}]发生错误,json={}", getName(), JsonUtil.toJSONString(this));
+        }
+    }
+
+    @Override
+    public boolean isResponseOk(){
+        //status、code、msg到底用哪一个?
+        Integer status = response == null ? null : response.get("status", Integer.class);
+        Integer code = response == null ? null : response.get("errcode", Integer.class);
+        String msg = response == null ? null : response.get("errmsg", String.class);
+        //todo 检查请求是否成功
+        return 1 == status;
+    }
+
+    @Override
+    public boolean isTokenError(){
+        return false;
+        //        Integer code = response == null ? null : (Integer)JsonUtils.toMap(response).get("errcode");
+        //        return code != null && WeChatConst.ResultCodeEnum.isTokenError(code) && !getTokenApiClassList
+        //        .contains(
+        //                this.getClass());
+    }
+
+    public String getContentType(){
+        return "application/json; charset=UTF-8";
+    }
+}

+ 47 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/AbstractListRApi.java

@@ -0,0 +1,47 @@
+package com.minto.app.organization.workpro.api;
+
+import java.util.List;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.minto.app.organization.workpro.config.WorkProConfig;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public abstract class AbstractListRApi<P, R> extends AbstractApi<P, List<R>>{
+
+    private P param;
+
+    private List<R> result;
+
+    protected AbstractListRApi(String name, String url, Method method, P param){
+        super(name, url, method);
+        this.param = param;
+    }
+
+    @JsonIgnore
+    public abstract Class<R> getResultClass();
+
+    @Override
+    public void call(WorkProConfig config, String uid){
+        super.call(config, uid);
+        if(isResponseOk()){
+            result = response.getBeanList("data", getResultClass());
+        }
+    }
+
+    @Override
+    public P getParam(){
+        return param;
+    }
+
+    @Override
+    public List<R> getResult(){
+        return result;
+    }
+}

+ 45 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/AbstractPRApi.java

@@ -0,0 +1,45 @@
+package com.minto.app.organization.workpro.api;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.minto.app.organization.workpro.config.WorkProConfig;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public abstract class AbstractPRApi<P, R> extends AbstractApi<P, R>{
+
+    private P param;
+
+    private R result;
+
+    protected AbstractPRApi(String name, String url, Method method, P param){
+        super(name, url, method);
+        this.param = param;
+    }
+
+    @JsonIgnore
+    public abstract Class<R> getResultClass();
+
+    @Override
+    public void call(WorkProConfig config, String uid){
+        super.call(config, uid);
+        if(isResponseOk()){
+            result = response.get("data", getResultClass());
+        }
+    }
+
+    @Override
+    public P getParam(){
+        return param;
+    }
+
+    @Override
+    public R getResult(){
+        return result;
+    }
+}

+ 48 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/IWorkProImApi.java

@@ -0,0 +1,48 @@
+package com.minto.app.organization.workpro.api;
+
+import java.util.Map;
+
+import cn.hutool.http.Method;
+import cn.hutool.json.JSONObject;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.minto.app.organization.workpro.config.WorkProConfig;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/17
+ */
+public interface IWorkProImApi<P, R>{
+
+    public String getName();
+
+    public String getUrl();
+
+    public Method getMethod();
+
+    public Map<String, String> getHeader();
+
+    public P getParam();
+
+    public JSONObject getResponse();
+
+    @JsonIgnore
+    public R getResult();
+
+    public int getRetry();
+
+    public int findAndAddRetry();
+
+    public void call(WorkProConfig config, String uid);
+
+    @JsonIgnore
+    public boolean isRequestOk();
+
+    @JsonIgnore
+    public boolean isResponseOk();
+
+    @JsonIgnore
+    public boolean isTokenError();
+}

+ 65 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/message/MessageSendMsg.java

@@ -0,0 +1,65 @@
+package com.minto.app.organization.workpro.api.message;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class MessageSendMsg extends AbstractPRApi<MessageSendMsg.Param, String>{
+
+    public MessageSendMsg(String sender, String recver, String text, String subject, String file, Param param){
+        super("MessageSendMsg", "/api/message/send_msg.html", Method.POST,
+                new Param(sender, recver, text, subject, file));
+    }
+
+    @Override
+    public Class<String> getResultClass(){
+        return String.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(getParam().getSender(), getParam().getRecver(), getParam().getText());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	发送者ID
+         */
+        private String sender;
+
+        /**
+         * true	json	接收者 用户:json格式 [{"id":"user_id1","name":"用户1"},{"id":"user_id2","name":"用户2"}]
+         */
+        private String recver;
+
+        /**
+         * true	string	内容
+         */
+        private String text;
+
+        /**
+         * false	string	标题 为空时会截取text内容
+         */
+        private String subject;
+
+        /**
+         * false	string	附件 通过 upload_file上传返回的 data
+         */
+        private String file;
+    }
+}

+ 83 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/message/MessageSendMsgFormview.java

@@ -0,0 +1,83 @@
+package com.minto.app.organization.workpro.api.message;
+
+import java.util.List;
+import java.util.Map;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class MessageSendMsgFormview extends AbstractPRApi<MessageSendMsgFormview.Param, String>{
+
+    public MessageSendMsgFormview(List<Map<String, String>> recver, String ctype, Map<String, String> refer,
+            String flag, String content, Map<String, Object> extdata){
+        super("MessageSendMsgFormview", "/api/message/send_msg_formview.html", Method.POST,
+                new Param(recver, ctype, refer, flag, content, extdata));
+    }
+
+    @Override
+    public Class<String> getResultClass(){
+        return String.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return CollectionUtils.isNotEmpty(getParam().getRecver());
+    }
+
+    /**
+     * 注意事项
+     * target.opentype 打开类型 1:内置浏览器(默认) 2:系统浏览器
+     * recver或recver_account,recver_account格式 ["test1","test2"],
+     * recver中的 role 可选,默认1为待办处理者,2是抄送者
+     * obj.s_type 可选 是待办的二级分类
+     * obj.create_uid 创建者,如果不传取当前用户
+     * content,如果flag=8是待办的内容
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	json	接收者 用户:json格式 [{"id":"user_id1","name":"用户1"},{"id":"user_id2","name":"用户2"}]
+         */
+        private List<Map<String, String>> recver;
+
+        /**
+         * false	string	会话类型 0 单聊 1 群组(当群组时 recver为字符串,群组ID) 3 应用
+         */
+        private String ctype;
+
+        /**
+         * false	string	参考者 2 强通知
+         */
+        private Map<String, String> refer;
+
+        /**
+         * false	string	标志 2 强通知 8 到待办箱
+         */
+        private String flag;
+
+        /**
+         * false	string	内容 将关键字放这里,可以用来搜索
+         */
+        private String content;
+
+        /**
+         * false	json	扩展数据
+         */
+        private Map<String, Object> extdata;
+    }
+}

+ 91 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptCreate.java

@@ -0,0 +1,91 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class DeptCreate extends AbstractPRApi<DeptCreate.Param, DeptCreate.Result>{
+
+    public DeptCreate(String orgId, String deptName, String deptId, String deptPid, Integer deptSort){
+        super("DeptCreate", "/api/orgs/dept_create.html", Method.POST,
+                new Param(orgId, deptName, deptId, deptPid, deptSort));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(getParam().getOrg_id(), getParam().getDept_name());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	组织ID
+         */
+        private String org_id;
+
+        /**
+         * true	string	部门名称
+         */
+        private String dept_name;
+
+        /**
+         * false	string	部门ID 不为空时,将使用该字段值为新增部门ID
+         */
+        private String dept_id;
+
+        /**
+         * false	string	上级部门ID
+         */
+        private String dept_pid;
+
+        /**
+         * false	integer	排序号
+         */
+        private Integer dept_sort;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String org_id;
+
+        private String name;
+
+        private String pid;
+
+        private String sort;
+
+        private String code;
+
+        private String full_name;
+
+        private String py_first;
+
+        private String py_full;
+
+        private String gid;
+
+        private Long create_time;
+
+    }
+}

+ 48 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptDelete.java

@@ -0,0 +1,48 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class DeptDelete extends AbstractPRApi<DeptDelete.Param, String>{
+
+    public DeptDelete(String orgId,String deptId){
+        super("DeptDelete", "/api/orgs/dept_delete.html", Method.POST, new Param(orgId,deptId));
+    }
+
+    @Override
+    public Class<String> getResultClass(){
+        return String.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(getParam().getOrg_id(),getParam().getDept_id());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true    string 组织ID
+         */
+        private String org_id;
+        /**
+         * true    string 部门ID
+         */
+        private String dept_id;
+    }
+}

+ 74 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptDetail.java

@@ -0,0 +1,74 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractListRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class DeptDetail extends AbstractListRApi<DeptDetail.Param, DeptDetail.Result>{
+
+    public DeptDetail(String orgId, String deptId, String type){
+        super("DeptDetail", "/api/orgs/dept_detail.html", Method.POST, new Param(orgId, deptId, type));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(getParam().getOrg_id());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	组织ID
+         */
+        private String org_id;
+
+        /**
+         * false	string	部门ID -1 表示显示组织下所有的部门
+         */
+        private String dept_id;
+
+        /**
+         * false	string	查询类型 dept:显示节点下部门(默认) user:显示节点下人员 all:显示节点部门及人员
+         */
+        private String type;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String gid;
+
+        private String name;
+
+        private String pid;
+
+        private String code;
+
+        private Long sort;
+
+        private Long user_count;
+
+        private String type;
+    }
+
+}

+ 69 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptSearch.java

@@ -0,0 +1,69 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractListRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class DeptSearch extends AbstractListRApi<DeptSearch.Param, DeptSearch.Result>{
+
+    public DeptSearch(String orgId, String key){
+        super("DeptSearch", "/api/orgs/dept_search.html", Method.POST, new Param(orgId, key));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(getParam().getKey());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * false	string	组织ID
+         */
+        private String org_id;
+
+        /**
+         * true	string	查询类型 关键字
+         */
+        private String key;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+
+        private String gid;
+
+        private String name;
+
+        private String pid;
+
+        private String code;
+
+        private Long sort;
+
+        private Long user_count;
+
+        private String type;
+    }
+}

+ 91 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptSet.java

@@ -0,0 +1,91 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class DeptSet extends AbstractPRApi<DeptSet.Param, DeptSet.Result>{
+
+    public DeptSet(String orgId, String deptId, String deptName, String deptPid, Integer deptSort){
+        super("DeptSet", "/api/orgs/dept_set.html", Method.POST, new Param(orgId, deptId, deptName, deptPid, deptSort));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(getParam().getOrg_id(), getParam().getDept_id(), getParam().getDept_name());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+
+        /**
+         * true	string	组织ID
+         */
+        private String org_id;
+
+        /**
+         * true	string	部门ID
+         */
+        private String dept_id;
+
+        /**
+         * true	string	部门名称
+         */
+        private String dept_name;
+
+        /**
+         * false	string	上级部门ID
+         */
+        private String dept_pid;
+
+        /**
+         * false	integer	排序号
+         */
+        private Integer dept_sort;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String org_id;
+
+        private String name;
+
+        private String pid;
+
+        private String sort;
+
+        private String code;
+
+        private String full_name;
+
+        private String py_first;
+
+        private String py_full;
+
+        private String gid;
+
+        private Long create_time;
+
+    }
+}

+ 65 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptUserCreate.java

@@ -0,0 +1,65 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class DeptUserCreate extends AbstractPRApi<DeptUserCreate.Param, String>{
+
+    public DeptUserCreate(String orgId, String deptId, String userId, String remove, String sort){
+        super("DeptUserCreate", "/api/orgs/dept_user_create.html", Method.POST,
+                new Param(orgId, deptId, userId, remove, sort));
+    }
+
+    @Override
+    public Class<String> getResultClass(){
+        return String.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(getParam().getOrg_id(), getParam().getUser_id());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true string 组织ID
+         */
+        private String org_id;
+
+        /**
+         * false string 部门ID
+         */
+        private String dept_id;
+
+        /**
+         * true string 用户ID 多个用户以逗号分隔,如id1,id2
+         */
+        private String user_id;
+
+        /**
+         * false string 移除原部门 1:移除 0:不移除(默认)
+         */
+        private String remove;
+
+        /**
+         * false string 排序值 从小到大排
+         */
+        private String sort;
+    }
+}

+ 54 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/DeptUserDelete.java

@@ -0,0 +1,54 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class DeptUserDelete extends AbstractPRApi<DeptUserDelete.Param, String>{
+
+    public DeptUserDelete(String orgId, String userId, String deptId){
+        super("DeptUserDelete", "/api/orgs/dept_user_delete.html", Method.POST, new Param(orgId, userId, deptId));
+    }
+
+    @Override
+    public Class<String> getResultClass(){
+        return String.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(getParam().getOrg_id(), getParam().getUser_id());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	组织ID
+         */
+        private String org_id;
+
+        /**
+         * true	string	用户ID 多个用户以逗号分隔,如id1,id2
+         */
+        private String user_id;
+
+        /**
+         * false	string	部门ID
+         */
+        private String dept_id;
+    }
+}

+ 90 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsCreate.java

@@ -0,0 +1,90 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class OrgsCreate extends AbstractPRApi<OrgsCreate.Param, OrgsCreate.Result>{
+
+    public OrgsCreate(String name, String adminName, String adminAccount, String adminPwd){
+        super("OrgsCreate", "/api/orgs/create.html", Method.POST, new Param(name, adminName, adminAccount, adminPwd));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(this.getParam().getName());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	组织名称
+         */
+        private String name;
+
+        /**
+         * false	string	管理员名称
+         */
+        private String admin_name;
+
+        /**
+         * false	string	管理员账号
+         */
+        private String admin_account;
+
+        /**
+         * false	string	管理员密码 明文
+         */
+        private String admin_pwd;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+
+        private String name;
+
+        private String py_first;
+
+        private String py_full;
+
+        private String gid;
+
+        private Long create_time;
+
+        private String create_uid;
+
+        private Admin admin;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    private static class Admin{
+
+        private String name;
+
+        private String account;
+
+    }
+}

+ 56 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsDel.java

@@ -0,0 +1,56 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractListRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class OrgsDel extends AbstractListRApi<OrgsDel.Param, OrgsDel.Result>{
+
+    public OrgsDel(String orgId, String pwd){
+        super("OrgsDel", "/api/orgs/del.html", Method.POST, new Param(orgId, pwd));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(this.getParam().getOrg_id());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	组织ID
+         */
+        private String org_id;
+
+        /**
+         * false	string	管理员密码
+         */
+        private String pwd;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String msg;
+    }
+}

+ 101 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsExportUser.java

@@ -0,0 +1,101 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import java.util.List;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/25
+ */
+public class OrgsExportUser extends AbstractPRApi<OrgsExportUser.Param, OrgsExportUser.Result>{
+    public OrgsExportUser(String orgId, String deptId, String pageSize, String page){
+        super("OrgsExportUser", "/api/orgs/export_user.html", Method.POST, new Param(orgId, deptId, pageSize, page));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return true;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * false	string	组织ID
+         */
+        private String org_id;
+
+        /**
+         * false	string	部门ID
+         */
+        private String dept_id;
+
+        /**
+         * true	string	页数 每页条数
+         */
+        private String page_size;
+
+        /**
+         * true	string	当前页 -1表示不分页
+         */
+        private String page;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private Long       count;
+
+        private List<User> list;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class User{
+        private String  org_id;
+
+        private String  dept_id;
+
+        private String  gid;
+
+        private String  name;
+
+        private String  avatar;
+
+        private String  account;
+
+        private String  mobile;
+
+        private String  email;
+
+        private Integer sex;
+
+        private String  position;
+
+        private String  job_number;
+
+        private String  pwd;
+
+        private Integer pwd_type;
+
+        private Integer status;
+    }
+}

+ 62 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsList.java

@@ -0,0 +1,62 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractListRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class OrgsList extends AbstractListRApi<OrgsList.Param, OrgsList.Result>{
+
+    public OrgsList(String userId){
+        super("OrgsList", "/api/orgs/list.html", Method.POST, new Param(userId));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(this.getParam().getUser_id());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	用户ID
+         */
+        private String user_id;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String gid;
+
+        private String name;
+
+        private Long user_count;
+
+        private Long sort;
+
+        private Long create_time;
+
+        private String type;
+    }
+
+}

+ 75 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsSet.java

@@ -0,0 +1,75 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class OrgsSet extends AbstractPRApi<OrgsSet.Param, OrgsSet.Result>{
+
+    public OrgsSet(String orgId, String name){
+        super("OrgsSet", "/api/orgs/set.html", Method.POST, new Param(orgId, name));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(this.getParam().getOrg_id(), this.getParam().getName());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	组织ID
+         */
+        private String org_id;
+
+        /**
+         * true	string	组织名称
+         */
+        private String name;
+
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String gid;
+
+        private String name;
+
+        private Long user_count;
+
+        private String py_first;
+
+        private String py_full;
+
+        private String intro;
+
+        private Long sort;
+
+        private Long create_time;
+
+        private Long update_time;
+
+        private Long status;
+    }
+}

+ 78 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/orgs/OrgsTree.java

@@ -0,0 +1,78 @@
+package com.minto.app.organization.workpro.api.orgs;
+
+import java.util.List;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractListRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/25
+ */
+public class OrgsTree extends AbstractListRApi<OrgsTree.Param, OrgsTree.Result>{
+
+    public OrgsTree(String orgId, String deptPid, Integer isAll, Integer isUser){
+        super("OrgsTree", "/api/orgs/tree.html", Method.POST, new Param(orgId, deptPid, isAll, isUser));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return true;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+
+        /**
+         * true	string	组织ID 不传,列出用户所有的组织
+         */
+        private String org_id;
+
+        /**
+         * false	string	父部门ID 父部门
+         */
+        private String dept_pid;
+
+        /**
+         * false	integer	是否显示全部 0 逐层 1 全部
+         */
+        private Integer is_all;
+
+        /**
+         * false	integer	是否显示用户 0 不显示人员 1 显示人员
+         */
+        private Integer is_user;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String id;
+
+        private String name;
+
+        private String type;
+
+        private String tid;
+
+        private String tpid;
+
+        private List<Result> children;
+    }
+}

+ 80 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/token/TokenCreate.java

@@ -0,0 +1,80 @@
+package com.minto.app.organization.workpro.api.token;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/17
+ */
+public class TokenCreate extends AbstractPRApi<TokenCreate.Param, TokenCreate.Result>{
+
+    public TokenCreate(String userId, String platform, String flag, String expireMiniute){
+        super("TokenCreate", "/api/token/create.html", Method.POST, new Param(userId, platform, flag, expireMiniute));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(this.getParam().getUser_id(), this.getParam().getPlatform(),
+                this.getParam().getFlag(), this.getParam().getExpire_miniute());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * 用户ID
+         * 必填
+         */
+        private String user_id;
+
+        /**
+         * 平台类型 1 pc 2 mac 3 qt 4 ios 5 android 6 web, 99为临时令牌,[得到令牌]后自动清除
+         * 必填
+         */
+        private String platform;
+
+        /**
+         * 标志 0 普通模式 1 检测用户是否在线
+         * 必填
+         */
+        private String flag;
+
+        /**
+         * 过期分钟 0 系统设置的值
+         * 必填
+         */
+        private String expire_miniute;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String user_id;
+
+        private String platform;
+
+        private String token;
+
+        private Long create_time;
+
+        private Long expire_time;
+    }
+
+}

+ 59 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/token/TokenDelete.java

@@ -0,0 +1,59 @@
+package com.minto.app.organization.workpro.api.token;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class TokenDelete extends AbstractPRApi<TokenDelete.Param, TokenDelete.Result>{
+
+    public TokenDelete(String token){
+        super("TokenDelete", "/api/token/delete.html", Method.POST, new Param(token));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(this.getParam().getToken());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * token true	string	令牌ID
+         */
+        private String token;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private Long create_time;
+
+        private Long expire_time;
+
+        private String platform;
+
+        private String token;
+
+        private String user_id;
+    }
+}

+ 77 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/token/TokenGet.java

@@ -0,0 +1,77 @@
+package com.minto.app.organization.workpro.api.token;
+
+import java.util.List;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class TokenGet extends AbstractPRApi<TokenGet.Param, TokenGet.Result>{
+
+    public TokenGet(String token, List<String> scope, String org_id){
+        super("TokenGet", "/api/token/get.html", Method.POST, new Param(token, scope, org_id));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(this.getParam().getToken()) && CollectionUtils.isNotEmpty(
+                this.getParam().getScope());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	令牌ID
+         */
+        private String token;
+
+        /**
+         * true	string	用户信息范围 ["user","powers","third"],
+         * user 为用户详情信息,
+         * powers 为用户的权限 ,
+         * third 为与第三方系统绑定的帐号信息,空表示没有
+         */
+        private List<String> scope;
+
+        /**
+         * false	string	组织ID 如果空,scope有powers,返回所有组织的权限,否则返回组织的权限
+         */
+        private String org_id;
+
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String user_id;
+
+        private String platform;
+
+        private String token;
+
+        private Long create_time;
+
+        private Long expire_time;
+    }
+}

+ 59 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/token/TokenRefresh.java

@@ -0,0 +1,59 @@
+package com.minto.app.organization.workpro.api.token;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractListRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/18
+ */
+public class TokenRefresh extends AbstractListRApi<TokenRefresh.Param, TokenRefresh.Result>{
+
+    public TokenRefresh(String token){
+        super("TokenRefresh", "/api/token/refresh.html", Method.POST, new Param(token));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(this.getParam().getToken());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * token true	string	令牌ID
+         */
+        private String token;
+    }
+
+    @Data
+    //@NoArgsConstructor
+    //@AllArgsConstructor
+    public static class Result{
+        //        private Long create_time;
+        //
+        //        private Long expire_time;
+        //
+        //        private String platform;
+        //
+        //        private String token;
+        //
+        //        private String user_id;
+    }
+}

+ 155 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersCreate.java

@@ -0,0 +1,155 @@
+package com.minto.app.organization.workpro.api.users;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class UsersCreate extends AbstractPRApi<UsersCreate.Param, UsersCreate.Result>{
+
+    public UsersCreate(String account, String pwd, String userId, String name, Integer pwdType, String avatar,
+            String mobile, String email, String phone, Integer sex, String position, String intro, String userinfo,
+            Integer status, String openidThird){
+        this(new Param(account, pwd, userId, name, pwdType, avatar, mobile, email, phone, sex, position, intro,
+                userinfo, status, openidThird));
+    }
+
+    public UsersCreate(Param param){
+        super("UsersCreate", "/api/users/create.html", Method.POST, param);
+    }
+
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(getParam().getAccount(), getParam().getPwd());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	帐号
+         */
+        private String account;
+
+        /**
+         * true	string	密码
+         */
+        private String pwd;
+
+        /**
+         * false	string	用户ID 不为空时,将使用该字段值为新增用户ID
+         */
+        private String user_id;
+
+        /**
+         * false	string	用户名
+         */
+        private String name;
+
+        /**
+         * false	integer	密码类型 1:md5 2:qd加密 3:sha256(默认) 4:sha1
+         */
+        private Integer pwd_type;
+
+        /**
+         * false	string	头像
+         */
+        private String avatar;
+
+        /**
+         * false	string	手机号
+         */
+        private String mobile;
+
+        /**
+         * false	string	邮箱
+         */
+        private String email;
+
+        /**
+         * false	string	座机
+         */
+        private String phone;
+
+        /**
+         * false	integer	性别 1:男 2:女
+         */
+        private Integer sex;
+
+        /**
+         * false	string	职位
+         */
+        private String position;
+
+        /**
+         * false	string	签名
+         */
+        private String intro;
+
+        /**
+         * false	json	扩展信息
+         */
+        private String userinfo;
+
+        /**
+         * false	integer	状态 状态 0 未激活 1正常 2禁用 3删除
+         */
+        private Integer status;
+
+        /**
+         * false	string	第三方应用ID
+         */
+        private String openid_third;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String gid;
+
+        private String account;
+
+        private String name;
+
+        private String py_first;
+
+        private String avatar;
+
+        private String mobile;
+
+        private String email;
+
+        private String phone;
+
+        private String sex;
+
+        private String position;
+
+        private String intro;
+
+        private String userinfo;
+
+        private String openid_third;
+
+        private Long create_time;
+    }
+}

+ 44 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersDelete.java

@@ -0,0 +1,44 @@
+package com.minto.app.organization.workpro.api.users;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class UsersDelete extends AbstractPRApi<UsersDelete.Param, String>{
+
+    public UsersDelete(String userId){
+        super("UsersDelete", "/api/users/delete.html", Method.POST, new Param(userId));
+    }
+
+    @Override
+    public Class<String> getResultClass(){
+        return String.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(getParam().getUser_id());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	用户ID
+         */
+        private String user_id;
+    }
+}

+ 92 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersGet.java

@@ -0,0 +1,92 @@
+package com.minto.app.organization.workpro.api.users;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class UsersGet extends AbstractPRApi<UsersGet.Param, UsersGet.Result>{
+
+    public UsersGet(String userId, String field, String from){
+        super("UsersGet", "/api/users/get.html", Method.POST, new Param(userId, field, from));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(getParam().getUser_id(), getParam().getField());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	用户ID/account field的值
+         */
+        private String user_id;
+
+        /**
+         * true	string	查询的字段 gid,account
+         */
+        private String field;
+
+        /**
+         * false	string	来源 freind 表示来自好友,显示好友信息
+         */
+        private String from;
+
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String gid;
+
+        private String name;
+
+        private String avatar;
+
+        private String account;
+
+        private String mobile;
+
+        private String email;
+
+        private String intro;
+
+        private String py_first;
+
+        private Long status;
+
+        private String userinfo;
+
+        private String openid_third;
+
+        private Long create_time;
+
+        private Long update_time;
+
+        private Long no_disturbing_style;
+
+        private Long no_disturbing_start;
+
+        private Long no_disturbing_end;
+    }
+}

+ 54 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersGetId.java

@@ -0,0 +1,54 @@
+package com.minto.app.organization.workpro.api.users;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractListRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class UsersGetId extends AbstractListRApi<UsersGetId.Param, UsersGetId.Result>{
+
+    public UsersGetId(String account){
+        super("UsersGetId", "/api/users/get_id.html", Method.POST, new Param(account));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(getParam().getAccount());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	帐号 zs,ls,多个逗号分隔
+         */
+        private String account;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String id;
+
+        private String account;
+    }
+
+}

+ 84 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersGetUsers.java

@@ -0,0 +1,84 @@
+package com.minto.app.organization.workpro.api.users;
+
+import java.util.List;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractListRApi;
+import com.minto.core.util.JsonUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class UsersGetUsers extends AbstractListRApi<UsersGetUsers.Param, UsersGetUsers.Result>{
+
+    public UsersGetUsers(List<String> userIds){
+        super("UsersGetUsers", "/api/users/get_users.html", Method.POST, new Param(JsonUtil.toJSONString(userIds)));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(getParam().getUser_ids());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	json	用户ID集合 ["user_id1","user_id2"]
+         */
+        private String user_ids;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String gid;
+
+        private String name;
+
+        private String avatar;
+
+        private String account;
+
+        private String mobile;
+
+        private String email;
+
+        private String intro;
+
+        private String py_first;
+
+        private Long status;
+
+        private String userinfo;
+
+        private String openid_third;
+
+        private Long create_time;
+
+        private Long update_time;
+
+        private Long no_disturbing_style;
+
+        private Long no_disturbing_start;
+
+        private Long no_disturbing_end;
+    }
+}

+ 94 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersSearch.java

@@ -0,0 +1,94 @@
+package com.minto.app.organization.workpro.api.users;
+
+import java.util.List;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class UsersSearch extends AbstractPRApi<UsersSearch.Param, UsersSearch.Result>{
+
+    public UsersSearch(String key, String orgId){
+        super("UsersSearch", "/api/users/search.html", Method.POST, new Param(key, orgId));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(getParam().getKey());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	搜索关键词 目前支持:用户名|手机号|用户简拼模糊搜索
+         */
+        private String key;
+
+        /**
+         * false	string	组织ID 搜索指定组织下的人员,多企业以逗号分隔,如org_id1,org_id2
+         */
+        private String org_id;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private Long count;
+
+        private Long page;
+
+        private Long page_size;
+
+        private List<Person> list;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    private static class Person{
+        private String gid;
+
+        private String account;
+
+        private String name;
+
+        private String avatar;
+
+        private String mobile;
+
+        private List<Org> orgs;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    private static class Org{
+        private String org_id;
+
+        private String org_name;
+
+        private String dept_id;
+
+        private String dept_name;
+    }
+}

+ 89 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersSearchInner.java

@@ -0,0 +1,89 @@
+package com.minto.app.organization.workpro.api.users;
+
+import java.util.List;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class UsersSearchInner extends AbstractPRApi<UsersSearchInner.Param, UsersSearchInner.Result>{
+
+    public UsersSearchInner(String key){
+        super("UsersSearchInner", "/api/users/search_inner.html", Method.POST, new Param(key));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNotEmpty(getParam().getKey());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	搜索关键词 目前支持:用户名|手机号|用户简拼模糊搜索
+         */
+        private String key;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private Long count;
+
+        private Long page;
+
+        private Long page_size;
+
+        private List<Person> list;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    private static class Person{
+        private String gid;
+
+        private String account;
+
+        private String name;
+
+        private String avatar;
+
+        private String mobile;
+
+        private List<Org> orgs;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    private static class Org{
+        private String org_id;
+
+        private String org_name;
+
+        private String dept_id;
+
+        private String dept_name;
+    }
+}

+ 154 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersSet.java

@@ -0,0 +1,154 @@
+package com.minto.app.organization.workpro.api.users;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractPRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class UsersSet extends AbstractPRApi<UsersSet.Param, UsersSet.Result>{
+
+    public UsersSet(String userId, String account, String name, String pwd, Integer pwdType, String avatar,
+            String mobile, String email, String phone, Integer sex, String position, String intro, Integer status,
+            String userinfo, String openidThird){
+        this(new Param(userId, account, name, pwd, pwdType, avatar, mobile, email, phone, sex, position, intro, status,
+                userinfo, openidThird));
+    }
+
+    public UsersSet(Param param){
+        super("UsersSet", "/api/users/set.html", Method.POST, param);
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(getParam().getUser_id());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	用户ID
+         */
+        private String user_id;
+
+        /**
+         * false	string	帐号
+         */
+        private String account;
+
+        /**
+         * false	string	用户名
+         */
+        private String name;
+
+        /**
+         * false	string	密码
+         */
+        private String pwd;
+
+        /**
+         * false	integer	密码类型 1:md5 3:sha256(默认) 4:sha1
+         */
+        private Integer pwd_type;
+
+        /**
+         * false	string	头像
+         */
+        private String avatar;
+
+        /**
+         * false	string	手机号
+         */
+        private String mobile;
+
+        /**
+         * false	string	邮箱
+         */
+        private String email;
+
+        /**
+         * false	string	座机
+         */
+        private String phone;
+
+        /**
+         * false	integer	性别 1:男 2:女
+         */
+        private Integer sex;
+
+        /**
+         * false	string	职位
+         */
+        private String position;
+
+        /**
+         * false	string	签名
+         */
+        private String intro;
+
+        /**
+         * false	integer	状态 状态 0 未激活 1正常 2禁用 3删除
+         */
+        private Integer status;
+
+        /**
+         * false	json	扩展信息
+         */
+        private String userinfo;
+
+        /**
+         * false	string	第三方应用ID
+         */
+        private String openid_third;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Result{
+        private String gid;
+
+        private String account;
+
+        private String name;
+
+        private String py_first;
+
+        private String avatar;
+
+        private String mobile;
+
+        private String email;
+
+        private String phone;
+
+        private String sex;
+
+        private String position;
+
+        private String intro;
+
+        private String userinfo;
+
+        private String openid_third;
+
+        private Long update_time;
+    }
+}

+ 65 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/api/users/UsersSetPwd.java

@@ -0,0 +1,65 @@
+package com.minto.app.organization.workpro.api.users;
+
+import cn.hutool.http.Method;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.minto.app.organization.workpro.api.AbstractListRApi;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public class UsersSetPwd extends AbstractListRApi<UsersSetPwd.Param, UsersSetPwd.Result>{
+    protected UsersSetPwd(String userId, String oldPwd, String pwd, String pwdType){
+        super("UsersSetPwd", "/api/users/set_pwd.html", Method.POST, new Param(userId, oldPwd, pwd, pwdType));
+    }
+
+    @Override
+    public Class<Result> getResultClass(){
+        return Result.class;
+    }
+
+    @Override
+    public boolean isRequestOk(){
+        return StringUtils.isNoneEmpty(getParam().getUser_id(), getParam().getOld_pwd(), getParam().getPwd());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class Param{
+        /**
+         * true	string	用户ID
+         */
+        private String user_id;
+
+        /**
+         * true	string	原密码
+         */
+        private String old_pwd;
+
+        /**
+         * true	string	新密码
+         */
+        private String pwd;
+
+        /**
+         * false	string	密码加密格式 0 明文 1:md5 2:qd加密 3:sha256 4:sha1
+         */
+        private String pwd_type;
+    }
+
+    @Data
+    //@NoArgsConstructor
+    //@AllArgsConstructor
+    public static class Result{
+
+    }
+}

+ 59 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/config/WorkProConfig.java

@@ -0,0 +1,59 @@
+package com.minto.app.organization.workpro.config;
+
+import com.minto.core.common.SystemProperties;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/17
+ */
+@Data
+public class WorkProConfig{
+    private static WorkProConfig INSTANCE = null;
+
+    private String url;
+
+    private String appid;
+
+    private String appSecret;
+
+    private String userId;
+
+    private String name;
+
+    private String account;
+
+    private String password;
+
+
+    private WorkProConfig(){
+    }
+
+    public static WorkProConfig getInstance(){
+        if(INSTANCE == null){
+            synchronized(WorkProConfig.class){
+                if(INSTANCE == null){
+                    INSTANCE = new WorkProConfig();
+                    SystemProperties instance = SystemProperties.getInstance();
+                    INSTANCE.setUrl(instance.getProperty("workpro.url"));
+                    INSTANCE.setAppid(instance.getProperty("workpro.appid"));
+                    INSTANCE.setAppSecret(instance.getProperty("workpro.appSecret"));
+                    INSTANCE.setUserId(instance.getProperty("workpro.admin.userId"));
+                    INSTANCE.setName(instance.getProperty("workpro.admin.name"));
+                    INSTANCE.setAccount(instance.getProperty("workpro.admin.account"));
+                    INSTANCE.setPassword(instance.getProperty("workpro.admin.password"));
+                }
+            }
+        }
+        return INSTANCE;
+    }
+
+    public boolean isEnable(){
+        return StringUtils.isNoneEmpty(this.url, this.appid, this.appSecret, this.userId, this.account, this.password);
+    }
+
+}

+ 34 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/service/IWorkProService.java

@@ -0,0 +1,34 @@
+package com.minto.app.organization.workpro.service;
+
+import com.minto.app.organization.workpro.api.IWorkProImApi;
+import com.minto.tip.common.exceptions.BusinessException;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+public interface IWorkProService{
+
+
+    public <P, R> void callApi(IWorkProImApi<P, R> api) throws BusinessException;
+
+    public <P, R> void callApi(IWorkProImApi<P, R> api, String uid) throws BusinessException;
+
+    /**
+     * 同步整个系统的组织架构到im服务器中
+     */
+    public void syncSystem(Long accountId);
+
+    /**
+     * 根据用户ID查找Web URL。
+     * 该方法首先检查工作平台配置是否启用,然后通过用户ID查找IM相关信息。
+     * 如果找到相关信息,它将尝试获取用户账户和令牌以构建Web URL。
+     *
+     * @param userId 用户的ID,用于查找IM相关信息。
+     * @return 返回构建的Web URL,如果无法获取必要的信息,则返回null。
+     */
+    public String findWebUrl(Long userId);
+}

+ 417 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/service/impl/WorkProServiceImpl.java

@@ -0,0 +1,417 @@
+package com.minto.app.organization.workpro.service.impl;
+
+import java.text.MessageFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import com.minto.app.organization.beans.OrgImBean;
+import com.minto.app.organization.beans.OrgPersonBean;
+import com.minto.app.organization.beans.OrgUnitBean;
+import com.minto.app.organization.manager.DepartmentManager;
+import com.minto.app.organization.manager.IOrgImMapper;
+import com.minto.app.organization.manager.IOrgManager;
+import com.minto.app.organization.workpro.api.IWorkProImApi;
+import com.minto.app.organization.workpro.api.orgs.*;
+import com.minto.app.organization.workpro.api.token.TokenCreate;
+import com.minto.app.organization.workpro.api.users.UsersCreate;
+import com.minto.app.organization.workpro.api.users.UsersDelete;
+import com.minto.app.organization.workpro.api.users.UsersGet;
+import com.minto.app.organization.workpro.api.users.UsersSet;
+import com.minto.app.organization.workpro.config.WorkProConfig;
+import com.minto.app.organization.workpro.service.IWorkProService;
+import com.minto.core.util.StringUtil;
+import com.minto.tip.common.exceptions.BusinessException;
+import com.minto.tip.organization.po.OrgPrincipal;
+import com.minto.tip.organization.service.PrincipalService;
+import org.apache.commons.collections.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+@Service
+public class WorkProServiceImpl implements IWorkProService{
+
+    private static final Logger log = LoggerFactory.getLogger(WorkProServiceImpl.class);
+
+    @Autowired
+    private IOrgManager orgManager;
+
+    @Autowired
+    private IOrgImMapper orgImMapper;
+
+    @Autowired
+    private PrincipalService principalService;
+
+    @Autowired
+    private DepartmentManager orgDepartmentManager;
+
+    @Override
+    public <P, R> void callApi(IWorkProImApi<P, R> api) throws BusinessException{
+        callApi(api, null);
+    }
+
+    @Override
+    public <P, R> void callApi(IWorkProImApi<P, R> api, String uid) throws BusinessException{
+        WorkProConfig workProConfig = WorkProConfig.getInstance();
+        if(!workProConfig.isEnable()){
+            throw new BusinessException("workPro IM 配置错误!");
+        }
+        if(api == null){
+            throw new BusinessException("workPro IM 请求不能为空!");
+        }
+        if(!api.isRequestOk()){
+            throw new BusinessException("workPro IM 请求构建错误!");
+        }
+        try{
+            api.call(workProConfig, uid);
+        } catch(Exception e){
+            log.error("workPro IM 请求失败!", e);
+        }
+    }
+
+    @Override
+    public void syncSystem(Long accountId){
+        WorkProConfig workProConfig = WorkProConfig.getInstance();
+        if(!workProConfig.isEnable()){
+            throw new BusinessException("workPro IM 配置错误");
+        }
+        OrgUnitBean org = orgManager.findAccountById(accountId);
+        //1、同步组织
+        OrgImBean orgIm = syncOrg(org, workProConfig);
+        //2、同步组织内人员
+        syncPerson(orgIm.getImId(), org);
+        //3、同步部门和部门成员
+        syncDept(org.getId(), orgIm.getImId(), new ArrayList<>());
+    }
+
+    /**
+     * 同步组织信息到IM系统。
+     * 根据给定的组织单元信息和工作平台配置,同步创建或更新IM系统的组织。
+     * 如果IM系统中不存在对应的组织,则创建新组织;如果已存在,则更新组织信息。
+     *
+     * @param org    组织单元信息,包含待同步的组织ID和名称。
+     * @param config 工作平台配置,包含用于IM系统认证的账号信息和密码。
+     * @return 返回同步后的组织信息bean。
+     * @throws BusinessException 如果IM系统操作失败,则抛出业务异常。
+     */
+    private OrgImBean syncOrg(OrgUnitBean org, WorkProConfig config){
+        //不考虑Im系统有组织,而OrgImBean 没有数据的场景
+        OrgImBean byMintoId = orgImMapper.findByMintoId(String.valueOf(org.getId()));
+
+        if(byMintoId == null){
+            // IM系统中不存在该组织,调用API进行组织创建
+            OrgsCreate orgsCreate = new OrgsCreate(org.getName(), config.getName(), config.getAccount(),
+                    config.getPassword());
+            callApi(orgsCreate);
+            // 检查组织创建是否成功
+            if(!orgsCreate.isResponseOk()){
+                throw new BusinessException("workPro IM 创建组织失败!");
+            }
+            // 获取创建后的组织ID,并在本地数据库中创建记录
+            OrgsCreate.Result result = orgsCreate.getResult();
+            String gid = result.getGid();
+            byMintoId = orgImMapper.create(gid, String.valueOf(org.getId()), "org");
+        } else{
+            // IM系统中已存在该组织,调用API进行组织信息更新
+            OrgsSet orgsSet = new OrgsSet(byMintoId.getImId(), org.getName());
+            callApi(orgsSet);
+            // 检查组织信息更新是否成功
+            if(!orgsSet.isResponseOk()){
+                throw new BusinessException("workPro IM 更新组织失败!");
+            }
+        }
+        // 返回同步后的组织信息
+        return byMintoId;
+    }
+
+    /**
+     * 同步组织人员信息到IM系统。
+     *
+     * @param imOrgId IM系统的组织ID。
+     * @param org     企业组织信息。
+     */
+    private void syncPerson(String imOrgId, OrgUnitBean org){
+        // 初始化一个OrgsExportUser对象,用于后续调用API获取所有用户信息
+        //im服务器所有人员
+        OrgsExportUser orgsTree = new OrgsExportUser(null, null, null, "-1");
+        // 调用API获取组织的所有用户信息
+        callApi(orgsTree);
+        // 检查API调用是否成功,如果失败则抛出业务异常
+        if(!orgsTree.isResponseOk()){
+            throw new BusinessException("workPro IM 获取所有人员失败!");
+        }
+        // 获取API返回的用户列表结果
+        OrgsExportUser.Result result = orgsTree.getResult();
+        // 将用户ID列表转换为字符串列表
+        List<String> userIds = result.getList().stream().map(e -> e.getGid()).collect(Collectors.toList());
+        // 从组织管理器中获取当前组织的所有人员信息
+        List<OrgPersonBean> persons = orgManager.findAllPersons(org.getId());
+        // 将人员信息映射为ID到人员对象的映射
+        Map<String, OrgPersonBean> personBeanMap = persons.stream()
+                .collect(Collectors.toMap(e -> String.valueOf(e.getId()), e -> e));
+        // 比较IM系统用户ID列表和组织人员ID列表的差异,得到删除、更新和新增的ID集合
+        List<Set<String>> sets = compareLists(userIds, new ArrayList<>(personBeanMap.keySet()));
+        // 遍历需要删除的用户ID集合,调用API删除用户,并在数据库中更新对应记录
+        sets.get(0).forEach(e -> {
+            UsersDelete usersDelete = new UsersDelete(e);
+            callApi(usersDelete);
+            if(usersDelete.isResponseOk()){
+                orgImMapper.deleteByImId(e);
+            }
+        });
+        // 遍历需要更新的用户ID集合,调用API更新用户信息,并在数据库中更新对应记录
+        sets.get(2).forEach(e -> {
+            OrgPersonBean person = personBeanMap.get(e);
+            OrgPrincipal principal = principalService.getPrincipalByPersonId(person.getId());
+            UsersSet usersSet = new UsersSet(e, principal.getUsername(), person.getPname(), null, null, null, null,
+                    null, null, 1 == person.getSex() ? 1 : 2, null, null, 1, null, null);
+            callApi(usersSet);
+            if(usersSet.isResponseOk()){
+                orgImMapper.updateByMintoId(e, e);
+            }
+        });
+        // 遍历需要新增的用户ID集合,调用API创建用户,并在数据库中新增对应记录
+        sets.get(1).forEach(e -> {
+            OrgPersonBean person = personBeanMap.get(e);
+            OrgPrincipal principal = principalService.getPrincipalByPersonId(person.getId());
+            UsersCreate usersCreate = new UsersCreate(principal.getUsername(), principal.getUsername(), e,
+                    person.getPname(), 3, null, null, null, null, 1 == person.getSex() ? 1 : 2, null, null, null, 1,
+                    null);
+            callApi(usersCreate);
+            if(usersCreate.isResponseOk()){
+                orgImMapper.create(e, e, "person");
+            }
+        });
+    }
+
+    /**
+     * 同步部门信息和人员信息。
+     * 根据给定的部门ID,IM组织ID和IM部门ID列表,同步企业系统中的部门和人员信息到IM系统中。
+     * 这包括创建新部门、更新现有部门、删除已删除的部门,以及同步部门内的人员变动。
+     *
+     * @param deptId    企业系统中的部门ID
+     * @param imOrgId   IM系统中的组织ID
+     * @param imDeptIds IM系统中的部门ID列表
+     */
+    private void syncDept(Long deptId, String imOrgId, List<String> imDeptIds){
+        // 获取IM部门列表中的最后一个部门ID,用于后续处理
+        String imDeptId = CollectionUtils.isEmpty(imDeptIds) ? "" : imDeptIds.get(imDeptIds.size() - 1);
+        // 根据IM组织ID和部门ID列表查询IM系统中的部门和人员信息
+        OrgsTree.Result orgsTree = findImDept(imOrgId, imDeptIds);
+        // 初始化企业系统中的部门和人员列表
+        List<OrgsTree.Result> depts = new ArrayList<>();
+        List<OrgsTree.Result> users = new ArrayList<>();
+        // 如果查询到IM系统的部门信息,进行进一步处理
+        if(orgsTree != null){
+            // 根据类型(部门或人员)对IM系统的部门和人员进行分组
+            Map<String, List<OrgsTree.Result>> collect = orgsTree.getChildren().stream()
+                    .filter(e -> !("d".equals(e.getType()) && "[未分配人员]".equals(e.getName())))
+                    .collect(Collectors.groupingBy(OrgsTree.Result::getType));
+
+            // 将部门和人员信息分别存入对应的列表
+            if(CollectionUtils.isNotEmpty(collect.get("d"))){
+                depts.addAll(collect.get("d"));
+            }
+            if(CollectionUtils.isNotEmpty(collect.get("u"))){
+                users.addAll(collect.get("u"));
+            }
+        }
+        // 从企业系统中查询指定父部门ID的所有子部门
+        List<OrgUnitBean> departments = orgDepartmentManager.findOrgDepartmentBeansByParentId(deptId);
+        // 将企业系统的部门ID映射到部门对象
+        Map<String, OrgUnitBean> deptMaps = departments.stream()
+                .collect(Collectors.toMap(e -> String.valueOf(e.getId()), e -> e));
+        // 获取IM系统中的部门ID列表
+        List<String> imDepIds = depts.stream().map(OrgsTree.Result::getId).collect(Collectors.toList());
+        // 比较企业系统和IM系统中的部门差异,包括新增、更新和删除的部门
+        List<Set<String>> deptDiffSets = compareLists(imDepIds, new ArrayList<>(deptMaps.keySet()));
+        // 处理需要删除的部门
+        deptDiffSets.get(0).forEach(e -> {
+            DeptDelete deptDelete = new DeptDelete(imOrgId, e);
+            callApi(deptDelete);
+            if(deptDelete.isResponseOk()){
+                orgImMapper.deleteByImId(e);
+            }
+        });
+        // 处理需要更新的部门
+        deptDiffSets.get(2).forEach(e -> {
+            OrgUnitBean dept = deptMaps.get(e);
+            DeptSet deptSet = new DeptSet(imOrgId, e, dept.getDname(), imDeptId, null);
+            callApi(deptSet);
+            if(deptSet.isResponseOk()){
+                orgImMapper.updateByMintoId(e, e);
+                List<String> objects = new ArrayList<>(imDeptIds);
+                objects.add(e);
+                syncDept(dept.getId(), imOrgId, objects);
+            }
+        });
+        // 处理需要新增的部门
+        deptDiffSets.get(1).forEach(e -> {
+            OrgUnitBean dept = deptMaps.get(e);
+            DeptCreate deptCreate = new DeptCreate(imOrgId, dept.getDname(), e, imDeptId, null);
+            callApi(deptCreate);
+            if(deptCreate.isResponseOk()){
+                orgImMapper.create(e, e, "dept");
+                List<String> objects = new ArrayList<>(imDeptIds);
+                objects.add(e);
+                syncDept(dept.getId(), imOrgId, objects);
+            }
+        });
+
+        // 如果当前处理的不是最顶层部门,则返回,不处理人员同步
+        if(StringUtil.isEmpty(imDeptId)){
+            return;
+        }
+        // 从企业系统中查询指定部门的所有人员
+        List<OrgPersonBean> deptPersons = orgManager.findPersonsByDepartmentId(deptId);
+        // 将企业系统的人员ID映射到人员对象
+        Map<String, OrgPersonBean> deptPersonMap = deptPersons.stream()
+                .collect(Collectors.toMap(e -> String.valueOf(e.getId()), e -> e));
+        // 获取IM系统中的人员ID列表
+        List<String> imDeptUserIds = users.stream().map(OrgsTree.Result::getId).collect(Collectors.toList());
+        // 比较企业系统和IM系统中的人员差异,包括新增、更新和删除的人员
+        List<Set<String>> userDiffSets = compareLists(imDeptUserIds, new ArrayList<>(deptPersonMap.keySet()));
+        // 处理需要删除的人员
+        if(CollectionUtils.isNotEmpty(userDiffSets.get(0))){
+            String collect1 = userDiffSets.get(0).stream().collect(Collectors.joining(","));
+            DeptUserDelete deptUserDelete = new DeptUserDelete(imOrgId, collect1, imDeptId);
+            callApi(deptUserDelete);
+        }
+        // 处理需要新增的人员
+        if(CollectionUtils.isNotEmpty(userDiffSets.get(1))){
+            String collect1 = userDiffSets.get(1).stream().collect(Collectors.joining(","));
+            DeptUserCreate deptUserCreate = new DeptUserCreate(imOrgId, imDeptId, collect1, null, null);
+            callApi(deptUserCreate);
+        }
+    }
+
+    /**
+     * 根据IM组织ID和IM部门ID列表,查找对应的IM部门在组织树中的位置。
+     *
+     * @param imOrgId   IM的组织ID。
+     * @param imDeptIds IM的部门ID列表。
+     * @return 如果找到对应的部门,返回组织树中的部门节点;如果未找到或请求失败,返回null。
+     */
+    private OrgsTree.Result findImDept(String imOrgId, List<String> imDeptIds){
+        // 初始化组织树对象,指定IM组织ID,以及起始层级和页码
+        OrgsTree orgsTree = new OrgsTree(imOrgId, "", 1, 1);
+        // 调用API获取组织树数据
+        callApi(orgsTree);
+        // 检查API响应是否成功,以及返回的组织树数据是否为空
+        if((!orgsTree.isResponseOk()) || (CollectionUtils.isEmpty(orgsTree.getResult()))){
+            return null;
+        }
+        // 从组织树结果中找出对应IM组织ID的根节点
+        OrgsTree.Result root = orgsTree.getResult().stream().filter(e -> imOrgId.equals(e.getId())).findFirst()
+                .orElse(null);
+        // 如果IM部门ID列表为空,直接返回根节点
+        if(CollectionUtils.isEmpty(imDeptIds)){
+            return root;
+        }
+        // 如果IM部门ID列表不为空,尝试在根节点下查找对应的子部门,如果找不到则返回null
+        return Optional.ofNullable(root).map(rootResult -> findChildDepartment(rootResult, imDeptIds)).orElse(null);
+    }
+
+
+    /**
+     * 根据父部门和部门ID列表,查找子部门。
+     * 该方法通过递归方式在给定的部门树中查找指定ID的子部门。
+     *
+     * @param parent    父部门对象,表示当前查找的起点。
+     * @param imDeptIds 部门ID列表,按层级顺序给出,用于指定需要查找的子部门路径。
+     * @return 返回找到的子部门对象,如果未找到或输入列表为空,则返回父部门对象或null。
+     */
+    private OrgsTree.Result findChildDepartment(OrgsTree.Result parent, List<String> imDeptIds){
+        // 避免对空list进行循环,提高效率
+        if(imDeptIds.isEmpty()){
+            return parent;
+        }
+        // 获取部门ID列表中的第一个ID,作为当前查找的目标。
+        String firstImDeptId = imDeptIds.get(0);
+        //从父部门的子部门中查找匹配第一个ID的部门对象。
+        OrgsTree.Result result = parent.getChildren().stream().filter(e -> e.getId().equals(firstImDeptId)).findFirst()
+                .orElse(null);
+        // 如果未找到匹配的部门对象,返回null,表示无法继续向下查找。
+        if(result == null){
+            return null;
+        }
+        // 准备剩余的部门ID列表,用于下一次递归查找。
+        List<String> remainingDeptIds = imDeptIds.subList(1, imDeptIds.size());
+        // 继续递归查找下一个子部门,直到部门ID列表为空或找到匹配的部门对象。
+        return findChildDepartment(result, remainingDeptIds);
+    }
+
+    /**
+     * 比较两个字符串列表的元素,并返回三个集合:
+     * 仅在列表A中出现的元素、仅在列表B中出现的元素,以及在两个列表中都出现的元素。
+     *
+     * @param listA 第一个字符串列表,不为null。
+     * @param listB 第二个字符串列表,不为null。
+     * @return 一个包含三个集合的列表,分别代表上述三个分类的元素。
+     */
+    private static List<Set<String>> compareLists(List<String> listA, List<String> listB){
+        // 将列表A转换为集合A,去除重复元素。
+        Set<String> setA = new HashSet<>(listA);
+        // 将列表B转换为集合B,去除重复元素。
+        Set<String> setB = new HashSet<>(listB);
+        // 使用流从集合A中筛选出不在集合B中的元素,得到A中独有的元素集合。
+        Set<String> uniqueToA = setA.stream().filter(e -> !setB.contains(e)).collect(Collectors.toSet());
+        // 使用流从集合B中筛选出不在集合A中的元素,得到B中独有的元素集合。
+        Set<String> uniqueToB = setB.stream().filter(e -> !setA.contains(e)).collect(Collectors.toSet());
+        // 初始化一个集合来存储A和B的交集。
+        Set<String> commonElements = new HashSet<>(setA);
+        // 通过保留A和B的交集来计算共同元素。
+        commonElements.retainAll(setB);
+        // 返回包含三个集合的列表。
+        return List.of(uniqueToA, uniqueToB, commonElements);
+    }
+
+    @Override
+    public String findWebUrl(Long userId){
+        // 获取工作平台配置实例
+        WorkProConfig workProConfig = WorkProConfig.getInstance();
+        // 检查工作平台配置是否启用,如果未启用,则记录错误并返回null
+        if(!workProConfig.isEnable()){
+            log.error("workPro IM 配置错误!");
+            return null;
+        }
+        // 根据用户ID查找IM信息
+        OrgImBean byMintoId = orgImMapper.findByMintoId(String.valueOf(userId));
+        // 检查是否找到IM信息或IM ID为空,如果为空,则记录错误并返回null
+        if(byMintoId == null || StringUtil.isEmpty(byMintoId.getImId())){
+            log.error("当前用户没有与IM服务器关联!");
+            return null;
+        }
+        // 创建UsersGet对象,用于获取用户账户信息
+        UsersGet usersGet = new UsersGet(byMintoId.getImId(), "gid", null);
+        // 调用API获取用户账户信息
+        callApi(usersGet, byMintoId.getImId());
+        // 获取用户账户信息,如果响应不OK,则返回null
+        String account = usersGet.isResponseOk() ? usersGet.getResult().getAccount() : null;
+        if(StringUtil.isEmpty(account)){
+            return null;
+        }
+        // 创建TokenCreate对象,用于获取用户令牌
+        TokenCreate tokenCreate = new TokenCreate(byMintoId.getImId(), "1", "0", "120");
+        // 调用API获取用户令牌
+        callApi(tokenCreate, byMintoId.getImId());
+        // 获取用户令牌,如果响应不OK,则返回null
+        String token = tokenCreate.isResponseOk() ? tokenCreate.getResult().getToken() : null;
+        if(StringUtil.isEmpty(token)){
+            return null;
+        }
+        // 定义URL模式,用于构建最终的Web URL
+        String pwdPattern = "{0}/webim/pc/#/chat?account={1}&password={2}";
+        String tokenPattern = "{0}/webim/pc/#/chat/index?account={1}&token={2}";
+        // 根据工作平台配置、用户账户和令牌构建并返回Web URL
+        return MessageFormat.format(tokenPattern, workProConfig.getUrl(), account, token);
+    }
+}

+ 42 - 0
tip-api/src/main/java/com/minto/app/organization/workpro/utils/HttpUtil.java

@@ -0,0 +1,42 @@
+package com.minto.app.organization.workpro.utils;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/17
+ */
+public class HttpUtil{
+    private static RestTemplate rest;
+
+    private HttpUtil(){
+    }
+
+    public static <T> T getSend(String url, Class<T> rclass, Map<String, ?> reqParam){
+        return getRestTemplate().getForObject(url, rclass, reqParam);
+    }
+
+    public static <T> T postSend(String url, Class<T> rclass, Map<String, ?> reqParam, Object reqBody){
+        return getRestTemplate().postForObject(url, reqBody, rclass, reqParam);
+    }
+
+    private static RestTemplate getRestTemplate(){
+        if(rest == null){
+            RestTemplate t = new RestTemplate();
+            MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter =
+                    new MappingJackson2HttpMessageConverter();
+            mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN));
+            t.getMessageConverters().add(mappingJackson2HttpMessageConverter);
+            rest = t;
+        }
+        return rest;
+    }
+}

+ 120 - 0
tip-api/src/main/java/com/minto/app/task/util/TaskImUtil.java

@@ -0,0 +1,120 @@
+package com.minto.app.task.util;
+
+import java.net.InetAddress;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import cn.hutool.core.date.DateUtil;
+import com.minto.app.organization.beans.OrgPersonBean;
+import com.minto.app.organization.manager.IOrgManager;
+import com.minto.app.organization.workpro.api.message.MessageSendMsgFormview;
+import com.minto.app.organization.workpro.service.IWorkProService;
+import com.minto.app.task.beans.TaskSummaryBean;
+import com.minto.tip.common.util.ApplicationContextHolder;
+import org.apache.groovy.util.Maps;
+import org.springframework.core.env.Environment;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/26
+ */
+public final class TaskImUtil{
+    private static final String appId = "taskInfo";
+
+    private static final String appName = "检察工作任务";
+
+    private static String baseUrl;
+
+    private static IWorkProService workProService;
+
+    private static IOrgManager orgManager;
+
+    private static String getBaseUrl(){
+        if(baseUrl == null){
+            Environment env = ApplicationContextHolder.getApplicationContext().getEnvironment();
+            baseUrl = env.getProperty("tc.baseUrl");
+            if(baseUrl == null){
+                try{
+                    baseUrl = MessageFormat.format("http://{0}:{1}{2}", InetAddress.getLocalHost().getHostAddress(),
+                            env.getProperty("server.port", "8080"),
+                            env.getProperty("server.servlet.context-path", "/minto"));
+                } catch(UnknownHostException e){
+
+                }
+            }
+        }
+
+        return baseUrl;
+    }
+
+    private static IWorkProService getWorkProService(){
+        if(workProService == null){
+            workProService = ApplicationContextHolder.getBean(IWorkProService.class);
+        }
+        return workProService;
+    }
+
+    private static IOrgManager getOrgManager(){
+        if(orgManager == null){
+            orgManager = ApplicationContextHolder.getBean(IOrgManager.class);
+        }
+        return orgManager;
+    }
+
+    public static void sendMessage(TaskSummaryBean taskSummary, Date sendTime, String content, Long[] personIds){
+        List<OrgPersonBean> persons = getOrgManager().findPersonsById(List.of(personIds));
+        sendMessage(taskSummary, sendTime, content, persons);
+    }
+
+    public static void sendMessage(TaskSummaryBean taskSummary, Date sendTime, String content,
+            List<OrgPersonBean> persons){
+        for(OrgPersonBean e : persons){
+            sendMessage(taskSummary, sendTime, content, e);
+        }
+    }
+
+    public static void sendMessage(TaskSummaryBean taskSummary, Date sendTime, String content, Long personId){
+        OrgPersonBean person = getOrgManager().findPersonById(personId);
+        sendMessage(taskSummary, sendTime, content, person);
+    }
+
+    public static void sendMessage(TaskSummaryBean taskSummary, Date sendTime, String content, OrgPersonBean person){
+        String url = taskDetailUrl(taskSummary.getId(), person.getId());
+        List<Map<String, String>> recver = List.of(
+                Maps.of("id", String.valueOf(person.getId()), "name", person.getPname()));
+        Map<String, String> refer = Maps.of("id", appId, "name", appName, "avatar",
+                getBaseUrl() + "/org/corp/" + person.getOrgCorporationId() + "/?m=cicon");
+        Map<String, Object> extdata = new HashMap<>();
+        extdata.put("header", List.of(Maps.of("title", "任务通知")));
+        //        extdata.put("header", List.of(Maps.of("title", "任务通知"),
+        //                Maps.of("title", "2016-1-1 12:12:12", "color", "#999999", "size", "s")));
+        extdata.put("body",
+                List.of(Maps.of("title", content), Maps.of("title", DateUtil.format(sendTime, "yyyy-MM-dd HH:mm:ss"))));
+        //        extdata.put("body", List.of(Maps.of("title", content), Maps.of("label", "取件码", "title", "111111"),
+        //                Maps.of("label", "快递公司", "title", "申通快递")));
+        extdata.put("footer", Maps.of("title", "查看详情"));
+        extdata.put("target", Maps.of("url_mobile", url, "url_pc", url, "opentype", "1"));
+        extdata.put("obj", Maps.of("type", "oa", "id", "1111", "s_type", "", "create_uid", ""));
+
+        MessageSendMsgFormview formview = new MessageSendMsgFormview(recver, "3", refer, "2", content, extdata);
+        getWorkProService().callApi(formview);
+    }
+
+    public static String taskDetailUrl(Long taskId, Long userId){
+        String taskUrl = MessageFormat.format("/taskmt/?m=taskDetail&id={0}", String.valueOf(taskId));
+        //String wrapperUrl = MessageFormat.format("{0}/general/wrapper?redirect_uri={1}",getBaseUrl(),
+        //        URLEncoder.encode(taskUrl,StandardCharsets.UTF_8));
+        return MessageFormat.format("{0}/workpro/sso?userId={1}&url={2}", getBaseUrl(), String.valueOf(userId),
+                URLEncoder.encode(taskUrl, StandardCharsets.UTF_8));
+    }
+
+}

+ 2 - 0
tip-front/src/main/java/com/minto/app/organization/controller/OrgCorpController.java

@@ -14,6 +14,7 @@ import javax.servlet.http.HttpServletResponse;
 import com.minto.app.organization.OrgConstants;
 import com.minto.app.organization.manager.CorporationManager;
 import com.minto.app.systemstate.SystemConstants;
+import com.minto.core.util.annotation.NeedlessCheckLogin;
 import org.apache.poi.hssf.usermodel.*;
 import org.apache.poi.ss.usermodel.*;
 import org.hibernate.criterion.Restrictions;
@@ -266,6 +267,7 @@ public class OrgCorpController {
      * @return
      * @throws Exception
      */
+    @NeedlessCheckLogin
     @RequestMapping(value = "/{cid}/", method = RequestMethod.GET, params = { "m=cicon" })
     public ModelAndView corPorationPiconGET(@PathVariable String cid, HttpServletRequest req, HttpServletResponse resp) throws Exception {
         ModelAndView result = null;

+ 126 - 0
tip-front/src/main/java/com/minto/app/organization/workpro/controller/WorkproController.java

@@ -0,0 +1,126 @@
+package com.minto.app.organization.workpro.controller;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.minto.app.organization.workpro.service.IWorkProService;
+import com.minto.core.common.AppContext;
+import com.minto.core.util.ReqUtil;
+import com.minto.core.util.RespUtil;
+import com.minto.core.util.annotation.NeedlessCheckLogin;
+import com.minto.tip.common.exceptions.BusinessException;
+import com.minto.tip.organization.po.OrgPrincipal;
+import com.minto.tip.organization.service.PrincipalService;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/22
+ */
+@Controller
+@RequestMapping("/workpro")
+public class WorkproController{
+    private static final Logger log = LoggerFactory.getLogger(WorkproController.class);
+
+    @Autowired
+    private IWorkProService workProService;
+
+    @Autowired
+    private AuthenticationManager authenticationManager;
+
+    @Autowired
+    private PrincipalService principalService;
+
+    @PostMapping("/sync")
+    public void syncSystem(HttpServletResponse response) throws IOException{
+        Map<String, Object> res = new HashMap<>();
+        try{
+            Long curAccountId = AppContext.currentLoginAccount();
+            workProService.syncSystem(curAccountId);
+            res.put("state", "success");
+        } catch(Exception e){
+            log.error("同步系统组织架构到IM服务器出错!", e);
+            res.put("state", "error");
+        } finally{
+            RespUtil.rendJson(response, res);
+        }
+    }
+
+    @GetMapping("/weburl")
+    public void getWebUrl(HttpServletResponse response) throws IOException{
+        Map<String, Object> res = new HashMap<>();
+        try{
+            Long userId = AppContext.currentUserId();
+            res.put("url", workProService.findWebUrl(userId));
+            res.put("state", "success");
+        } catch(Exception e){
+            log.error("同步系统组织架构到IM服务器出错!", e);
+            res.put("state", "error");
+        } finally{
+            RespUtil.rendJson(response, res);
+        }
+    }
+
+    @GetMapping("/sso")
+    @NeedlessCheckLogin
+    public ModelAndView sso(HttpServletRequest req, HttpServletResponse response) throws IOException{
+        try{
+            Long userId = ReqUtil.getLong(req, "userId");
+            String url = URLDecoder.decode(ReqUtil.getString(req, "url"), StandardCharsets.UTF_8);
+            url = StringUtils.replace(url, "&amp;", "&");
+            if(AppContext.getCurrentUser() == null){
+                AppContext.putThreadContext("workPorIm.SSO", "true");
+                // 创建一个 UsernamePasswordAuthenticationToken 对象
+                OrgPrincipal principal = principalService.getPrincipalByPersonId(userId);
+                if(principal == null){
+                    throw new BusinessException("认证错误!");
+                }
+                UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
+                        principal.getUsername(), null);
+                // 使用 AuthenticationManager 进行认证
+                Authentication authentication = authenticationManager.authenticate(token);
+                // 认证成功后,设置当前 SecurityContext
+                SecurityContextHolder.getContext().setAuthentication(authentication);
+                return new ModelAndView(
+                        "forward:/general/wrapper?redirect_uri=" + URLEncoder.encode(url, StandardCharsets.UTF_8));
+
+            } else if(!userId.equals(AppContext.currentUserId())){
+                // 跳转到退出地址
+                String u = MessageFormat.format("/workpro/sso?userId={0}&url={1}", String.valueOf(userId),
+                        URLEncoder.encode(url, StandardCharsets.UTF_8));
+                return new ModelAndView(
+                        "redirect:/logout?redirect_uri=" + URLEncoder.encode(u, StandardCharsets.UTF_8));
+            } else{
+                return new ModelAndView(
+                        "forward:/general/wrapper?redirect_uri=" + URLEncoder.encode(url, StandardCharsets.UTF_8));
+            }
+        } catch(Exception e){
+            log.error("SSO认证出错!", e);
+        } finally{
+            AppContext.removeThreadContext("workPorIm.SSO");
+        }
+        return null;
+    }
+}

+ 2 - 0
tip-front/src/main/java/com/minto/web/tc/GeneralController.java

@@ -45,6 +45,8 @@ public class GeneralController {
     @GetMapping("/wrapper")
     public String wrapper(@RequestParam(name = "redirect_uri") String url, Model model){
         model.addAttribute("url", url);
+        model.addAttribute("locale", "cn");
+        model.addAttribute("cid", AppContext.currentLoginCorporation());
         return "common/wrapper";
     }
 

+ 15 - 0
tip-service/tip-common/src/main/java/com/minto/app/organization/beans/org_im.hbm.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="gb2312"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
+<hibernate-mapping package="com.minto.app.organization.beans">
+    <class name="OrgImBean" table="org_im">
+        <id column="id" name="id" type="java.lang.Long">
+            <generator class="assigned"/>
+        </id>
+        <property column="im_id" length="64" name="imId" not-null="true" type="java.lang.String"/>
+        <property column="minto_id" length="64" name="mintoId" not-null="true" type="java.lang.String"/>
+        <property column="type" length="64" name="type" not-null="true" type="java.lang.String"/>
+        <property column="create_time" name="createTime" not-null="true" type="java.util.Date"/>
+        <property column="update_time" name="updateTime" not-null="true" type="java.util.Date"/>
+    </class>
+</hibernate-mapping>

+ 20 - 0
tip-service/tip-common/src/main/java/com/minto/app/organization/dao/IOrgImDao.java

@@ -0,0 +1,20 @@
+package com.minto.app.organization.dao;
+
+import java.util.List;
+
+import com.minto.app.organization.beans.OrgImBean;
+import com.minto.core.dao.BaseDao;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/25
+ */
+public interface IOrgImDao extends BaseDao{
+
+    public OrgImBean findByMintoId(String mintoId);
+
+    public List<OrgImBean> findByType(String type);
+}

+ 28 - 0
tip-service/tip-common/src/main/java/com/minto/app/organization/dao/OrgImDaoImpl.java

@@ -0,0 +1,28 @@
+package com.minto.app.organization.dao;
+
+import java.util.List;
+
+import com.minto.app.organization.beans.OrgImBean;
+import com.minto.core.dao.BaseDaoImpl;
+import org.hibernate.criterion.Restrictions;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/25
+ */
+@Repository("orgImDao")
+public class OrgImDaoImpl extends BaseDaoImpl implements IOrgImDao{
+    @Override
+    public OrgImBean findByMintoId(String mintoId){
+       return getHibernateTpl().findOne(OrgImBean.class, Restrictions.eq("mintoId", mintoId), false);
+    }
+
+    @Override
+    public List<OrgImBean> findByType(String type){
+       return getHibernateTpl().query(OrgImBean.class, Restrictions.eq("type", type));
+    }
+}

+ 63 - 0
tip-service/tip-common/src/main/java/com/minto/app/organization/manager/OrgImManagerImpl.java

@@ -0,0 +1,63 @@
+package com.minto.app.organization.manager;
+
+import java.util.Date;
+import java.util.List;
+
+import com.minto.app.organization.beans.OrgImBean;
+import com.minto.app.organization.dao.IOrgImDao;
+import com.minto.core.util.UUIDUtil;
+import org.hibernate.criterion.Restrictions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 应用模块名称<p>
+ * 代码描述<p>
+ *
+ * @author wany
+ * @since 2024/7/25
+ */
+@Service
+public class OrgImManagerImpl implements IOrgImMapper{
+
+    @Autowired
+    private IOrgImDao orgDao;
+
+    @Override
+    public OrgImBean create(String imId, String mintoId, String type){
+        OrgImBean bean = new OrgImBean();
+        bean.setId(UUIDUtil.UUIDAbsLong());
+        bean.setImId(imId);
+        bean.setMintoId(mintoId);
+        bean.setType(type);
+        bean.setCreateTime(new Date());
+        bean.setUpdateTime(bean.getCreateTime());
+        orgDao.save(bean);
+        return findByMintoId(mintoId);
+    }
+
+    @Override
+    public void updateByMintoId(String mintoId, String imId){
+        OrgImBean byMintoId = findByMintoId(mintoId);
+        byMintoId.setImId(imId);
+        byMintoId.setUpdateTime(new Date());
+        orgDao.update(byMintoId);
+    }
+
+    @Override
+    public int deleteByImId(String imId){
+        return orgDao.delete(OrgImBean.class, Restrictions.eq("imId", imId));
+    }
+
+    @Override
+    public OrgImBean findByMintoId(String mintoId){
+        return orgDao.findByMintoId(mintoId);
+    }
+
+
+    @Override
+    public List<OrgImBean> findByType(String type){
+
+        return orgDao.findByType(type);
+    }
+}

+ 6 - 1
tip-service/tip-common/src/main/java/org/springframework/security/authentication/dao/TIPAuthenticationProvider.java

@@ -9,6 +9,7 @@ import com.minto.core.common.AppContext;
 import com.minto.core.security.auth.MintoAuthRealm;
 import com.minto.core.security.exception.AuthExpireException;
 import com.minto.core.security.exception.AuthMaxSizeException;
+import com.minto.core.util.StringUtil;
 import com.minto.tip.common.authenticate.bo.UserAdapter;
 import com.minto.tip.sso.SSOAuthenticationToken;
 import com.minto.core.util.Base64Util;
@@ -63,7 +64,11 @@ public class TIPAuthenticationProvider extends AbstractUserDetailsAuthentication
             } catch (AuthMaxSizeException e) {
                 logger.error("拒绝登录,已拆过最大登录数", e);
             }
-
+            //不想去抄那么多的跳过密码校验的代码逻辑,所以这里写点丑代码
+            String workPorIm = AppContext.removeThreadContext("workPorIm.SSO");
+            if(StringUtil.isNotEmpty(workPorIm)){
+                return;
+            }
             if (authentication.getCredentials() == null) {
                 logger.debug("Authentication failed: no credentials provided");
 

+ 10 - 0
tip-service/tip-common/src/main/java/org/springframework/security/web/authentication/logout/TIPLogoutSuccessHandler.java

@@ -13,11 +13,13 @@ import com.minto.core.util.*;
 import com.minto.tip.common.authenticate.bo.User;
 import com.minto.tip.login.enums.LogoutType;
 import com.minto.tip.login.service.OnlineRecord;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.web.DefaultRedirectStrategy;
 import org.springframework.security.web.RedirectStrategy;
 
+import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -50,6 +52,14 @@ public class TIPLogoutSuccessHandler implements LogoutSuccessHandler {
         if(AjaxUtil.isAjax(request)){
             RespUtil.rendJson(httpServletResponse, R.success());
         }else{
+            String forwardUri = request.getParameter("forward_uri");
+            if(StringUtil.isNotEmpty(forwardUri)){
+                // 获取RequestDispatcher对象
+                RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUri);
+                // 使用forward()方法进行服务器内部转发
+                dispatcher.forward(request, httpServletResponse);
+                return;
+            }
             // 如果附带了跳转参数,就直接跳转地址
             String redirectUri = request.getParameter("redirect_uri");
             if(StringUtil.isNotEmpty(redirectUri)){