diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java index d6f66baf0..61b6c2ab9 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java @@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.google.common.base.Joiner; import com.jeecg.dingtalk.api.core.response.Response; @@ -20,9 +21,11 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.shiro.SecurityUtils; +import org.jeecg.common.api.dto.AiragFlowDTO; import org.jeecg.common.api.dto.DataLogDTO; import org.jeecg.common.api.dto.OnlineAuthDTO; import org.jeecg.common.api.dto.message.*; +import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.UrlMatchEnum; import org.jeecg.common.constant.*; import org.jeecg.common.constant.enums.*; @@ -32,12 +35,13 @@ import org.jeecg.common.system.api.ISysBaseAPI; import org.jeecg.common.system.query.QueryCondition; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.query.QueryRuleEnum; -import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.system.vo.*; import org.jeecg.common.util.*; import org.jeecg.common.util.dynamic.db.FreemarkerParseFactory; import org.jeecg.config.firewall.SqlInjection.IDictTableWhiteListHandler; import org.jeecg.config.mybatis.MybatisPlusSaasConfig; +import org.jeecg.modules.airag.flow.service.IAiragFlowService; +import org.jeecg.modules.airag.flow.vo.api.FlowRunParams; import org.jeecg.modules.message.entity.SysMessageTemplate; import org.jeecg.modules.message.handle.impl.DdSendMsgHandle; import org.jeecg.modules.message.handle.impl.EmailSendMsgHandle; @@ -139,6 +143,9 @@ public class SysBaseApiImpl implements ISysBaseAPI { @Autowired private ISysAnnouncementService sysAnnouncementService; + @Autowired + IAiragFlowService airagFlowService; + @Override //@SensitiveDecode public LoginUser getUserByName(String username) { @@ -441,7 +448,8 @@ public class SysBaseApiImpl implements ISysBaseAPI { message.getContent(), message.getCategory(), message.getBusType(), - message.getBusId()); + message.getBusId(), + message.getNoticeType()); try { // 同步发送第三方APP消息 wechatEnterpriseService.sendMessage(message, true); @@ -521,7 +529,7 @@ public class SysBaseApiImpl implements ISysBaseAPI { try { // 同步企业微信、钉钉的消息通知 dingtalkService.sendActionCardMessage(announcement, mobileOpenUrl, true); - wechatEnterpriseService.sendTextCardMessage(announcement, true); + wechatEnterpriseService.sendTextCardMessage(announcement, mobileOpenUrl, true); } catch (Exception e) { log.error("同步发送第三方APP消息失败!", e); } @@ -574,7 +582,17 @@ public class SysBaseApiImpl implements ISysBaseAPI { if(tmplateParam!=null && oConvertUtils.isNotEmpty(tmplateParam.get(CommonConstant.MSG_HREF_URL))){ mobileOpenUrl = tmplateParam.get(CommonConstant.MSG_HREF_URL); } - + + // 如果传递扩展json,说明是个性化业务,有意见remark则设置为通知内容 + if(oConvertUtils.isJson(announcement.getMsgAbstract())) { + // 获取announcement.getMsgAbstract()的字段remark + JSONObject jsonObject = JSON.parseObject(announcement.getMsgAbstract()); + String remark = jsonObject.containsKey("remark")? jsonObject.getString("remark"): null; + if(oConvertUtils.isNotEmpty(remark)){ + announcement.setMsgContent(remark); + } + } + announcement.setMsgCategory(CommonConstant.MSG_CATEGORY_2); announcement.setDelFlag(String.valueOf(CommonConstant.DEL_FLAG_0)); announcement.setBusId(busId); @@ -609,7 +627,7 @@ public class SysBaseApiImpl implements ISysBaseAPI { // 钉钉的消息通知 dingtalkService.sendActionCardMessage(announcement, mobileOpenUrl, true); // 企业微信通知 - wechatEnterpriseService.sendTextCardMessage(announcement, true); + wechatEnterpriseService.sendTextCardMessage(announcement, mobileOpenUrl, true); } catch (Exception e) { log.error("同步发送第三方APP消息失败!", e); } @@ -763,7 +781,6 @@ public class SysBaseApiImpl implements ISysBaseAPI { return json; } - @Override public List queryAllRole() { List list = new ArrayList(); List roleList = roleMapper.selectList(new QueryWrapper()); @@ -1357,8 +1374,9 @@ public class SysBaseApiImpl implements ISysBaseAPI { * @param setMsgCategory * @param busType * @param busId + * @param noticeType 消息类型,for [JHHB-136]【vue3】协同工作系统消息需要添加一个类型 */ - private void sendBusAnnouncement(String fromUser, String toUser, String title, String msgContent, String setMsgCategory, String busType, String busId) { + private void sendBusAnnouncement(String fromUser, String toUser, String title, String msgContent, String setMsgCategory, String busType, String busId, String noticeType) { SysAnnouncement announcement = new SysAnnouncement(); announcement.setTitile(title); announcement.setMsgContent(msgContent); @@ -1373,7 +1391,12 @@ public class SysBaseApiImpl implements ISysBaseAPI { announcement.setBusType(busType); announcement.setOpenType(SysAnnmentTypeEnum.getByType(busType).getOpenType()); announcement.setOpenPage(SysAnnmentTypeEnum.getByType(busType).getOpenPage()); - announcement.setNoticeType(NoticeTypeEnum.NOTICE_TYPE_FLOW.getValue()); + //update-begin---author:chenrui ---date:20250807 for:[JHHB-136]【vue3】协同工作系统消息需要添加一个类型------------ + if(oConvertUtils.isEmpty(noticeType)){ + noticeType = NoticeTypeEnum.NOTICE_TYPE_FLOW.getValue(); + } + announcement.setNoticeType(noticeType); + //update-end---author:chenrui ---date:20250807 for:[JHHB-136]【vue3】协同工作系统消息需要添加一个类型------------ //update-begin-author:liusq---date:2025-07-01--for: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了 announcement.setIzTop(CommonConstant.IZ_TOP_0); //update-end-author:liusq---date:2025-07-01--for: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了 @@ -1764,8 +1787,23 @@ public class SysBaseApiImpl implements ISysBaseAPI { queryWrapper.lambda().select(SysUserDepart::getUserId).in(true,SysUserDepart::getDepId,deptIds); return sysUserDepartService.listObjs(queryWrapper,e->e.toString()); } - - @Override + + @Override + public List queryUserIdsByCascadeDeptIds(List deptIds) { + Set userIds = new HashSet<>(); + List departs = sysDepartService.list(Wrappers.lambdaQuery(SysDepart.class) + .select(SysDepart::getOrgCode) + .in(SysDepart::getId, deptIds)); + departs.forEach(depart -> { + List sysUsers = sysUserDepartService.queryUserByDepCode(depart.getOrgCode(), null); + if(oConvertUtils.isObjectNotEmpty(sysUsers)){ + userIds.addAll(sysUsers.stream().map(SysUser::getId).collect(Collectors.toSet())); + } + }); + return new ArrayList<>(userIds); + } + + @Override public List queryUserAccountsByDeptIds(List deptIds) { return departMapper.queryUserAccountByDepartIds(deptIds); } @@ -1920,7 +1958,7 @@ public class SysBaseApiImpl implements ISysBaseAPI { try { // 同步企业微信、钉钉的消息通知 Response dtResponse = dingtalkService.sendActionCardMessage(sysAnnouncement, null, true); - wechatEnterpriseService.sendTextCardMessage(sysAnnouncement, true); + wechatEnterpriseService.sendTextCardMessage(sysAnnouncement, null,true); if (dtResponse != null && dtResponse.isSuccess()) { String taskId = dtResponse.getResult(); @@ -1933,4 +1971,129 @@ public class SysBaseApiImpl implements ISysBaseAPI { } } + @Override + public SysDepartModel queryCompByOrgCode(String orgCode) { + AssertUtils.assertNotEmpty("请输入部门编码",orgCode); + SysDepart comp = sysDepartService.queryCompByOrgCode(orgCode); + if(comp == null) { + log.error("未查询到对应的公司信息"); + return null; + } + SysDepartModel respData = new SysDepartModel(); + BeanUtils.copyProperties(comp, respData); + return respData; + } + + /** + * 根据部门编码和层次查询上级公司 + * + * @param orgCode 部门编码 + * @param level 可以传空 默认为1 最小值为1 + * @return + */ + @Override + public SysDepartModel queryCompByOrgCodeAndLevel(String orgCode, Integer level) { + if (null == level || 0 == level) { + level = 1; + } + int codeNum = YouBianCodeUtil.ZHANWEI_LENGTH; + + //先判断父级code + String parendCode = ""; + if (orgCode.length() > codeNum) { + parendCode = orgCode.substring(0, codeNum); + } else { + return null; + } + //根据部门编码查询公司和子公司的数据 + List categoryList = new ArrayList<>(); + categoryList.add(DepartCategoryEnum.DEPART_CATEGORY_COMPANY.getValue()); + categoryList.add(DepartCategoryEnum.DEPART_CATEGORY_SUB_COMPANY.getValue()); + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.like(SysDepart::getOrgCode, parendCode); + query.in(SysDepart::getOrgCategory, categoryList); + query.orderByAsc(SysDepart::getOrgType); + List sysDepartList = sysDepartService.list(query); + if (!CollectionUtils.isEmpty(sysDepartList)) { + //获取上级公司 + SysDepart depart = getParentCompanyByOrgCode(orgCode, sysDepartList, level, 1); + if(depart == null){ + depart = sysDepartList.get(0); + } + SysDepartModel respData = new SysDepartModel(); + BeanUtils.copyProperties(depart, respData); + return respData; + } + return null; + } + + @Override + public Object runAiragFlow(AiragFlowDTO airagFlowDTO) { + if(oConvertUtils.isEmpty(airagFlowDTO.getFlowId())) { + throw new JeecgBootException("流程ID不能为空"); + } + FlowRunParams params = new FlowRunParams(); + params.setFlowId(airagFlowDTO.getFlowId()); + params.setInputParams(airagFlowDTO.getInputParams()); + params.setResponseMode("blocking"); + Result o = (Result)airagFlowService.runFlow(params); + return o.getResult(); + } + + /** + * 根据orgCode找上级 + * + * @param orgCode + * @param sysDepartList + * @param level 指定那第几级 从下往上 + * @param nowLevel + * @return + */ + public SysDepart getParentCompanyByOrgCode(String orgCode,List sysDepartList, int level, int nowLevel) { + //获取上一级公司的编码 + String code = this.getPrefix(orgCode); + if(oConvertUtils.isEmpty(code)) { + return null; + } + List list = sysDepartList.stream().filter(sysDepart -> sysDepart.getOrgCode().equals(code)).toList(); + //判断去上级的级别 + if(!CollectionUtils.isEmpty(list) && nowLevel == level) { + return list.get(0); + } else { + if(!CollectionUtils.isEmpty(list)) { + nowLevel++; + } + return getParentCompanyByOrgCode(code, sysDepartList, level, nowLevel); + } + } + + /** + * 根据指定值获取编码前缀(每级固定YouBianCodeUtil.ZHANWEI_LENGTH位) + * + * @param fullCode 完整编码(如"A01A01A01") + * @return 提取后的前缀编码(如"A01A01") + */ + private String getPrefix(String fullCode) { + if(fullCode.length() < YouBianCodeUtil.ZHANWEI_LENGTH){ + return ""; + } + // 计算总层级数,根据ZHANWEI_LENGTH + int totalLevels = fullCode.length() / YouBianCodeUtil.ZHANWEI_LENGTH; + int keepLevels = totalLevels - 1; + // 计算需要截取的长度(保留层级数 × YouBianCodeUtil.ZHANWEI_LENGTH) + int prefixLength = keepLevels * YouBianCodeUtil.ZHANWEI_LENGTH; + return prefixLength == 0 ? "" : fullCode.substring(0, prefixLength); + } + + /** + * 根据部门code或部门id获取部门名称(当前和上级部门) + * + * @param orgCode 部门编码 + * @param depId 部门id + * @return String 部门名称 + */ + @Override + public String getDepartPathNameByOrgCode(String orgCode, String depId) { + return sysDepartService.getDepartPathNameByOrgCode(orgCode, depId); + } } \ No newline at end of file diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java index a05a52b36..56a7f90b6 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java @@ -1,6 +1,7 @@ package org.jeecg.modules.system.service.impl; import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -846,7 +847,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { * @param verifyConfig 是否验证配置(未启用的APP会拒绝发送) * @return */ - public JSONObject sendTextCardMessage(SysAnnouncement announcement, boolean verifyConfig) { + public JSONObject sendTextCardMessage(SysAnnouncement announcement,String mobileOpenUrl, boolean verifyConfig) { SysThirdAppConfig config = this.getWeChatThirdAppConfig(); if (verifyConfig && null == config) { return null; @@ -882,9 +883,30 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { textCard.setTouser(this.getTouser(usernameString, isToAll)); TextCardEntity entity = new TextCardEntity(); entity.setTitle(announcement.getTitile()); - entity.setDescription(oConvertUtils.getString(announcement.getMsgAbstract(),"空")); - String baseUrl = null; + + //update-begin---author:scott ---date:2025-08-05 for:【QQYUN-13257】【h5】催办、抄送消息,在企业微信中显示json乱码--- + // 判断announcement.getMsgAbstract()值是json格式 + if(oConvertUtils.isJson(announcement.getMsgAbstract()) && oConvertUtils.isNotEmpty(mobileOpenUrl)){ + entity.setDescription(announcement.getMsgContent()); + entity.setUrl(mobileOpenUrl); + }else{ + entity.setDescription(oConvertUtils.getString(announcement.getMsgAbstract(),"空")); + entity.setUrl(geQywxtAnnouncementUrl(announcement)); + } + //update-end---author:scott ---date::2025-08-05 for:【QQYUN-13257】【h5】催办、抄送消息,在企业微信中显示json乱码--- + + textCard.setTextcard(entity); + return JwMessageAPI.sendTextCardMessage(textCard, accessToken); + } + + /** + * 获取企业微信的公告链接 + * + * @return + */ + private String geQywxtAnnouncementUrl(SysAnnouncement announcement){ + String baseUrl = null; //优先通过请求获取basepath,获取不到读取 jeecg.domainUrl.pc try { baseUrl = RestUtil.getBaseUrl(); @@ -893,10 +915,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { baseUrl = jeecgBaseConfig.getDomainUrl().getPc(); //e.printStackTrace(); } - - entity.setUrl(baseUrl + "/sys/annountCement/show/" + announcement.getId()); - textCard.setTextcard(entity); - return JwMessageAPI.sendTextCardMessage(textCard, accessToken); + return baseUrl + "/sys/annountCement/show/" + announcement.getId(); } private String getTouser(String origin, boolean toAll) {