瀏覽代碼

Merge branch 'master' of http://47.110.251.215:3000/java_org/bladex

“zhifk” 2 年之前
父節點
當前提交
9e514893f2
共有 16 個文件被更改,包括 744 次插入467 次删除
  1. 1 1
      blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/OssEndpoint.java
  2. 3 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/CopyContractTreeNodeVO.java
  3. 2 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ArchiveTreeContract.java
  4. 27 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ArchiveTreeContractAutoRuleVO.java
  5. 0 2
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ArchiveTreeContractVO.java
  6. 8 0
      blade-service/blade-archive/pom.xml
  7. 26 78
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  8. 0 49
      blade-service/blade-business/src/main/java/org/springblade/business/controller/MessageWarningController.java
  9. 303 284
      blade-service/blade-business/src/main/java/org/springblade/business/controller/UserOpinionController.java
  10. 48 18
      blade-service/blade-business/src/main/java/org/springblade/business/socket/WebSocket.java
  11. 197 0
      blade-service/blade-business/src/main/java/org/springblade/business/socket/WebSocketManager.java
  12. 16 13
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ArchiveTreeContractController.java
  13. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.java
  14. 2 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IArchiveTreeContractService.java
  15. 100 10
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractServiceImpl.java
  16. 10 10
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsFormElementServiceImpl.java

+ 1 - 1
blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/OssEndpoint.java

@@ -182,7 +182,7 @@ public class OssEndpoint {
 	 */
 	@SneakyThrows
 	@PostMapping("/upload-file")
-	public R<NewBladeFile> uploadFile(@RequestParam MultipartFile file){
+	public synchronized R<NewBladeFile> uploadFile(@RequestParam MultipartFile file){
 		//上传原文件
 		BladeFile bladeFile = ossBuilder.template().putFile(file.getOriginalFilename(), file.getInputStream());
 

+ 3 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/CopyContractTreeNodeVO.java

@@ -27,6 +27,9 @@ public class CopyContractTreeNodeVO {
     @ApiModelProperty("所属方 1=施工 2=监理")
     private Integer tableOwner;
 
+    @ApiModelProperty("所属方,1=施工,2=监理,字符串拼接,复制数据")
+    private String classify;
+
     public void setCopyBatchToPaths(String primaryKeyId, String nodeName){
         this.copyBatchToPaths.add(new CopyBatch(primaryKeyId, nodeName));
     }

+ 2 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ArchiveTreeContract.java

@@ -140,6 +140,8 @@ public class ArchiveTreeContract extends BaseEntity {
 	 * 是否自动立卷规则选择设置的节点 选中的节点设为1 方便页面显示列表
 	 */
 	private Integer archiveAutoSelect;
+
+
 	public ArchiveTreeContract() {
 	}
 

+ 27 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ArchiveTreeContractAutoRuleVO.java

@@ -0,0 +1,27 @@
+package org.springblade.manager.vo;
+
+import lombok.Data;
+import org.springblade.manager.entity.ArchiveTreeContract;
+
+@Data
+public class ArchiveTreeContractAutoRuleVO implements Cloneable {
+
+    private Long nodeId;//节点id
+
+    private String allName; //全路经名
+
+    private Integer selectVo; //页面勾选标志 0未勾选  1勾选
+
+
+    @Override
+    public ArchiveTreeContractAutoRuleVO clone() {
+        try {
+            ArchiveTreeContractAutoRuleVO vo = (ArchiveTreeContractAutoRuleVO) super.clone();
+            return vo;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+    }
+
+
+}

+ 0 - 2
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ArchiveTreeContractVO.java

@@ -142,6 +142,4 @@ public class ArchiveTreeContractVO extends ArchiveTreeContract implements INode<
 	@ApiModelProperty(value = "自动立卷关联Id")
 	private Long archiveAutoNodeId;
 
-	private String allName; //全路经名
-
 }

+ 8 - 0
blade-service/blade-archive/pom.xml

@@ -14,6 +14,14 @@
     <version>${bladex.project.version}</version>
     <packaging>jar</packaging>
 
+    <repositories>
+        <repository>
+            <id>com.e-iceblue</id>
+            <name>e-iceblue</name>
+            <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
+        </repository>
+    </repositories>
+
     <dependencies>
         <dependency>
             <groupId>org.springblade</groupId>

+ 26 - 78
blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java

@@ -29,6 +29,7 @@ import org.springblade.business.vo.*;
 import org.springblade.common.constant.CommonConstant;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
 import org.springblade.core.oss.model.BladeFile;
@@ -351,13 +352,27 @@ public class InformationWriteQueryController extends BladeController {
     @ApiOperationSupport(order = 25)
     @ApiOperation(value = "复制节点填报数据")
     public R<Boolean> copyContractNodeSubmitBusinessData(@RequestBody CopyContractTreeNodeVO copyVO) {
+        if (StringUtils.isNotEmpty(copyVO.getClassify())) {
+            throw new ServiceException("请选择至少一个所属方");
+        }
         if (StringUtils.isNotEmpty(copyVO.getNeedCopyPrimaryKeyId()) && copyVO.getCopyBatchToPaths().size() > 0) {
             //查询被复制节点
             WbsTreeContract wbsTreeContract = this.wbsTreeContractClient.getContractNodeByPrimaryKeyId(copyVO.getNeedCopyPrimaryKeyId());
-            //获取被复制节点的表格
-            List<WbsTreeContract> tableList = this.wbsTreeContractClient.queryChildByParentId(wbsTreeContract, "queryTable", "");
-            if (tableList != null && tableList.size() > 0) {
+            String tabOwner;
+            if (("1,2").equals(copyVO.getClassify()) || ("2,1").equals(copyVO.getClassify())) {
+                tabOwner = "1,2,3,4,5,6";
+            } else {
+                if (("1").equals(copyVO.getClassify())) {
+                    tabOwner = "1,2,3";
+                } else {
+                    tabOwner = "4,5,6";
+                }
+            }
 
+            //获取被复制节点下的表格,根据所属方
+            String sqlContractNode = "select * from m_wbs_tree_contract where parent_id = " + wbsTreeContract.getId() + " and contract_id = " + wbsTreeContract.getContractId() + " and table_owner in(" + tabOwner + ") and is_deleted = 0";
+            List<WbsTreeContract> tableList = jdbcTemplate.query(sqlContractNode, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+            if (tableList.size() > 0) {
                 //获取表格的业务数据
                 Map<String, List<List<Map<String, Object>>>> tableBusinessDataMap = new HashMap<>();
                 for (WbsTreeContract treeContract : tableList) {
@@ -1011,84 +1026,9 @@ public class InformationWriteQueryController extends BladeController {
     public R<Boolean> diySort(@RequestBody DiySortVO vo) {
         //对整棵树进行排序(资料查询需要同步显示排序)采用自增
         List<String> sortLists = vo.getSortList();
-
-        /*String id = sortLists.stream().map(String::valueOf).findAny().orElse(null);
-        WbsTreeContract wbsTreeContract = wbsTreeContractClient.getContractNodeByPrimaryKeyId(id);
-        //当前项目全部填报资料
-        List<InformationQuery> informationQueries = informationQueryService.getBaseMapper().selectList(Wrappers.<InformationQuery>lambdaQuery()
-                .eq(InformationQuery::getProjectId, wbsTreeContract.getProjectId())
-                .eq(InformationQuery::getContractId, wbsTreeContract.getContractId())
-        );
-
-        //获取合同段整棵树
-        List<WbsTreeContract> list = null;
-        if (ObjectUtil.isNotEmpty(wbsTreeContract)) {
-            list = informationQueryService.getContractWbsTreeAll(wbsTreeContract);
-        }
-
-        if (Objects.requireNonNull(list).size() > 0) {
-            //获取根节点
-            List<WbsTreeContract> rootNodes = list.stream().filter(f -> ObjectUtil.isNotEmpty(f.getParentId()) && f.getParentId() == 0).collect(Collectors.toList());
-            List<InformationQuery> infos = new ArrayList<>();
-            int sort = 2;
-            //this.diySortRecursion(list, rootNodes, sort, informationQueries, infos);
-
-            //修改资料查询sort、节点sort
-            for (InformationQuery info : infos) {
-                informationQueryService.updateById(info);
-            }
-            informationQueryService.updateBatchByPKeyId(list);
-
-            //获取排序集合 自定义当前同级排序
-            List<String> sortList = vo.getSortList();
-            if (sortList.size() > 0) {
-                for (int i = 1, l = sortList.size(); i < l; i++) {
-                    try {
-                        WbsTreeContract newData = new WbsTreeContract();
-                        newData.setPKeyId(Long.parseLong(sortList.get(i)));
-                        newData.setSort(i);
-                        //修改排序
-                        this.wbsTreeContractClient.updateContractNodeParameter(newData);
-
-                    } catch (Exception e) {
-                        e.printStackTrace();
-                    }
-                }
-            }
-            */
-
         return R.status(wbsTreeContractClient.diySort(sortLists));
     }
 
-    //递归排序
-    /*private void diySortRecursion(List<WbsTreeContract> list, List<WbsTreeContract> rootNodes, int sort, List<InformationQuery> informationQueries, List<InformationQuery> infos) {
-        if (ObjectUtil.isNotEmpty(rootNodes)) {
-            List<WbsTreeContract> parentNodes = new ArrayList<>();
-            for (WbsTreeContract wbsTreeContract : list) {
-                for (WbsTreeContract rootNode : rootNodes) {
-                    //获取子节点并排序
-                    if (wbsTreeContract.getParentId().equals(rootNode.getId())) {
-                        //资料填报数据排序
-                        InformationQuery informationQuery = informationQueries.stream().filter(f -> f.getWbsId().equals(wbsTreeContract.getPKeyId())).findAny().orElse(null);
-                        if (informationQuery != null) {
-                            informationQuery.setSort(sort);
-                            infos.add(informationQuery);
-                        }
-
-                        wbsTreeContract.setSort(sort++);
-
-                        //重构父级
-                        parentNodes.add(wbsTreeContract);
-                    }
-                }
-            }
-            //递归
-            if (parentNodes.size() > 0) {
-                this.diySortRecursion(list, parentNodes, sort, informationQueries, infos);
-            }
-        }
-    }*/
-
     /**
      * 复制节点
      */
@@ -1260,6 +1200,14 @@ public class InformationWriteQueryController extends BladeController {
                         //初始化PDF路径
                         newData.setPdfUrl(null);
 
+                        //获取当前所有复制的节点的最大sort
+                        String sql = "select sort from m_wbs_tree_contract where contract_id = '" + node.getContractId() + "' and (id = '" + node.getId() + "' or old_id = '" + node.getId() + "')";
+                        List<WbsTreeContract> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+                        List<Integer> collect = query.stream().map(WbsTreeContract::getSort).collect(Collectors.toList());
+                        Integer max = collect.stream().reduce(collect.get(0), Integer::max);
+                        //设置sort
+                        newData.setSort(max);
+
                         //重塑父节点关联关系
                         this.restoreParent(newData, oldToNewIdMap);
 

+ 0 - 49
blade-service/blade-business/src/main/java/org/springblade/business/controller/MessageWarningController.java

@@ -19,7 +19,6 @@ package org.springblade.business.controller;
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -45,14 +44,12 @@ import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.system.entity.DictBiz;
 import org.springblade.system.feign.IDictBizClient;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.RequestParam;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.springblade.business.service.IMessageWarningService;
 import org.springblade.core.boot.ctrl.BladeController;
 
-import javax.websocket.Session;
 import java.io.IOException;
 import java.util.*;
 
@@ -254,50 +251,4 @@ public class MessageWarningController extends BladeController {
         return R.status(false);
     }
 
-
-    /***
-     * 定时重发任务消息WebSocket
-     */
-    @Scheduled(cron = "0 0/5 * * * ?")
-    public void reSendMessage() throws IOException {
-        Map<String, WebSocket> webSocketMap = WebSocket.getWebSocketMap();
-        Map<String, String> webSocketMessageMap = WebSocket.getWebSocketMessageMap();
-
-        if (webSocketMap.isEmpty() || webSocketMessageMap.isEmpty()) {
-            logger.error("定时重发消息WebSocket,reSendMessage()方法未执行,原因:客户端未建立WebSocket链接");
-            return;
-        }
-
-        logger.info("定时重发消息WebSocket,reSendMessage()方法执行成功,入参:webSocketMap->{},webSocketMessageMap->{}", webSocketMap, webSocketMessageMap);
-
-        Set<Map.Entry<String, String>> message = webSocketMessageMap.entrySet();
-
-        List<Map<String, String>> maps = new ArrayList<>();
-
-        for (Map.Entry<String, String> entry : message) {
-            String userId = entry.getKey();
-            String projectAndContractId = entry.getValue();
-            if (projectAndContractId.contains(",") && StringUtils.isNotEmpty(userId)) {
-                //客户端
-                String projectId = projectAndContractId.split(",")[0];
-                String contractId = projectAndContractId.split(",")[1];
-                Map<String, String> stringMap = iTaskService.getTaskCount(projectId, contractId, userId);
-                maps.add(stringMap);
-            } else {
-                //后管
-                Map<String, String> stringMap = iTaskService.getTaskCount(null, null, userId);
-                maps.add(stringMap);
-            }
-        }
-
-        for (Map<String, String> map : maps) {
-            String userId = map.get("userId");
-            webSocketMap.get(userId).sendMessage(JSON.toJSONString(map));
-            logger.info("给用户{}重发消息{}", userId, map);
-        }
-
-        logger.info("定时重发消息WebSocket,reSendMessage()方法执行结束");
-    }
-
-
 }

+ 303 - 284
blade-service/blade-business/src/main/java/org/springblade/business/controller/UserOpinionController.java

@@ -8,6 +8,7 @@ import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import lombok.AllArgsConstructor;
+
 import javax.validation.Valid;
 
 import org.apache.commons.lang.StringUtils;
@@ -17,6 +18,7 @@ import org.springblade.business.entity.UserOpinionGood;
 import org.springblade.business.feign.MessageWarningClient;
 import org.springblade.business.service.*;
 import org.springblade.business.socket.WebSocket;
+import org.springblade.business.socket.WebSocketManager;
 import org.springblade.business.vo.MessageWarningVO;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.mp.support.Condition;
@@ -61,288 +63,305 @@ import java.util.*;
 @Api(value = "用户意见表", tags = "用户意见表接口")
 public class UserOpinionController extends BladeController {
 
-	private final IUserOpinionService userOpinionService;
-
-	private final IUserOpinionFileService userOpinionFileService;
-
-	private final IUserOpinionFlowService userOpinionFlowService;
-
-	private final IDictBizClient dictBizClient;
-
-	private final ProjectAssignmentUserClient projectAssignmentUserClient;
-
-	private final IUserClient userClient;
-
-	private final IUserOpinionGoodService userOpinionGoodService;
-
-	private final MessageWarningClient messageWarningClient;
-
-	private final ContractClient contractClient;
-
-	private final ProjectClient projectClient;
-
-	private final ITaskService iTaskService;
-
-	private final WebSocket webSocket;
-
-	/**
-	 * 取消点赞
-	 * @param userOpinionId 工单ID
-	 * @return 结果
-	 */
-	@PostMapping("/cancelGood")
-	@ApiOperationSupport(order = 6)
-	@ApiOperation(value = "取消点赞")
-	@ApiImplicitParam(name = "userOpinionId", value = "工单ID")
-	public R<Boolean> cancelGood(@RequestParam String userOpinionId){
-		if(StringUtils.isNotEmpty(userOpinionId)){
-			UserOpinion opinion = this.userOpinionService.getById(userOpinionId);
-
-			//删除当前用户对当前工单的点赞信息
-			BladeUser user = AuthUtil.getUser();
-			this.userOpinionGoodService.update(Wrappers.<UserOpinionGood>lambdaUpdate().set(UserOpinionGood::getIsDeleted, 1).eq(UserOpinionGood::getCreateUser, user.getUserId()).eq(UserOpinionGood::getUserOpinionId, userOpinionId));
-
-			//获取原本的点赞数
-			Integer oldGood = opinion.getGoodNumber();
-			return R.data(this.userOpinionService.update(Wrappers.<UserOpinion>lambdaUpdate().set(UserOpinion::getGoodNumber, (oldGood - 1)).eq(UserOpinion::getId, userOpinionId)));
-		}
-		return R.data(-1, false, "数据操作失败");
-	}
-
-	/**
-	 * 获取工单服务相关数据字典
-	 * @return 结果
-	 */
-	@GetMapping("/queryDictBizList")
-	@ApiOperationSupport(order = 5)
-	@ApiOperation(value = "获取字典信息")
-	public R<List<DictBizVO>> queryDictBizList(){
-		//获取字典
-		List<DictBiz> dictList = this.dictBizClient.getList("opinion_type", "").getData();
-		//找到根节点
-		DictBiz root = null;
-		Iterator<DictBiz> iterator = dictList.iterator();
-		while (iterator.hasNext()){
-			DictBiz biz = iterator.next();
-			if(new Long("0").equals(biz.getParentId())){
-				root = biz;
-				iterator.remove();
-				break;
-			}
-		}
-
-		//首先找到父节点为0的
-		List<DictBizVO> result = new ArrayList<>();
-		Iterator<DictBiz> iterator1 = dictList.iterator();
-		while (iterator1.hasNext()){
-			DictBiz biz = iterator1.next();
-			if(root != null && root.getId().equals(biz.getParentId())){
-				DictBizVO vo = new DictBizVO();
-				BeanUtils.copyProperties(biz, vo);
-				result.add(vo);
-				iterator1.remove();
-			} else if(new Long("0").equals(biz.getParentId())){
-				DictBizVO vo = new DictBizVO();
-				BeanUtils.copyProperties(biz, vo);
-				result.add(vo);
-				iterator1.remove();
-			}
-		}
-		//组成相关结构树
-		result.forEach(vo -> {
-			List<DictBizVO> clientList = new ArrayList<>();
-			Iterator<DictBiz> iterator2 = dictList.iterator();
-			while (iterator2.hasNext()){
-				DictBiz biz = iterator2.next();
-				if(biz.getParentId().equals(vo.getId())){
-					//找到子节点
-					DictBizVO voClient = new DictBizVO();
-					BeanUtils.copyProperties(biz, voClient);
-					clientList.add(voClient);
-					iterator2.remove();
-				}
-			}
-			vo.setChildren(clientList);
-		});
-
-		return R.data(result);
-	}
-
-	/**
-	 * 获取当前用户提交的工单服务
-	 */
-	@PostMapping("/queryCurrentUserOpinionList")
-	@ApiOperationSupport(order = 4)
-	@ApiOperation(value = "获取当前用户提交的工单服务")
-	public R<List<UserOpinionVO>> queryCurrentUserOpinionList(){
-		return R.data(this.userOpinionService.queryCurrentUserOpinionList(AuthUtil.getUser()));
-	}
-
-	/**
-	 * 新增点赞
-	 * @param good 点赞数
-	 * @param userOpinionId 点赞的用户工单ID
-	 * @return 新增结果
-	 */
-	@PostMapping("/addGoodNumber")
-	@ApiOperationSupport(order = 3)
-	@ApiOperation(value = "点赞")
-	@ApiImplicitParams(value = {
-			@ApiImplicitParam(name = "good", value = "点赞量", required = true),
-			@ApiImplicitParam(name = "userOpinionId", value = "工单ID", required = true)
-	})
-	public R<Boolean> addGoodNumber(@RequestParam Integer good,@RequestParam String userOpinionId){
-		if(StringUtils.isNotEmpty(userOpinionId)){
-			UserOpinion opinion = this.userOpinionService.getById(userOpinionId);
-			//获取原本的点赞数
-			Integer oldGood = opinion.getGoodNumber();
-			opinion.setGoodNumber(oldGood == null || oldGood < 0 ? good : oldGood + good);
-
-			//获取当前用户信息
-			BladeUser user = AuthUtil.getUser();
-			Long deptId = user.getDeptId().contains(",") ? Long.parseLong(user.getDeptId().split(",")[0]) : Long.parseLong(user.getDeptId());
-			//保存点赞信息
-			this.userOpinionGoodService.save(new UserOpinionGood(opinion.getId(), user.getUserId(), deptId));
-
-			return R.data(this.userOpinionService.updateById(opinion));
-		}
-		return R.data(-1, false, "数据操作失败");
-	}
-
-	/**
-	 * 工单主页列表
-	 * @param query 分页信息
-	 * @return 列表数据
-	 */
-	@GetMapping("/queryUserOpinionPage")
-	@ApiOperationSupport(order = 2)
-	@ApiOperation(value = "获取工单服务列表")
-	public R<IPage<UserOpinionVO>> queryUserOpinionPage(Query query){
-		return R.data(this.userOpinionService.selectUserOpinionPage(Condition.getPage(query), new UserOpinionVO(), AuthUtil.getUser()));
-	}
-
-	/**
-	 * 新增 用户意见表
-	 */
-	@PostMapping("/saveUserOpinion")
-	@ApiOperationSupport(order = 1)
-	@ApiOperation(value = "新增工单服务信息", notes = "传入userOpinion")
-	public R<Boolean> saveUserOpinion(@Valid @RequestBody UserOpinionVO userOpinionVo) {
-		//设置用户信息
-		this.setUserData(userOpinionVo);
-		//生成主表ID
-		long idKey = SnowFlakeUtil.getId();
-		userOpinionVo.setId(idKey);
-
-		//获取附件信息
-		List<String> files = userOpinionVo.getReturnFiles();
-		if(files != null && files.size() != 0){
-			List<UserOpinionFile> saveFileList = new ArrayList<>();
-			//存在附件,执行上传后依次新增记录
-			for(String ossUrl : files){
-				try{
-					//上传附件
-					if(StringUtils.isNotEmpty(ossUrl)){
-						//新增附件信息
-						UserOpinionFile userOpinionFile = new UserOpinionFile();
-						//设置主表ID
-						userOpinionFile.setUserOpinionId(idKey);
-						//设置文件路径
-						userOpinionFile.setFileUrl(ossUrl);
-						saveFileList.add(userOpinionFile);
-					}
-				}catch (Exception e){
-					e.printStackTrace();
-				}
-			}
-			//新增附件信息
-			this.userOpinionFileService.saveBatch(saveFileList);
-		}
-		//获取当前项目合同段下分配的维护人员
-		String manageUserName = "admin", manegeUserPhone = "";
-		Long manageUser = 1123598821738675201L;
-		try{
-			List<SaveUserInfoByProjectDTO> assignmentUserList = this.projectAssignmentUserClient.queryCurrentProjectContractAssignmentUserList(userOpinionVo.getProjectId(), userOpinionVo.getContractId());
-			if(assignmentUserList != null && assignmentUserList.size() > 0){
-				//有分配人员,随机获取某一个人员
-				Random random = new Random();
-				//随机结果集长度下的数量
-				int ran = random.nextInt(assignmentUserList.size());
-				SaveUserInfoByProjectDTO userDto = assignmentUserList.get(ran);
-				User user = this.userClient.userInfoById(Long.parseLong(userDto.getUserId())).getData();
-				if(user != null){
-					manageUser = user.getId();
-					manageUserName = user.getRealName();
-					manegeUserPhone = user.getPhone();
-				}
-			}
-
-			ProjectInfo projectInfo = this.projectClient.queryProjectList(Func.toStrList(userOpinionVo.getProjectId().toString())).get(0);
-			ContractInfo contractInfo = this.contractClient.getContractById(userOpinionVo.getContractId());
-
-			//保存推送记录
-			this.messageWarningClient.savePushUserMessageWarning(new MessageWarningVO(
-					userOpinionVo.getProjectId(),
-					userOpinionVo.getContractId(),
-					4,
-					(StringUtils.isNotEmpty(projectInfo.getProjectAlias()) ? projectInfo.getProjectAlias() : projectInfo.getProjectName()) + contractInfo.getContractName() + "的用户" + AuthUtil.getNickName() + "向您提交的【" + userOpinionVo.getProblemType() + ":" + userOpinionVo.getOpinionContent() + "】工单反馈,请及时处理",
-					manageUser,
-					0
-			));
-
-			//通过WebSocket推送数量条数,推送到对应维护人的工单反馈中
-			if (ObjectUtil.isNotEmpty(userOpinionVo.getProjectId()) && ObjectUtil.isNotEmpty(userOpinionVo.getContractId()) && ObjectUtil.isNotEmpty(manageUser)) {
-				Map<String, String> stringMap = iTaskService.getTaskCount(userOpinionVo.getProjectId().toString(), userOpinionVo.getContractId().toString(), manageUser.toString());
-				try {
-					webSocket.sendMessageByUserId(manageUser.toString(), JSON.toJSONString(stringMap));
-				} catch (IOException e) {
-					e.printStackTrace();
-				}
-			}
-
-		}catch (Exception e){
-			e.printStackTrace();
-		}
-
-		//生成第一次流程
-		List<UserOpinionFlow> saveFlowList = new ArrayList<>();
-		Date nowDate = new Date();
-		//30分钟相应时间
-		String manageTime = DateUtil.format(DateUtil.plusMinutes(nowDate, 30), "yyyy-MM-dd HH:mm:ss");
-		//提交成功环节
-		saveFlowList.add(setUserData(new UserOpinionFlow(idKey, 2, 1, 1, "已提交", "已成功提交您的工单信息", manageTime, manageUser, manageUserName, manegeUserPhone)));
-		//分配维护人员环节
-		saveFlowList.add(setUserData(new UserOpinionFlow(idKey, 1, 1, 2, "已分配专属客服", "客服:" + manageUserName + "<br>电话:" + manegeUserPhone, manageTime, manageUser, manageUserName, manegeUserPhone)));
-		//进入人工预处理环节
-		saveFlowList.add(setUserData(new UserOpinionFlow(idKey, 0, 1, 3, "进入人工预处理环节", null, manageTime, manageUser, manageUserName, manegeUserPhone)));
-		//问题已解决
-		saveFlowList.add(setUserData(new UserOpinionFlow(idKey, 0, 1, 4, "问题已解决", null, manageTime, manageUser, manageUserName, manegeUserPhone)));
-		//新增处理环节
-		this.userOpinionFlowService.saveBatch(saveFlowList);
-		//最后新增主表数据
-		UserOpinion newUserOpinion = new UserOpinion();
-		BeanUtils.copyProperties(userOpinionVo, newUserOpinion);
-		newUserOpinion.setCreateTime(nowDate);
-
-		return R.status(this.userOpinionService.save(newUserOpinion));
-	}
-
-	//设置登录用户信息
-	private UserOpinionFlow setUserData(UserOpinionFlow userOpinionFlow){
-		//获取当前登录人
-		BladeUser user = AuthUtil.getUser();
-		//记录操作人信息
-		userOpinionFlow.setCreateUser(user.getUserId());
-		userOpinionFlow.setCreateDept(user.getDeptId().contains(",") ? Long.parseLong(user.getDeptId().split(",")[0]) : Long.parseLong(user.getDeptId()));
-		return userOpinionFlow;
-	}
-
-	//设置登录用户信息
-	private void setUserData(UserOpinion userOpinion){
-		//获取当前登录人
-		BladeUser user = AuthUtil.getUser();
-		userOpinion.setCreateUser(user.getUserId());
-		userOpinion.setCreateUserName(user.getNickName());
-		userOpinion.setCreateDept(user.getDeptId().contains(",") ? Long.parseLong(user.getDeptId().split(",")[0]) : Long.parseLong(user.getDeptId()));
-	}
+    private final IUserOpinionService userOpinionService;
+
+    private final IUserOpinionFileService userOpinionFileService;
+
+    private final IUserOpinionFlowService userOpinionFlowService;
+
+    private final IDictBizClient dictBizClient;
+
+    private final ProjectAssignmentUserClient projectAssignmentUserClient;
+
+    private final IUserClient userClient;
+
+    private final IUserOpinionGoodService userOpinionGoodService;
+
+    private final MessageWarningClient messageWarningClient;
+
+    private final ContractClient contractClient;
+
+    private final ProjectClient projectClient;
+
+    private final ITaskService iTaskService;
+
+    private final WebSocket webSocket;
+
+    private final WebSocketManager webSocketManager;
+
+    /**
+     * 取消点赞
+     *
+     * @param userOpinionId 工单ID
+     * @return 结果
+     */
+    @PostMapping("/cancelGood")
+    @ApiOperationSupport(order = 6)
+    @ApiOperation(value = "取消点赞")
+    @ApiImplicitParam(name = "userOpinionId", value = "工单ID")
+    public R<Boolean> cancelGood(@RequestParam String userOpinionId) {
+        if (StringUtils.isNotEmpty(userOpinionId)) {
+            UserOpinion opinion = this.userOpinionService.getById(userOpinionId);
+
+            //删除当前用户对当前工单的点赞信息
+            BladeUser user = AuthUtil.getUser();
+            this.userOpinionGoodService.update(Wrappers.<UserOpinionGood>lambdaUpdate().set(UserOpinionGood::getIsDeleted, 1).eq(UserOpinionGood::getCreateUser, user.getUserId()).eq(UserOpinionGood::getUserOpinionId, userOpinionId));
+
+            //获取原本的点赞数
+            Integer oldGood = opinion.getGoodNumber();
+            return R.data(this.userOpinionService.update(Wrappers.<UserOpinion>lambdaUpdate().set(UserOpinion::getGoodNumber, (oldGood - 1)).eq(UserOpinion::getId, userOpinionId)));
+        }
+        return R.data(-1, false, "数据操作失败");
+    }
+
+    /**
+     * 获取工单服务相关数据字典
+     *
+     * @return 结果
+     */
+    @GetMapping("/queryDictBizList")
+    @ApiOperationSupport(order = 5)
+    @ApiOperation(value = "获取字典信息")
+    public R<List<DictBizVO>> queryDictBizList() {
+        //获取字典
+        List<DictBiz> dictList = this.dictBizClient.getList("opinion_type", "").getData();
+        //找到根节点
+        DictBiz root = null;
+        Iterator<DictBiz> iterator = dictList.iterator();
+        while (iterator.hasNext()) {
+            DictBiz biz = iterator.next();
+            if (new Long("0").equals(biz.getParentId())) {
+                root = biz;
+                iterator.remove();
+                break;
+            }
+        }
+
+        //首先找到父节点为0的
+        List<DictBizVO> result = new ArrayList<>();
+        Iterator<DictBiz> iterator1 = dictList.iterator();
+        while (iterator1.hasNext()) {
+            DictBiz biz = iterator1.next();
+            if (root != null && root.getId().equals(biz.getParentId())) {
+                DictBizVO vo = new DictBizVO();
+                BeanUtils.copyProperties(biz, vo);
+                result.add(vo);
+                iterator1.remove();
+            } else if (new Long("0").equals(biz.getParentId())) {
+                DictBizVO vo = new DictBizVO();
+                BeanUtils.copyProperties(biz, vo);
+                result.add(vo);
+                iterator1.remove();
+            }
+        }
+        //组成相关结构树
+        result.forEach(vo -> {
+            List<DictBizVO> clientList = new ArrayList<>();
+            Iterator<DictBiz> iterator2 = dictList.iterator();
+            while (iterator2.hasNext()) {
+                DictBiz biz = iterator2.next();
+                if (biz.getParentId().equals(vo.getId())) {
+                    //找到子节点
+                    DictBizVO voClient = new DictBizVO();
+                    BeanUtils.copyProperties(biz, voClient);
+                    clientList.add(voClient);
+                    iterator2.remove();
+                }
+            }
+            vo.setChildren(clientList);
+        });
+
+        return R.data(result);
+    }
+
+    /**
+     * 获取当前用户提交的工单服务
+     */
+    @PostMapping("/queryCurrentUserOpinionList")
+    @ApiOperationSupport(order = 4)
+    @ApiOperation(value = "获取当前用户提交的工单服务")
+    public R<List<UserOpinionVO>> queryCurrentUserOpinionList() {
+        return R.data(this.userOpinionService.queryCurrentUserOpinionList(AuthUtil.getUser()));
+    }
+
+    /**
+     * 新增点赞
+     *
+     * @param good          点赞数
+     * @param userOpinionId 点赞的用户工单ID
+     * @return 新增结果
+     */
+    @PostMapping("/addGoodNumber")
+    @ApiOperationSupport(order = 3)
+    @ApiOperation(value = "点赞")
+    @ApiImplicitParams(value = {
+            @ApiImplicitParam(name = "good", value = "点赞量", required = true),
+            @ApiImplicitParam(name = "userOpinionId", value = "工单ID", required = true)
+    })
+    public R<Boolean> addGoodNumber(@RequestParam Integer good, @RequestParam String userOpinionId) {
+        if (StringUtils.isNotEmpty(userOpinionId)) {
+            UserOpinion opinion = this.userOpinionService.getById(userOpinionId);
+            //获取原本的点赞数
+            Integer oldGood = opinion.getGoodNumber();
+            opinion.setGoodNumber(oldGood == null || oldGood < 0 ? good : oldGood + good);
+
+            //获取当前用户信息
+            BladeUser user = AuthUtil.getUser();
+            Long deptId = user.getDeptId().contains(",") ? Long.parseLong(user.getDeptId().split(",")[0]) : Long.parseLong(user.getDeptId());
+            //保存点赞信息
+            this.userOpinionGoodService.save(new UserOpinionGood(opinion.getId(), user.getUserId(), deptId));
+
+            return R.data(this.userOpinionService.updateById(opinion));
+        }
+        return R.data(-1, false, "数据操作失败");
+    }
+
+    /**
+     * 工单主页列表
+     *
+     * @param query 分页信息
+     * @return 列表数据
+     */
+    @GetMapping("/queryUserOpinionPage")
+    @ApiOperationSupport(order = 2)
+    @ApiOperation(value = "获取工单服务列表")
+    public R<IPage<UserOpinionVO>> queryUserOpinionPage(Query query) {
+        return R.data(this.userOpinionService.selectUserOpinionPage(Condition.getPage(query), new UserOpinionVO(), AuthUtil.getUser()));
+    }
+
+    /**
+     * 新增 用户意见表
+     */
+    @PostMapping("/saveUserOpinion")
+    @ApiOperationSupport(order = 1)
+    @ApiOperation(value = "新增工单服务信息", notes = "传入userOpinion")
+    public R<Boolean> saveUserOpinion(@Valid @RequestBody UserOpinionVO userOpinionVo) {
+        //设置用户信息
+        this.setUserData(userOpinionVo);
+        //生成主表ID
+        long idKey = SnowFlakeUtil.getId();
+        userOpinionVo.setId(idKey);
+
+        //获取附件信息
+        List<String> files = userOpinionVo.getReturnFiles();
+        if (files != null && files.size() != 0) {
+            List<UserOpinionFile> saveFileList = new ArrayList<>();
+            //存在附件,执行上传后依次新增记录
+            for (String ossUrl : files) {
+                try {
+                    //上传附件
+                    if (StringUtils.isNotEmpty(ossUrl)) {
+                        //新增附件信息
+                        UserOpinionFile userOpinionFile = new UserOpinionFile();
+                        //设置主表ID
+                        userOpinionFile.setUserOpinionId(idKey);
+                        //设置文件路径
+                        userOpinionFile.setFileUrl(ossUrl);
+                        saveFileList.add(userOpinionFile);
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+            //新增附件信息
+            this.userOpinionFileService.saveBatch(saveFileList);
+        }
+        //获取当前项目合同段下分配的维护人员
+        String manageUserName = "admin", manegeUserPhone = "";
+        Long manageUser = 1123598821738675201L;
+        try {
+            List<SaveUserInfoByProjectDTO> assignmentUserList = this.projectAssignmentUserClient.queryCurrentProjectContractAssignmentUserList(userOpinionVo.getProjectId(), userOpinionVo.getContractId());
+            if (assignmentUserList != null && assignmentUserList.size() > 0) {
+                //有分配人员,随机获取某一个人员
+                Random random = new Random();
+                //随机结果集长度下的数量
+                int ran = random.nextInt(assignmentUserList.size());
+                SaveUserInfoByProjectDTO userDto = assignmentUserList.get(ran);
+                User user = this.userClient.userInfoById(Long.parseLong(userDto.getUserId())).getData();
+                if (user != null) {
+                    manageUser = user.getId();
+                    manageUserName = user.getRealName();
+                    manegeUserPhone = user.getPhone();
+                }
+            }
+
+            ProjectInfo projectInfo = this.projectClient.queryProjectList(Func.toStrList(userOpinionVo.getProjectId().toString())).get(0);
+            ContractInfo contractInfo = this.contractClient.getContractById(userOpinionVo.getContractId());
+
+            //保存推送记录
+            this.messageWarningClient.savePushUserMessageWarning(new MessageWarningVO(
+                    userOpinionVo.getProjectId(),
+                    userOpinionVo.getContractId(),
+                    4,
+                    (StringUtils.isNotEmpty(projectInfo.getProjectAlias()) ? projectInfo.getProjectAlias() : projectInfo.getProjectName()) + contractInfo.getContractName() + "的用户" + AuthUtil.getNickName() + "向您提交的【" + userOpinionVo.getProblemType() + ":" + userOpinionVo.getOpinionContent() + "】工单反馈,请及时处理",
+                    manageUser,
+                    0
+            ));
+
+            //通过WebSocket推送数量条数,推送到对应维护人客户端的工单反馈中
+            if (ObjectUtil.isNotEmpty(userOpinionVo.getProjectId()) && ObjectUtil.isNotEmpty(userOpinionVo.getContractId()) && ObjectUtil.isNotEmpty(manageUser)) {
+                Map<String, String> stringMap = iTaskService.getTaskCount(userOpinionVo.getProjectId().toString(), userOpinionVo.getContractId().toString(), manageUser.toString());
+                try {
+                    webSocket.sendMessageByUserId(manageUser.toString(), JSON.toJSONString(stringMap));
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+
+            //通过WebSocket推送数量条数,推送到对应维护人后管的消息区我的消息中
+            if (ObjectUtil.isNotEmpty(manageUser)) {
+                Map<String, String> stringMap = iTaskService.getTaskCount(null, null, manageUser.toString());
+                try {
+                    webSocketManager.sendMessageByUserId(manageUser.toString(), JSON.toJSONString(stringMap));
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        //生成第一次流程
+        List<UserOpinionFlow> saveFlowList = new ArrayList<>();
+        Date nowDate = new Date();
+        //30分钟相应时间
+        String manageTime = DateUtil.format(DateUtil.plusMinutes(nowDate, 30), "yyyy-MM-dd HH:mm:ss");
+        //提交成功环节
+        saveFlowList.add(setUserData(new UserOpinionFlow(idKey, 2, 1, 1, "已提交", "已成功提交您的工单信息", manageTime, manageUser, manageUserName, manegeUserPhone)));
+        //分配维护人员环节
+        saveFlowList.add(setUserData(new UserOpinionFlow(idKey, 1, 1, 2, "已分配专属客服", "客服:" + manageUserName + "<br>电话:" + manegeUserPhone, manageTime, manageUser, manageUserName, manegeUserPhone)));
+        //进入人工预处理环节
+        saveFlowList.add(setUserData(new UserOpinionFlow(idKey, 0, 1, 3, "进入人工预处理环节", null, manageTime, manageUser, manageUserName, manegeUserPhone)));
+        //问题已解决
+        saveFlowList.add(setUserData(new UserOpinionFlow(idKey, 0, 1, 4, "问题已解决", null, manageTime, manageUser, manageUserName, manegeUserPhone)));
+        //新增处理环节
+        this.userOpinionFlowService.saveBatch(saveFlowList);
+        //最后新增主表数据
+        UserOpinion newUserOpinion = new UserOpinion();
+        BeanUtils.copyProperties(userOpinionVo, newUserOpinion);
+        newUserOpinion.setCreateTime(nowDate);
+
+        return R.status(this.userOpinionService.save(newUserOpinion));
+    }
+
+    //设置登录用户信息
+    private UserOpinionFlow setUserData(UserOpinionFlow userOpinionFlow) {
+        //获取当前登录人
+        BladeUser user = AuthUtil.getUser();
+        //记录操作人信息
+        userOpinionFlow.setCreateUser(user.getUserId());
+        userOpinionFlow.setCreateDept(user.getDeptId().contains(",") ? Long.parseLong(user.getDeptId().split(",")[0]) : Long.parseLong(user.getDeptId()));
+        return userOpinionFlow;
+    }
+
+    //设置登录用户信息
+    private void setUserData(UserOpinion userOpinion) {
+        //获取当前登录人
+        BladeUser user = AuthUtil.getUser();
+        userOpinion.setCreateUser(user.getUserId());
+        userOpinion.setCreateUserName(user.getNickName());
+        userOpinion.setCreateDept(user.getDeptId().contains(",") ? Long.parseLong(user.getDeptId().split(",")[0]) : Long.parseLong(user.getDeptId()));
+    }
 }

+ 48 - 18
blade-service/blade-business/src/main/java/org/springblade/business/socket/WebSocket.java

@@ -6,6 +6,8 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.springblade.business.service.ITaskService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 import cn.hutool.core.util.StrUtil;
 import org.springframework.web.bind.annotation.CrossOrigin;
@@ -14,12 +16,16 @@ import javax.websocket.*;
 import javax.websocket.server.PathParam;
 import javax.websocket.server.ServerEndpoint;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 @Component
 @CrossOrigin
 @ServerEndpoint(value = "/websocket/{userId}")
+@Scope("prototype")
 public class WebSocket {
 
     private static ITaskService iTaskService;
@@ -80,25 +86,12 @@ public class WebSocket {
     public void onMessage(String message, Session session) {
         if (StringUtils.isNotEmpty(userId)) {
             webSocketMessageMap.put(userId, message);
-            String projectId = "";
-            String contractId = "";
-            if (message.contains(",")) {
-                logger.info("来自客户端用户:{} 消息:{}", userId, message);
-                projectId = message.split(",")[0];
-                contractId = message.split(",")[1];
-            } else {
-                logger.info("来自后管用户:{} 消息:{}", userId, message);
-                userId = message;
-            }
 
-            Map<String, String> stringMap;
-            if (StringUtils.isNotEmpty(projectId) && StringUtils.isNotEmpty(contractId)) {
-                //客户端
-                stringMap = iTaskService.getTaskCount(projectId, contractId, userId);
-            } else {
-                //后管
-                stringMap = iTaskService.getTaskCount(null, null, userId);
-            }
+            logger.info("来自客户端用户:{} 消息:{}", userId, message);
+            String projectId = message.split(",")[0];
+            String contractId = message.split(",")[1];
+            //客户端
+            Map<String, String> stringMap = iTaskService.getTaskCount(projectId, contractId, userId);
 
             try {
                 webSocketMap.get(userId).sendMessage(JSON.toJSONString(stringMap));
@@ -168,6 +161,43 @@ public class WebSocket {
         WebSocket.onlineCount--;
     }
 
+    /***
+     * 定时重发任务消息WebSocket - 客户端
+     */
+    @Scheduled(cron = "0 0/5 * * * ?")
+    public void reSendMessage() throws IOException {
+        if (webSocketMap.isEmpty() || webSocketMessageMap.isEmpty()) {
+            logger.error("定时重发消息WebSocket,reSendMessage()方法未执行,原因:客户端未建立WebSocket链接");
+            return;
+        }
+
+        logger.info("定时重发消息WebSocket,reSendMessage()方法执行成功,入参:webSocketMap->{},webSocketMessageMap->{}", webSocketMap, webSocketMessageMap);
+
+        Set<Map.Entry<String, String>> message = webSocketMessageMap.entrySet();
+
+        List<Map<String, String>> maps = new ArrayList<>();
+
+        for (Map.Entry<String, String> entry : message) {
+            String userId = entry.getKey();
+            String projectAndContractId = entry.getValue();
+            if (projectAndContractId.contains(",") && StringUtils.isNotEmpty(userId)) {
+                //客户端
+                String projectId = projectAndContractId.split(",")[0];
+                String contractId = projectAndContractId.split(",")[1];
+                Map<String, String> stringMap = iTaskService.getTaskCount(projectId, contractId, userId);
+                maps.add(stringMap);
+            }
+        }
+
+        for (Map<String, String> map : maps) {
+            String userId = map.get("userId");
+            webSocketMap.get(userId).sendMessage(JSON.toJSONString(map));
+            logger.info("给用户{}重发消息{}", userId, map);
+        }
+
+        logger.info("定时重发消息WebSocket,reSendMessage()方法执行结束");
+    }
+
 }
 
 

+ 197 - 0
blade-service/blade-business/src/main/java/org/springblade/business/socket/WebSocketManager.java

@@ -0,0 +1,197 @@
+package org.springblade.business.socket;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import org.apache.commons.lang.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springblade.business.service.ITaskService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.CrossOrigin;
+
+import javax.websocket.*;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpoint;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+@CrossOrigin
+@ServerEndpoint(value = "/websocket/manager/{userId}")
+@Scope("prototype")
+public class WebSocketManager {
+
+    private static ITaskService iTaskService;
+
+    private final static Logger logger = LogManager.getLogger(WebSocketManager.class);
+    private static int onlineCount = 0;
+    private static ConcurrentHashMap<String, WebSocketManager> webSocketMap2 = new ConcurrentHashMap<>();
+    private static ConcurrentHashMap<String, String> webSocketMessageMap2 = new ConcurrentHashMap<>();
+    private Session session;
+    private String userId;
+
+    /**
+     * 注入service
+     */
+    @Autowired
+    public void setApplicationContext(ITaskService iTaskService) {
+        WebSocketManager.iTaskService = iTaskService;
+    }
+
+    public static Map<String, WebSocketManager> getWebSocketMap() {
+        return webSocketMap2;
+    }
+
+    public static Map<String, String> getWebSocketMessageMap() {
+        return webSocketMessageMap2;
+    }
+
+    @OnOpen
+    public void onOpen(Session session, @PathParam("userId") String userId) {
+        this.session = session;
+        this.userId = userId;
+        //加入map
+        webSocketMap2.put(userId, this);
+        addOnlineCount();//在线数加1
+        logger.info("用户:{}连接成功,当前在线人数为{}人", userId, getOnlineCount());
+        try {
+            sendMessage(String.valueOf(this.session.getQueryString()));
+        } catch (IOException e) {
+            logger.error("IO异常");
+        }
+    }
+
+    @OnClose
+    public void onClose() {
+        //从map中删除
+        webSocketMap2.remove(userId);
+        webSocketMessageMap2.remove(userId);
+        subOnlineCount(); //在线数减1
+        logger.info("用户:{}关闭了连接!当前在线人数为{}人", userId, getOnlineCount());
+    }
+
+    /**
+     * 收到后管消息后调用的方法
+     *
+     * @param message 后管发送过来的消息
+     */
+    @OnMessage
+    public void onMessage(String message, Session session) {
+        if (StringUtils.isNotEmpty(userId)) {
+            webSocketMessageMap2.put(userId, message);
+            logger.info("来自后管用户:{} 消息:{}", userId, message);
+            userId = message;
+
+            //后管
+            Map<String, String> stringMap = iTaskService.getTaskCount(null, null, userId);
+
+            try {
+                webSocketMap2.get(userId).sendMessage(JSON.toJSONString(stringMap));
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+
+        } else {
+            logger.info("未获取到用户信息,接收消息失败");
+        }
+    }
+
+    /**
+     * 发生错误时调用
+     */
+    @OnError
+    public void onError(Session session, Throwable error) {
+        logger.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
+        error.printStackTrace();
+    }
+
+    /**
+     * 向客户端发送消息
+     */
+    public void sendMessage(String message) throws IOException {
+        //同步
+        //this.session.getBasicRemote().sendText(message);
+
+        //异步
+        this.session.getAsyncRemote().sendText(message);
+    }
+
+    /**
+     * 通过userId向客户端发送消息
+     */
+    public void sendMessageByUserId(String userId, String message) throws IOException {
+        logger.info("服务端发送消息到{},消息:{}", userId, message);
+        if (StrUtil.isNotBlank(userId) && webSocketMap2.containsKey(userId)) {
+            webSocketMap2.get(userId).sendMessage(message);
+        } else {
+            logger.error("用户{}不在线", userId);
+        }
+    }
+
+    /**
+     * 群发自定义消息
+     */
+    public static void sendInfo(String message) throws IOException {
+        for (String item : webSocketMap2.keySet()) {
+            try {
+                webSocketMap2.get(item).sendMessage(message);
+            } catch (IOException e) {
+                continue;
+            }
+        }
+    }
+
+    public static synchronized int getOnlineCount() {
+        return onlineCount;
+    }
+
+    public static synchronized void addOnlineCount() {
+        WebSocketManager.onlineCount++;
+    }
+
+    public static synchronized void subOnlineCount() {
+        WebSocketManager.onlineCount--;
+    }
+
+    /***
+     * 定时重发任务消息WebSocket - 后管
+     */
+    @Scheduled(cron = "0 0/6 * * * ?")
+    public void reSendMessageManager() throws IOException {
+        if (webSocketMap2.isEmpty() || webSocketMessageMap2.isEmpty()) {
+            logger.error("定时重发消息WebSocket,reSendMessageManager()方法未执行,原因:客户端未建立WebSocket链接");
+            return;
+        }
+
+        logger.info("定时重发消息WebSocket,reSendMessageManager()方法执行成功,入参:webSocketMap->{},webSocketMessageMap->{}", webSocketMap2, webSocketMessageMap2);
+
+        Set<Map.Entry<String, String>> message = webSocketMessageMap2.entrySet();
+
+        List<Map<String, String>> maps = new ArrayList<>();
+
+        for (Map.Entry<String, String> entry : message) {
+            String userId = entry.getKey();
+            //后管
+            Map<String, String> stringMap = iTaskService.getTaskCount(null, null, userId);
+            maps.add(stringMap);
+        }
+
+        for (Map<String, String> map : maps) {
+            String userId = map.get("userId");
+            webSocketMap2.get(userId).sendMessage(JSON.toJSONString(map));
+            logger.info("给用户{}重发消息{}", userId, map);
+        }
+
+        logger.info("定时重发消息WebSocket,reSendMessageManager()方法执行结束");
+    }
+
+}
+
+

+ 16 - 13
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ArchiveTreeContractController.java

@@ -31,6 +31,7 @@ import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.manager.entity.ArchiveTree;
 import org.springblade.manager.service.IArchiveTreeService;
+import org.springblade.manager.vo.ArchiveTreeContractAutoRuleVO;
 import org.springblade.manager.vo.ArchiveTreeContractVO2;
 import org.springblade.manager.vo.ArchiveTreeVO;
 import org.springframework.web.bind.annotation.*;
@@ -139,18 +140,6 @@ public class ArchiveTreeContractController extends BladeController {
 	}
 
 
-	/**
-	 * 初始化归档树根节点
-	 */
-	@PostMapping("/init")
-	@ApiOperationSupport(order = 1)
-	@ApiOperation(value = "初始化项目级归档树", notes = "传入token")
-	public R<ArchiveTree> init() {
-
-
-		return R.fail(200, "初始化创建失败");
-	}
-
 	/**
 	 * 懒加载树形结构
 	 */
@@ -239,7 +228,7 @@ public class ArchiveTreeContractController extends BladeController {
 	@ApiOperationSupport(order = 9)
 	@ApiOperation(value = "修改立卷规则设置", notes = "传入节点id")
 	public R getArchiveAutoRule(@ApiParam(value = "主键", required = true) @RequestParam Long id) {
-		Map<String, List<ArchiveTreeContractVO>> ruleMap=archiveTreeContractService.getArchiveAutoRule(id);
+		Map<Integer, List<ArchiveTreeContractAutoRuleVO>> ruleMap=archiveTreeContractService.getArchiveAutoRule(id);
 		return R.data(ruleMap);
 	}
 
@@ -255,4 +244,18 @@ public class ArchiveTreeContractController extends BladeController {
 	}
 
 
+	/**
+	 * 初始化归档树根节点
+	 */
+	@PostMapping("/initTree")
+	@ApiOperationSupport(order = 10)
+	@ApiOperation(value = "初始化项目级归档树", notes = "传入token")
+	@ApiImplicitParams(value = {
+			@ApiImplicitParam(name = "projectId", value = "项目id", required = true)
+	})
+	public R<ArchiveTree> initTree(Long projectId) {
+		List<ArchiveTree> trees = archiveTreeService.treeList(AuthUtil.getTenantId(), null, null);
+		archiveTreeContractService.initTree(AuthUtil.getTenantId(), projectId,trees);
+		return R.fail(200, "初始化创建成功");
+	}
 }

+ 1 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.java

@@ -62,5 +62,5 @@ public interface ArchiveTreeContractMapper extends BaseMapper<ArchiveTreeContrac
 	 * @param treeContract
 	 * @return
 	 */
-	List<ArchiveTreeContractVO> getAllSonNodeIdsForArchiveAutoRuleSelected(@Param("treeContract")ArchiveTreeContract treeContract);
+	List<ArchiveTreeContract> getAllSonNodeIdsForArchiveAutoRuleSelected(@Param("treeContract")ArchiveTreeContract treeContract);
 }

+ 2 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IArchiveTreeContractService.java

@@ -19,6 +19,7 @@ package org.springblade.manager.service;
 import feign.Param;
 import org.springblade.manager.entity.ArchiveTree;
 import org.springblade.manager.entity.ArchiveTreeContract;
+import org.springblade.manager.vo.ArchiveTreeContractAutoRuleVO;
 import org.springblade.manager.vo.ArchiveTreeContractVO;
 import org.springblade.core.mp.base.BaseService;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -71,7 +72,7 @@ public interface IArchiveTreeContractService extends BaseService<ArchiveTreeCont
 
 
 
-	Map<String, List<ArchiveTreeContractVO>> getArchiveAutoRule(Long id);
+	Map<Integer, List<ArchiveTreeContractAutoRuleVO>> getArchiveAutoRule(Long id);
 
 	/**
 	 *项目级立卷规则更新

+ 100 - 10
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractServiceImpl.java

@@ -24,6 +24,7 @@ import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.node.ForestNodeMerger;
 import org.springblade.manager.entity.ArchiveTree;
 import org.springblade.manager.entity.ArchiveTreeContract;
+import org.springblade.manager.vo.ArchiveTreeContractAutoRuleVO;
 import org.springblade.manager.vo.ArchiveTreeContractVO;
 import org.springblade.manager.mapper.ArchiveTreeContractMapper;
 import org.springblade.manager.service.IArchiveTreeContractService;
@@ -50,13 +51,17 @@ public class ArchiveTreeContractServiceImpl extends BaseServiceImpl<ArchiveTreeC
 	}
 	@Override
 	public boolean initTree(String tenantId, Long projectId, List<ArchiveTree> trees){
+
+		//清理旧的项目归档树,待补充
+		clearProjectTree(tenantId,projectId);
+
+		//建立父子关系,祖先关系
 		List<ArchiveTreeContract> archiveTreeContracts = new ArrayList<>();
 		Map<Long,Long> oldNewMap = new LinkedHashMap<>();
-		Map<Long,Long> idPidMap = new LinkedHashMap<>();
+
 		Map<Long,ArchiveTree> archiveMap = new LinkedHashMap<>();
 
 		for (ArchiveTree archiveTreeVO :trees) {
-			idPidMap.put(archiveTreeVO.getId(),archiveTreeVO.getParentId());
 			oldNewMap.put(archiveTreeVO.getId(), SnowFlakeUtil.getId());
 			archiveMap.put(archiveTreeVO.getId(), archiveTreeVO);
 		}
@@ -93,6 +98,10 @@ public class ArchiveTreeContractServiceImpl extends BaseServiceImpl<ArchiveTreeC
 			archiveTreeContracts.add(archiveTree);
 		}
 
+		//扩展动态节点
+
+		//处理丽娟规则
+
 		this.saveBatch(archiveTreeContracts);
 		return true;
 	}
@@ -176,23 +185,95 @@ public class ArchiveTreeContractServiceImpl extends BaseServiceImpl<ArchiveTreeC
 	 * @return
 	 */
 	@Override
-	public Map<String, List<ArchiveTreeContractVO>> getArchiveAutoRule(Long id) {
-
-		Map<String, List<ArchiveTreeContractVO>> map= new HashMap<>();
-		List<ArchiveTreeContractVO> voList_1_3 = new ArrayList<>();//最高规则和单独组卷的tab显示节点及节点下有设置的节点(archive_auto_select=1)
-		List<ArchiveTreeContractVO> voList_2 = new ArrayList<>();//分类并卷的tab显示当前节点的相同分类节点
+	public Map<Integer, List<ArchiveTreeContractAutoRuleVO>> getArchiveAutoRule(Long id) {
 
+		Map<Integer, List<ArchiveTreeContractAutoRuleVO>> map= new HashMap<>();
+		List<ArchiveTreeContractAutoRuleVO> voList_1 = new ArrayList<>();//最高规则显示节点及节点下有设置的节点(archive_auto_select=1)
+		List<ArchiveTreeContractAutoRuleVO> voList_2 = new ArrayList<>();//分类并卷的tab显示当前节点的相同分类节点
+		List<ArchiveTreeContractAutoRuleVO> voList_3 = new ArrayList<>();//单独组卷的显示节点及节点下有设置的节点(archive_auto_select=1)
 
 		ArchiveTreeContract archiveTreeContract = baseMapper.selectById(id);
 
+		Map<Long,String> nodeNameMap = new HashMap<>();//单个节点名称缓存
+
 		//获取当前节点下所有设置的节点
-		List<ArchiveTreeContractVO> list=baseMapper.getAllSonNodeIdsForArchiveAutoRuleSelected(archiveTreeContract);
-		for(ArchiveTreeContractVO vo:list){
+		List<ArchiveTreeContract> list=baseMapper.getAllSonNodeIdsForArchiveAutoRuleSelected(archiveTreeContract);
+		//找出最高规则和单独规则列表
+		for(ArchiveTreeContract node:list){
+			Integer archiveAutoType = node.getArchiveAutoType();
+			if(archiveAutoType !=null && archiveAutoType!=2){
+				ArchiveTreeContractAutoRuleVO vo = new ArchiveTreeContractAutoRuleVO();
+				vo.setNodeId(node.getId());
+				StringBuffer allName= new StringBuffer();
+				String ancestors = node.getAncestors();
+				String[] ancestorssplit = ancestors.split(",");//全路径ID
+				for(String pId:ancestorssplit){
+					long pIdLong = Long.parseLong(pId);
+					if(nodeNameMap.containsKey(pIdLong)){
+						allName.append(nodeNameMap.get(pIdLong)+"/");
+					}else{
+						ArchiveTreeContract pIdNode = baseMapper.selectById(pIdLong);
+						nodeNameMap.put(pIdNode.getId(),pIdNode.getNodeName());
+						allName.append(pIdNode.getNodeName()+"/");
+					}
+				}
+				allName.append(node.getNodeName());
+				vo.setAllName(allName.toString());
 
-		}
+				if(archiveAutoType==3){
+					vo.setSelectVo(1);
+					voList_3.add(vo);
+
+					ArchiveTreeContractAutoRuleVO vo1 = vo.clone();
+					vo1.setSelectVo(0);
+					voList_1.add(vo1);
+				}
+
+				if(archiveAutoType==1){
+					vo.setSelectVo(0);
+					voList_3.add(vo);
 
+					ArchiveTreeContractAutoRuleVO vo1 = vo.clone();
+					vo1.setSelectVo(1);
+					voList_1.add(vo1);
+				}
 
 
+			}
+		}
+		//找出分类并卷规则 与当前节点同一分类的节点
+		if(archiveTreeContract.getArchiveAutoType()!=null && archiveTreeContract.getArchiveAutoType()==2){
+
+			//设置同一分类的节点 archiveAutoSelect=1的,不是范围内的所有子节点
+			List<ArchiveTreeContract> list2= baseMapper.selectList(Wrappers.<ArchiveTreeContract>lambdaQuery()
+					.eq(ArchiveTreeContract::getArchiveAutoNodeId, archiveTreeContract.getArchiveAutoNodeId())
+					.eq(ArchiveTreeContract::getArchiveAutoSelect, 1).orderByAsc(ArchiveTreeContract::getSort));
+			for(ArchiveTreeContract node:list2){
+				ArchiveTreeContractAutoRuleVO vo = new ArchiveTreeContractAutoRuleVO();
+				vo.setNodeId(node.getId());
+				StringBuffer allName= new StringBuffer();
+				String ancestors = node.getAncestors();
+				String[] ancestorssplit = ancestors.split(",");//全路径ID
+				for(String pId:ancestorssplit){
+					long pIdLong = Long.parseLong(pId);
+					if(nodeNameMap.containsKey(pIdLong)){
+						allName.append(nodeNameMap.get(pIdLong)+"/");
+					}else{
+						ArchiveTreeContract pIdNode = baseMapper.selectById(pIdLong);
+						nodeNameMap.put(pIdNode.getId(),pIdNode.getNodeName());
+						allName.append(pIdNode.getNodeName()+"/");
+					}
+				}
+				allName.append(node.getNodeName());
+				vo.setAllName(allName.toString());
+				vo.setSelectVo(1);
+				voList_2.add(vo);
+			}
+		}
+
+		map.put(1,voList_1);
+		map.put(2,voList_2);
+		map.put(3,voList_3);
 		return map;
 	}
 
@@ -247,4 +328,13 @@ public class ArchiveTreeContractServiceImpl extends BaseServiceImpl<ArchiveTreeC
 		return false;
 	}
 
+	/**
+	 * 清理旧的项目归档树
+	 * @param tenantId
+	 * @param projectId
+	 */
+	void clearProjectTree(String tenantId, Long projectId){
+
+	}
+
 }

+ 10 - 10
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsFormElementServiceImpl.java

@@ -359,16 +359,16 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean submitBatch(WbsFormElementVO2 wbsFormElementVO2) {
-        if (StringUtils.isEmpty(wbsFormElementVO2.getInitTableName())) {
-            throw new ServiceException("未获取到实体表名称,操作失败");
-        }
-        WbsTree wbsTree = new WbsTree();
-        wbsTree.setInitTableName(wbsFormElementVO2.getInitTableName());
-        Integer integer = baseMapper.showShowTabLike(wbsTree);
-        if (integer != 1) {
-            throw new ServiceException("实体信息表不存在");
-        }
-        WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, wbsFormElementVO2.getProjectId()).eq(WbsTreePrivate::getId, wbsFormElementVO2.getId()));
+//        if (StringUtils.isEmpty(wbsFormElementVO2.getInitTableName())) {
+//            throw new ServiceException("未获取到实体表名称,操作失败");
+//        }
+//        WbsTree wbsTree = new WbsTree();
+//        wbsTree.setInitTableName(wbsFormElementVO2.getInitTableName());
+//        Integer integer = baseMapper.showShowTabLike(wbsTree);
+//        if (integer != 1) {
+//            throw new ServiceException("实体信息表不存在");
+//        }
+        WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, wbsFormElementVO2.getProjectId()).eq(WbsTreePrivate::getPKeyId, wbsFormElementVO2.getId()));
         if (wbsTreePrivate != null && ObjectUtil.isNotEmpty(wbsTreePrivate.getInitTableId())) {
             //获取当前表所有元素
             List<WbsFormElement> wbsFormElements = baseMapper.selectList(Wrappers.<WbsFormElement>query().lambda()