TestChangeMessageStatePlugin.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. package kd.cosmic.jkjt.msg.feishu;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import kd.bos.bec.api.IEventServicePlugin;
  6. import kd.bos.bec.model.EntityEvent;
  7. import kd.bos.bec.model.JsonEvent;
  8. import kd.bos.bec.model.KDBizEvent;
  9. import kd.bos.dataentity.entity.DynamicObject;
  10. import kd.bos.logging.Log;
  11. import kd.bos.logging.LogFactory;
  12. import kd.bos.orm.query.QCP;
  13. import kd.bos.orm.query.QFilter;
  14. import kd.bos.servicehelper.BusinessDataServiceHelper;
  15. import kd.bos.util.StringUtils;
  16. import kd.bos.workflow.engine.WfUtils;
  17. import kd.cosmic.jkjt.tmc.util.ParamsUtil;
  18. import org.apache.commons.lang.time.DateFormatUtils;
  19. import org.apache.http.HttpResponse;
  20. import org.apache.http.client.methods.HttpPost;
  21. import org.apache.http.entity.StringEntity;
  22. import org.apache.http.impl.client.DefaultHttpClient;
  23. import org.apache.http.message.BasicHeader;
  24. import org.apache.http.util.EntityUtils;
  25. import java.io.UnsupportedEncodingException;
  26. import java.net.URLEncoder;
  27. import java.rmi.ConnectException;
  28. import java.util.Arrays;
  29. import java.util.Date;
  30. import java.util.List;
  31. /**
  32. * @author wanghaiwu_kd
  33. * @date 2024/04/22
  34. * 插件说明:业务事件中心插件,修改飞书待办状态,测试类
  35. * 表单标识:消息阅读状态变更事件.执行插件(wf.AfterChangeMessageStateEvent.executePlugin)
  36. */
  37. public class TestChangeMessageStatePlugin implements IEventServicePlugin {
  38. private static Log logger = LogFactory.getLog(TestChangeMessageStatePlugin.class);
  39. private static final String USER_FORM_ID = "bos_user";
  40. private static final String USERNAME = "username";
  41. private List<Integer> interErrCodeArr = Arrays.asList(new Integer[]{
  42. 65001,90203,90235,90242,91201,95001,95003,95005,95010,95011,
  43. 95203,95204,95205,95206,95207,95208,95209,
  44. 105001,190003,230020,1050002,1050008,1069301,1069399
  45. });
  46. public static final String createInstanceUrl = "https://www.feishu.cn/approval/openapi/v2/external/instance/create";
  47. private static final String TRAGETNAME = "云苍穹移动审批";
  48. private static final String SPDYNUMBER = "jxjkxh";//审批定义number
  49. private static final String SPDYID = "946F4A46-2D64-4EBF-9C83-5CDBC5FEB9BD";//审批定义id-测试
  50. private static final String APP_ID = "cli_a6f0c94f273ed00b";//个人测试
  51. private static final String APP_SERCRET = "WmQUMiDFFSjN60kKnsayvdaEd0wvqidh";
  52. @Override
  53. public Object handleEvent(KDBizEvent evt) {
  54. logger.info("飞书消息阅读状态变更事件" + evt.toString());
  55. if (evt instanceof EntityEvent) {//苍穹事件
  56. EntityEvent entityEvent = (EntityEvent) evt;//类型转换
  57. String businesskey = entityEvent.getBusinesskeys().get(0);
  58. String entityNumber = entityEvent.getEntityNumber();
  59. DynamicObject obj = BusinessDataServiceHelper.loadSingle(businesskey, entityNumber);
  60. Long evtID = evt.getEventId();
  61. String source = evt.getSource();//传递的事件参数
  62. } else {//自定义事件
  63. JsonEvent jsonEvent = (JsonEvent) evt;//类型转换
  64. String source = jsonEvent.getSource();//传递的事件参数
  65. if (WfUtils.isNotEmpty(source)) {
  66. JSONArray arr = (JSONArray) JSON.parse(source);
  67. for (int i = 0; i < arr.size(); i++) {
  68. if(arr.getJSONObject(i) == null) {
  69. continue;
  70. }
  71. //消息id
  72. String msgIds = arr.getJSONObject(i).getString("msgIds");
  73. logger.info("飞书消息阅读状态变更事件:msgIds" + msgIds);
  74. //用户id
  75. String userId = arr.getJSONObject(i).getString("userId");
  76. if(StringUtils.isEmpty(msgIds)){
  77. continue;
  78. }
  79. updateFeiShuMsgState(userId, msgIds);
  80. }
  81. }
  82. }
  83. return null;
  84. }
  85. private void updateFeiShuMsgState(String userId, String msgIds){
  86. QFilter qFilter = new QFilter("id", QCP.equals, Long.valueOf(userId));
  87. //接收人员
  88. DynamicObject user = BusinessDataServiceHelper.loadSingle("bos_user", qFilter.toArray());
  89. String personNo = user.getString("number");
  90. msgIds = msgIds.replace("[", "").replace("]", "");
  91. String[] msgIdList = msgIds.split(",");
  92. if(msgIdList.length == 0){
  93. return;
  94. }
  95. for(String msgId : msgIdList){
  96. logger.info("飞书消息阅读状态变更事件:替换前 msgId:" + msgId);
  97. msgId = msgId.replace("\"", "");
  98. logger.info("飞书消息阅读状态变更事件:替换后msgId:" + msgId);
  99. qFilter = new QFilter("channel", QCP.equals, "feishu");
  100. qFilter.and(new QFilter("messageid", QCP.equals, Long.valueOf(msgId)));
  101. DynamicObject msgFail = BusinessDataServiceHelper.loadSingle("wf_msg_failmessage", qFilter.toArray());
  102. if(msgFail == null){
  103. continue;
  104. }
  105. qFilter = new QFilter("id", QCP.equals, Long.valueOf(msgId));
  106. DynamicObject msg = BusinessDataServiceHelper.loadSingle("wf_msg_message", qFilter.toArray());
  107. if(msg == null || StringUtils.isEmpty(msg.getString("contenturl"))){
  108. continue;
  109. }
  110. Long channelMsgId = msgFail.getLong("id");
  111. String tplscene = msgFail.getString("tplscene");
  112. logger.info("飞书消息阅读状态变更事件:tplscene:" + tplscene);
  113. if("circulation".equals(tplscene)){
  114. String token = getToken();
  115. sendFlowMessage(channelMsgId.toString(), msg, user, token);
  116. }
  117. }
  118. }
  119. public void sendFlowMessage(String channelMsgId, DynamicObject message, DynamicObject userInfo, String token){
  120. try {
  121. JSONObject m = new JSONObject(true);
  122. JSONObject c = new JSONObject(true);
  123. c.put("approval_code", SPDYID);
  124. c.put("instance_id","cq"+ channelMsgId);
  125. c.put("status", "HIDDEN");
  126. //url连接
  127. JSONObject links = new JSONObject();
  128. String pcUrl = StringUtils.isEmpty(message.getString("contenturl")) ? "" : message.getString("contenturl");
  129. String mobUrl = StringUtils.isEmpty(message.getString("mobcontenturl")) ? pcUrl : message.getString("mobcontenturl");
  130. logger.info("消息pcurl:" + pcUrl + ", moburl:" + mobUrl);
  131. //移动端需要走外网,将地址替换成外网地址
  132. String curUrl = ParamsUtil.getCommonParamsField("nckd_url");
  133. String mobileUrl = ParamsUtil.getCommonParamsField("nckd_mobileurl");
  134. if(StringUtils.isNotEmpty(pcUrl)){
  135. pcUrl = pcUrl.replace(mobileUrl, curUrl);
  136. }
  137. if(StringUtils.isNotEmpty(mobUrl)){
  138. mobUrl = mobUrl.replace(curUrl, mobileUrl);
  139. }
  140. if("".equals(pcUrl)||pcUrl==null){
  141. pcUrl = System.getProperty("domain.contextUrl")+"/index.html?formId=wf_msg_center";
  142. }
  143. links.put("pc_link",pcSrcToFeishu(changeDanDianSrc(pcUrl+"&apptype=feishu")));
  144. links.put("mobile_link", changeDanDianSrc(mobUrl+"&apptype=feishu"));
  145. c.put("links", links);
  146. String content = message.getString("content");
  147. String title = message.getString("title");
  148. //标题
  149. c.put("title", title);
  150. Long createTime = (new Date()).getTime();
  151. c.put("start_time", createTime);
  152. c.put("update_time", createTime);
  153. c.put("update_mode", "UPDATE");
  154. /*************处理消息格式*****************/
  155. // String nodename = toDoInfo.getCategory();
  156. String workflowname = "财务系统审批流";
  157. String nodename = "";
  158. String createDate = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  159. if(message != null && StringUtils.isNotEmpty(message.getString("config"))){
  160. JSONObject messateContext = JSONObject.parseObject(message.getString("config")).getJSONObject("messageContext");
  161. Long taskId = messateContext.getLong("taskId");
  162. /*************处理消息格式*****************/
  163. DynamicObject taskInfo = BusinessDataServiceHelper.loadSingleFromCache(taskId ,"wf_task");
  164. //add by wnaghaiwu_kd 2024/04/28
  165. //如果任务中找不到,就找历史任务
  166. if(taskInfo == null){
  167. taskInfo = BusinessDataServiceHelper.loadSingleFromCache(taskId ,"wf_hitaskinst");
  168. }
  169. if(taskInfo != null){
  170. QFilter qFilter;
  171. nodename = taskInfo.getString("name");
  172. if(taskInfo.getLong("processdefinitionid") > 0) {
  173. qFilter = new QFilter("id", QCP.equals, taskInfo.getLong("processdefinitionid"));
  174. DynamicObject processdef = BusinessDataServiceHelper.loadSingle("wf_processdefinition", qFilter.toArray());
  175. if (processdef != null) {
  176. workflowname = processdef.getString("name");
  177. }
  178. }
  179. if("财务系统审批流".equals(workflowname) && taskInfo.getString("entityname") != null){
  180. workflowname = taskInfo.getString("entityname") + "审批流程";
  181. }
  182. if(StringUtils.isNotEmpty(taskInfo.getString("entitynumber"))
  183. && StringUtils.isNotEmpty(taskInfo.getString("businesskey"))){
  184. qFilter = new QFilter("id", QCP.equals, Long.valueOf(taskInfo.getString("businesskey")));
  185. DynamicObject bill = BusinessDataServiceHelper.loadSingle(taskInfo.getString("entitynumber"), qFilter.toArray());
  186. if(bill != null){
  187. if(bill.getDynamicObjectType().getProperties().contains("createtime")) {
  188. createDate = DateFormatUtils.format(bill.getDate("createtime"), "yyyy-MM-dd HH:mm:ss");
  189. } else if(bill.getDynamicObjectType().getProperties().contains("createdate")) {
  190. createDate = DateFormatUtils.format(bill.getDate("createdate"), "yyyy-MM-dd HH:mm:ss");
  191. }
  192. }
  193. }
  194. }
  195. }
  196. c.put("title", workflowname);
  197. JSONArray formArr = new JSONArray();
  198. JSONObject form1 = new JSONObject();
  199. form1.put("name", "流程标题");
  200. form1.put("value", StringUtils.isEmpty(message.getString("title")) ? workflowname : message.getString("title"));
  201. formArr.add(form1);
  202. JSONObject form2 = new JSONObject();
  203. form2.put("name", "提单时间");
  204. form2.put("value", createDate);
  205. formArr.add(form2);
  206. JSONObject form3 = new JSONObject();
  207. form3.put("name", "当前节点");
  208. form3.put("value", nodename);
  209. formArr.add(form3);
  210. c.put("form", formArr);
  211. /*************处理消息格式*****************/
  212. //cc_list 抄送人相关
  213. JSONArray ccArr = new JSONArray();
  214. JSONObject cc = new JSONObject();
  215. cc.put("cc_id", userInfo.getPkValue()+"_"+ channelMsgId);
  216. cc.put("open_id", getUserId(userInfo.getString("phone"),token));
  217. cc.put("read_status", "READ");
  218. cc.put("title", title);
  219. cc.put("create_time", createTime);
  220. cc.put("update_time", createTime);
  221. cc.put("title", workflowname);
  222. JSONObject links1 = new JSONObject();
  223. links1.put("pc_link",pcSrcToFeishu(changeDanDianSrc(pcUrl+"&apptype=feishu")));
  224. links1.put("mobile_link",changeDanDianSrc(mobUrl+"&apptype=feishu"));
  225. cc.put("links", links1);
  226. ccArr.add(cc);
  227. c.put("cc_list", ccArr);
  228. m.put("content", c);
  229. logger.info("财务系统飞书推送传阅状态更新:"+m.toJSONString());
  230. String response = doPostByHttpClient(createInstanceUrl, m.toJSONString(), true,token);
  231. logger.info("财务系统飞书推送传阅状态更新:"+response);
  232. } catch (ConnectException e) {
  233. logger.info("财务系统飞书,推送失败");
  234. logger.error(e.getMessage(), e);
  235. e.printStackTrace();
  236. }
  237. }
  238. //pc链接特殊处理
  239. public String pcSrcToFeishu(String src){
  240. String dandianStr="";
  241. if(dandianStr != null) {
  242. try {
  243. String encodesrc = URLEncoder.encode(src, "utf-8");
  244. dandianStr = "https://applink.feishu.cn/client/web_url/open?mode=window&url=" + encodesrc;
  245. } catch (UnsupportedEncodingException e) {
  246. logger.info(e.getMessage());
  247. e.printStackTrace();
  248. }
  249. }
  250. return dandianStr;
  251. }
  252. public static String changeDanDianSrc(String src){
  253. String dandianStr="";
  254. if(src != null) {
  255. try {
  256. String encodesrc = URLEncoder.encode(src, "utf-8");
  257. dandianStr = "https://open.feishu.cn/open-apis/authen/v1/index?redirect_uri=" + encodesrc + "&app_id=" + APP_ID;
  258. } catch (UnsupportedEncodingException e) {
  259. logger.info(e.getMessage());
  260. e.printStackTrace();
  261. }
  262. }
  263. return dandianStr;
  264. }
  265. /**
  266. * 获取飞书token
  267. * @return
  268. */
  269. public static String getToken(){
  270. String returnstr = "";
  271. String url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";
  272. JSONObject tokenJson = new JSONObject();
  273. tokenJson.put("app_id",APP_ID);
  274. tokenJson.put("app_secret",APP_SERCRET);
  275. try {
  276. String returnSt = doPostByHttpClient(url,tokenJson.toJSONString(),false,null);
  277. JSONObject returnJson = JSONObject.parseObject(returnSt);
  278. if("0".equals(returnJson.getString("code"))){//成功
  279. returnstr = returnJson.getString("tenant_access_token");
  280. }
  281. } catch (ConnectException e) {
  282. logger.info(e.getMessage());
  283. e.printStackTrace();
  284. }
  285. return returnstr;
  286. }
  287. /**
  288. * 根据手机号(暂定)获取userId/openId
  289. */
  290. public static String getUserId(String cell,String token) {
  291. String user_id = "";
  292. JSONObject m = new JSONObject();
  293. JSONArray mobiles = new JSONArray();
  294. mobiles.add(cell);
  295. m.put("mobiles", mobiles);
  296. String userIdUrl="https://open.feishu.cn/open-apis/contact/v3/users/batch_get_id";
  297. try {
  298. logger.info("获取用户json: " + m.toString());
  299. String response = doPostByHttpClient(userIdUrl, m.toJSONString(),true,token);
  300. JSONObject userRes = JSONObject.parseObject(response);
  301. user_id = userRes.getJSONObject("data").getJSONArray("user_list").getJSONObject(0).getString("user_id");
  302. logger.info("获取用户结束json: " + userRes.toString());
  303. } catch (ConnectException e) {
  304. // TODO Auto-generated catch block
  305. logger.info(e.getMessage());
  306. e.printStackTrace();
  307. }
  308. return user_id;
  309. }
  310. public static String doPostByHttpClient(String url, String data, boolean isBearer,String token) throws ConnectException {
  311. System.out.println("url =" + url);
  312. System.out.println("data =" + data);
  313. try {
  314. // System.setProperty("javax.net.debug", "ssl");
  315. DefaultHttpClient httpClient = null;
  316. if (url.toLowerCase().startsWith("https://")) {
  317. System.out.println("use ssl");
  318. httpClient = new SSLClient();
  319. } else {
  320. System.out.println("use nonssl");
  321. httpClient = new DefaultHttpClient();
  322. }
  323. HttpPost httpPost = new HttpPost(url);
  324. httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
  325. if(isBearer) {
  326. httpPost.addHeader("Authorization", "Bearer" + " " + token);
  327. }
  328. StringEntity se = new StringEntity(data, "UTF-8");
  329. se.setContentType("text/json");
  330. se.setContentEncoding(new BasicHeader("Content-Type", "application/json; charset=UTF-8"));
  331. httpPost.setEntity(se);
  332. HttpResponse response = httpClient.execute(httpPost);
  333. int statusCode = response.getStatusLine().getStatusCode();
  334. if (statusCode != 200) {
  335. throw new ConnectException("连接服务器发生错误!");
  336. }
  337. String body = EntityUtils.toString(response.getEntity());
  338. System.out.println(body);
  339. return body;
  340. } catch (Exception e) {
  341. e.printStackTrace();
  342. System.out.println(" ===== doPostByHttpClient() ERROR ===== ");
  343. throw new ConnectException(e.getMessage());
  344. } finally {
  345. System.clearProperty("javax.net.debug");
  346. }
  347. }
  348. }