From 7d4b7c4851868e260ca7991a43c3c01c7e65de96 Mon Sep 17 00:00:00 2001 From: "LAPTOP-SB56SG4Q\\86185" Date: Tue, 19 Oct 2021 13:40:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E5=BC=80=E6=BA=90=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=9D=90=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- JSD-8449配置使用文档.docx | Bin 0 -> 42380 bytes README.md | 5 +- 单点/plugin.xml | 24 ++ .../plugin/yuyuantm/oauth2/CommonUtils.java | 132 +++++++ .../oauth2/CustomLogInOutEventProvider.java | 31 ++ .../fr/plugin/yuyuantm/oauth2/DesECBUtil.java | 66 ++++ .../fr/plugin/yuyuantm/oauth2/SsoFilter.java | 192 ++++++++++ 单点/src/main/resources/yuyuantm.properties | 14 + 推送/plugin.xml | 27 ++ .../yuyuan/dingding/DingDIngDBAccess.java | 44 +++ .../dingding/DingTalkFormulaProvider.java | 27 ++ .../yuyuan/dingding/DingTalkLocaleFinder.java | 22 ++ .../dingding/DingTalkOutputActionHandler.java | 100 +++++ .../DingTalkOutputFormulaExtractor.java | 26 ++ .../OutputPluginLifecycleMonitor.java | 31 ++ .../yuyuan/dingding/bean/OutputDingTalk.java | 125 +++++++ .../bean/msg/DingTalkFileMessage.java | 36 ++ .../bean/msg/DingTalkLinkMessage.java | 84 +++++ .../dingding/bean/msg/DingTalkMessage.java | 221 +++++++++++ .../bean/msg/DingTalkMessageType.java | 24 ++ .../dingding/bean/msg/DingTalkOAMessage.java | 38 ++ .../bean/msg/DingTalkTextMessage.java | 36 ++ .../plugin/yuyuan/dingding/bean/msg/OA.java | 127 +++++++ .../constant/DingTalkApiConstants.java | 31 ++ .../dingding/constant/DingTalkConstants.java | 183 +++++++++ .../dingding/dao/OutputDingTalkDAO.java | 21 ++ .../dingding/entity/OutputDingTalkEntity.java | 154 ++++++++ .../dingding/format/PNGOutputFormat.java | 40 ++ .../fr/plugin/yuyuan/dingding/js/FileDef.java | 55 +++ .../yuyuan/dingding/js/JSCSSBridge.java | 28 ++ .../yuyuan/dingding/util/DesECBUtil.java | 66 ++++ .../plugin/yuyuan/dingding/util/HttpUtil.java | 132 +++++++ .../yuyuan/dingding/util/HttpsUtil.java | 346 ++++++++++++++++++ .../dingding/locale/dingtalk.properties | 165 +++++++++ .../dingding/locale/dingtalk_en_US.properties | 165 +++++++++ .../dingding/locale/dingtalk_ja_JP.properties | 165 +++++++++ .../dingding/locale/dingtalk_zh_CN.properties | 165 +++++++++ .../dingding/locale/dingtalk_zh_TW.properties | 165 +++++++++ .../com/fr/plugin/yuyuan/dingding/theme.js | 51 +++ 推送/src/main/resources/dingtalk.properties | 3 + 40 files changed, 3366 insertions(+), 1 deletion(-) create mode 100644 JSD-8449配置使用文档.docx create mode 100644 单点/plugin.xml create mode 100644 单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/CommonUtils.java create mode 100644 单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/CustomLogInOutEventProvider.java create mode 100644 单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/DesECBUtil.java create mode 100644 单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/SsoFilter.java create mode 100644 单点/src/main/resources/yuyuantm.properties create mode 100644 推送/plugin.xml create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingDIngDBAccess.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkFormulaProvider.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkLocaleFinder.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkOutputActionHandler.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkOutputFormulaExtractor.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/OutputPluginLifecycleMonitor.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/OutputDingTalk.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkFileMessage.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkLinkMessage.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkMessage.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkMessageType.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkOAMessage.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkTextMessage.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/OA.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/constant/DingTalkApiConstants.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/constant/DingTalkConstants.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/dao/OutputDingTalkDAO.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/entity/OutputDingTalkEntity.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/format/PNGOutputFormat.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/js/FileDef.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/js/JSCSSBridge.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/DesECBUtil.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/HttpUtil.java create mode 100644 推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/HttpsUtil.java create mode 100644 推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk.properties create mode 100644 推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_en_US.properties create mode 100644 推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_ja_JP.properties create mode 100644 推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_zh_CN.properties create mode 100644 推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_zh_TW.properties create mode 100644 推送/src/main/resources/com/fr/plugin/yuyuan/dingding/theme.js create mode 100644 推送/src/main/resources/dingtalk.properties diff --git a/JSD-8449配置使用文档.docx b/JSD-8449配置使用文档.docx new file mode 100644 index 0000000000000000000000000000000000000000..7f750970cc23879131898bae8383b983259a6f77 GIT binary patch literal 42380 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

Med%s&6%21@7UC` z^JzT|=$`Nf9t!m|%08#(XBpo*&T{N24rq>f%8!bmC1$krZKcho`UK;N>Xc?7LQ2Du zKsN$Drrlc8km8CrrgVjVe_hy~0oqmdT*Jc93-};Gc~T1wS5Mgy!jcYLCTnTw{^H9% zyT{qDnqBfzMPOIVKa!0=_~(WnM}mhh^d$f!r__31W6GyC%`Ldt%%&nzFKmzswR>HOdUdTVvIDwZtW8?n9~t>I-P7+hjwavkj6 ztjdxS3ShQx@tRUk40GegLXA7!kFG$4Eu{g0@oh3ck4oi32gS91-YS((G_BJ9L+iC~ zxt>lK7U;C7d?Sc|A9o`$cj~+kOfB2>Ei8)@CBG^`Ism3XUj=wdBOmM$IP}jTSB~zJ z0fMbf1%}oLoa_W|FNepsDIrJv_-@c*4Fihxut5 zk-rT5dzHGY_rKa*y*iHjyRzSRdcXePX?{7ykN;cqa~=LKXTOGUC%tpF!u-zy`M-2` zy??d4XF{L;sr$Qb{28PBrS(qzYq%EwqW-hc-v8?NDUiQy0a^YzlK)t_Z{R+F@wb8D z|1$6!$N0Yjf^ui#XZt%e(0ce&3f;EVDIlXcfwzT4gOOI z9ru4|<^Ra}-z)S!cfO(R*BpBPoiBFw5DVjfi2ps={>&U>vcG)Wn;Bag w|JNED(Oc?ChE~#OqF)TR-(Exh6#kU|gsm#eA^a@8P>KQIJ2bPuB;ASr4`~lx7ytkO literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 0796de2..5abf539 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ # open-JSD-8449 -JSD-8449 钉钉单点+推送(特殊)开源任务材料 \ No newline at end of file +JSD-8449 钉钉单点+推送(特殊)开源任务材料\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。 \ No newline at end of file diff --git a/单点/plugin.xml b/单点/plugin.xml new file mode 100644 index 0000000..ef8ec4e --- /dev/null +++ b/单点/plugin.xml @@ -0,0 +1,24 @@ + + + com.fr.plugin.yuyuantm.oauth2 + + yes + 1.5 + 10.0 + 2018-07-31 + fr.open + + + + + + + + + \ No newline at end of file diff --git a/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/CommonUtils.java b/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/CommonUtils.java new file mode 100644 index 0000000..822a870 --- /dev/null +++ b/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/CommonUtils.java @@ -0,0 +1,132 @@ +package com.fr.plugin.yuyuantm.oauth2; + +import com.fr.data.NetworkHelper; +import com.fr.decision.authority.data.User; +import com.fr.decision.mobile.terminal.TerminalHandler; +import com.fr.decision.webservice.utils.DecisionServiceConstants; +import com.fr.decision.webservice.utils.DecisionStatusService; +import com.fr.decision.webservice.v10.login.LoginService; +import com.fr.decision.webservice.v10.login.TokenResource; +import com.fr.decision.webservice.v10.user.UserService; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import com.fr.stable.web.Device; +import com.fr.web.utils.WebUtils; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; +import java.util.Properties; + +/** + * @author fr.open + * @since 2021/8/24 + */ +public class CommonUtils { + + public static String getProperty(Properties props, String key, String defaultValue, boolean allowBlank) { + String value = props.getProperty(key); + if (StringUtils.isNotBlank(value)) { + return value; + } else { + if (allowBlank) { + FineLoggerFactory.getLogger().warn("Property[" + key + "] value is blank."); + return defaultValue; + } else { + throw new IllegalArgumentException("Property[" + key + "] cann't be blank."); + } + } + } + + public static String getProperty(Properties props, String key, boolean allowBlank) { + return getProperty(props, key, null, allowBlank); + } + + public static String getProperty(Properties props, String key) { + return getProperty(props, key, null, true); + } + + public static boolean isLogin(HttpServletRequest request) { + String oldToken = TokenResource.COOKIE.getToken(request); + return oldToken != null && checkTokenValid(request, (String) oldToken); + } + + private static boolean checkTokenValid(HttpServletRequest req, String token) { + try { + Device device = NetworkHelper.getDevice(req); + LoginService.getInstance().loginStatusValid(token, TerminalHandler.getTerminal(req, device)); + return true; + } catch (Exception ignore) { + } + return false; + } + + /** + * 跳转到过滤器链中的下一个过滤器 + * + * @param request + * @param response + * @param chain + */ + public static void next(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { + try { + chain.doFilter(request, response); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void login(String username, HttpServletRequest request, HttpServletResponse response) { + try { + User user = UserService.getInstance().getUserByUserName(username); + if (user == null) { + throw new RuntimeException("系统未授权, 当前用户是\"" + username + "\""); + } + String token = LoginService.getInstance().login(request, response, username); + request.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("sso >> Failed to login with[" + username + "]", e); + throw new RuntimeException("用户\"" + username +"\"登录失败"); + } + } + + public static boolean isMobileDevice(HttpServletRequest request) { + if (WebUtils.getDevice(request).isMobile()) { + FineLoggerFactory.getLogger().info("current request is is mobile request ,url is {}", request.getRequestURI()); + return true; + } + String requestHeader = request.getHeader("user-agent"); + String[] deviceArray = new String[]{"android", "iphone", "ipad", "ios", "windows phone", "wechat"}; + if (requestHeader == null) { + return false; + } + requestHeader = requestHeader.toLowerCase(); + for (int i = 0; i < deviceArray.length; i++) { + if (requestHeader.toLowerCase().contains(deviceArray[i])) { + FineLoggerFactory.getLogger().info("current request:{} is mobile request!", request.getRequestURI()); + return true; + } + } + String op = WebUtils.getHTTPRequestParameter(request, "op"); + return StringUtils.isNotBlank(op) && StringUtils.equals("h5",op); + } + + public static void cacheParams(String key, Map values) { + try { + DecisionStatusService.originUrlStatusService().put(key, values); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String getCachedParam(String key, String name) { + try { + Map values = DecisionStatusService.originUrlStatusService().get(key); + return values.get(name); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/CustomLogInOutEventProvider.java b/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/CustomLogInOutEventProvider.java new file mode 100644 index 0000000..0c128ad --- /dev/null +++ b/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/CustomLogInOutEventProvider.java @@ -0,0 +1,31 @@ +package com.fr.plugin.yuyuantm.oauth2; + +import com.fr.decision.fun.impl.AbstractLogInOutEventProvider; +import com.fr.decision.webservice.login.LogInOutResultInfo; +import com.fr.general.PropertiesUtils; +import com.fr.stable.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Properties; + +import static com.fr.plugin.yuyuantm.oauth2.CommonUtils.getProperty; + +/** + * @Author fr.open + * @since 2021/8/24 + **/ +public class CustomLogInOutEventProvider extends AbstractLogInOutEventProvider { + + @Override + public String logoutAction(LogInOutResultInfo result) { + Properties props = PropertiesUtils.getProperties("yuyuantm"); + String syscode = getProperty(props, "api.syscode", false); + String logoutURL = getProperty(props, "api.logout", true); + String logoutRedirectURL = getProperty(props, "api.logout-redirect", "http://www.baidu.com", true); + if (StringUtils.isBlank(logoutURL)) { + return null; + } + return String.format("%s?yuyuan_syscode=%s&service=%s", logoutURL, syscode, logoutRedirectURL); + } +} diff --git a/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/DesECBUtil.java b/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/DesECBUtil.java new file mode 100644 index 0000000..36a0134 --- /dev/null +++ b/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/DesECBUtil.java @@ -0,0 +1,66 @@ +package com.fr.plugin.yuyuantm.oauth2; + +import com.fr.third.org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; + +/** + * @Author fr.open + * @Date 2021/8/24 + * @Description + **/ +public class DesECBUtil { + /** + * 加密数据 + * + * @param encryptString + * @param encryptKey + * @return + * @throws Exception + */ + public static String encryptDES(String encryptString, String encryptKey) throws Exception { + Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(getKey(encryptKey), "DES")); + byte[] encryptedData = cipher.doFinal(encryptString.getBytes("UTF-8")); + return Base64.encodeBase64String(encryptedData); + } + + /** + * key 不足8位补位 + * + * @param + */ + public static byte[] getKey(String keyRule) { + Key key = null; + byte[] keyByte = keyRule.getBytes(); + // 创建一个空的八位数组,默认情况下为0 + byte[] byteTemp = new byte[8]; + // 将用户指定的规则转换成八位数组 + for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) { + byteTemp[i] = keyByte[i]; + } + key = new SecretKeySpec(byteTemp, "DES"); + return key.getEncoded(); + } + + /*** + * 解密数据 + * @param decryptString + * @param decryptKey + * @return + * @throws Exception + */ + + public static String decryptDES(String decryptString, String decryptKey) throws Exception { + byte[] sourceBytes = Base64.decodeBase64(decryptString); + Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(getKey(decryptKey), "DES")); + byte[] decoded = cipher.doFinal(sourceBytes); + return new String(decoded, "UTF-8"); + + } + +} + diff --git a/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/SsoFilter.java b/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/SsoFilter.java new file mode 100644 index 0000000..add6f4e --- /dev/null +++ b/单点/src/main/java/com/fr/plugin/yuyuantm/oauth2/SsoFilter.java @@ -0,0 +1,192 @@ +package com.fr.plugin.yuyuantm.oauth2; + +import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; +import com.fr.decision.webservice.utils.WebServiceUtils; +import com.fr.general.PropertiesUtils; +import com.fr.general.http.HttpToolbox; +import com.fr.json.JSONObject; +import com.fr.locale.InterProviderFactory; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.transform.FunctionRecorder; +import com.fr.stable.StringUtils; +import com.fr.web.utils.WebUtils; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; +import java.util.stream.Stream; + +import static com.fr.plugin.yuyuantm.oauth2.CommonUtils.*; + +/** + * @author fr.open + * @since 2021/8/24 + */ +@FunctionRecorder +public class SsoFilter extends AbstractGlobalRequestFilterProvider { + + private static String[] NOT_FILTER = { + "/decision/file", + "/decision/resources", + "/system", + "/materials.min.js.map", + "/remote", + "/login", + "/url/mobile", + "/login/config", + "/help/css", + }; + + private static final String E_KEY = "xxxx"; + + private String syscode; + + private String apiClientId; + + private String apiClientSecret; + + private String apiAuthorize; + + private String apiGetToken; + + private String apiGetUser; + + private void initParams() { + Properties props = PropertiesUtils.getProperties("yuyuantm"); + this.syscode = getProperty(props, "api.syscode", false); + this.apiClientId = getProperty(props, "api.client_id", false); + this.apiAuthorize = getProperty(props, "api.authorize", false); + this.apiGetToken = getProperty(props, "api.get-token", false); + this.apiGetUser = getProperty(props, "api.get-user", false); + this.apiClientSecret = getProperty(props, "api.client_secret", false); + } + + + @Override + public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { + if (isAccept(request)) { + next(request, response, chain); + return; + } + try { + String resultSign = request.getParameter("result_sign"); + if (StringUtils.isNotBlank(resultSign)) { + String username = DesECBUtil.decryptDES(resultSign, E_KEY); + login(username, request, response); + next(request, response, chain); + return; + } + initParams(); + String code = request.getParameter("code"); + if (StringUtils.isBlank(code)) { + jumpAuthorize(request, response); + return; + } + login(getUsername(getToken(code)), request, response); + String state = request.getParameter("state"); + if (StringUtils.isNotBlank(state)) { + String accessURL = getCachedParam(state, "accessURL"); + if (StringUtils.isNotBlank(accessURL)) { + response.sendRedirect(accessURL); + return; + } + } + next(request, response, chain); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("oauth2 >>> 单点登陆处理失败", e); + setError(response, e.getMessage()); + } + } + + private String getUsername(String token) throws IOException { + String address = String.format("%s?yuyuan_syscode=%s", apiGetUser, syscode); + HashMap params = new HashMap<>(); + params.put("access_token", token); + String res = HttpToolbox.post(address, params); + JSONObject body = new JSONObject(res); + if (body.has("account")) { + return body.getString("account"); + } + throw new RuntimeException("获取用户信息失败,Cause by: " + res); + } + + private String getToken(String code) throws IOException { + String address = String.format("%s?yuyuan_syscode=%s", apiGetToken, syscode); + HashMap params = new HashMap<>(); + params.put("client_id", apiClientId); + params.put("client_secret", apiClientSecret); + params.put("code", code); + params.put("grant_type", "authorization_code"); + String res = HttpToolbox.post(address, params); + JSONObject body = new JSONObject(res); + if (body.has("access_token")) { + return body.getString("access_token"); + } + throw new RuntimeException("获取access_token失败,Cause by: " + res); + } + + private void jumpAuthorize(HttpServletRequest request, HttpServletResponse response) throws IOException { + String state = UUID.randomUUID().toString(); + String accessURL = request.getRequestURI(); + if (StringUtils.isNotBlank(request.getQueryString())) { + accessURL += "?" + request.getQueryString(); + } + Map params = new HashMap<>(); + params.put("accessURL", accessURL); + cacheParams(state, params); + String address = String.format("%s?yuyuan_syscode=%s&response_type=code&client_id=%s&state=%s&redirect=%s", apiAuthorize, syscode, apiClientId, state, request.getRequestURI()); + FineLoggerFactory.getLogger().info("oauth2 >>> 请求中不包含code值,条转到登陆页面 >>> \"{}\"", address); + response.sendRedirect(address); + } + + @Override + public String filterName() { + return "sso"; + } + + @Override + public String[] urlPatterns() { + return new String[]{"/*"}; + } + + private boolean isAccept(HttpServletRequest request) { + if (request.getRequestURI().endsWith("/view/form") || request.getRequestURI().endsWith("/view/report")) { + String viewlet = WebUtils.getHTTPRequestParameter(request, "viewlet"); + if (StringUtils.isBlank(viewlet)) { + return true; + } + } + String url = request.getRequestURL().toString(); + if (Stream.of(NOT_FILTER).anyMatch(url::contains)) { + return true; + } + String t = request.getParameter("ref_t"); + if (StringUtils.equals("design", t)) { + return true; + } + return isLogin(request); + } + + private void setError(HttpServletResponse res, String reason) { + try { + PrintWriter printWriter = WebUtils.createPrintWriter(res); + Map map = new HashMap<>(); + map.put("result", InterProviderFactory.getProvider().getLocText("Fine-Engine_Error_Page_Result")); + map.put("reason", reason); + map.put("solution", InterProviderFactory.getProvider().getLocText("Fine-Engine_Please_Contact_Platform_Admin")); + String page = WebServiceUtils.parseWebPageResourceSafe("com/fr/web/controller/decision/entrance/resources/unavailable.html", map); + printWriter.write(page); + printWriter.flush(); + printWriter.close(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + +} diff --git a/单点/src/main/resources/yuyuantm.properties b/单点/src/main/resources/yuyuantm.properties new file mode 100644 index 0000000..7cac4ab --- /dev/null +++ b/单点/src/main/resources/yuyuantm.properties @@ -0,0 +1,14 @@ +# \u63A5\u53E3\u6240\u9700\u7684 yuyuan_syscode \u53C2\u6570\u503C +api.syscode=xxxxx +api.client_id=xxxxx +api.client_secret=xxxx +# \u767B\u9646\u9875\u9762\u83B7\u53D6code\u5730\u5740 +api.authorize=https://xxxx/oauth2/authorize +# \u83B7\u53D6access_token\u63A5\u53E3 +api.get-token=https://xxxx/oauth2/token +# \u83B7\u53D6\u7528\u6237\u4FE1\u606F\u63A5\u53E3 +api.get-user=https://xxxx/oauth2/resource +# \u6CE8\u9500\u767B\u9646\u63A5\u53E3\uFF0C\u4E0D\u9700\u8981\u53EF\u4E3A\u7A7A +api.logout=https://xxxx/oauth2/logout +# \u6CE8\u9500\u767B\u9646\u540E\u6761\u8F6C\u5730\u5740 +api.logout-redirect=https://www.baidu.com \ No newline at end of file diff --git a/推送/plugin.xml b/推送/plugin.xml new file mode 100644 index 0000000..81be93d --- /dev/null +++ b/推送/plugin.xml @@ -0,0 +1,27 @@ + + com.fr.plugin.yuyuan.dingding + + yes + 1.2 + 10.0 + 2018-07-31 + fr.open + + + ]]> + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingDIngDBAccess.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingDIngDBAccess.java new file mode 100644 index 0000000..81c33e6 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingDIngDBAccess.java @@ -0,0 +1,44 @@ +package com.fr.plugin.yuyuan.dingding; + +import com.fr.decision.plugin.db.AbstractDecisionDBAccessProvider; +import com.fr.plugin.yuyuan.dingding.dao.OutputDingTalkDAO; +import com.fr.plugin.yuyuan.dingding.entity.OutputDingTalkEntity; +import com.fr.stable.db.accessor.DBAccessor; +import com.fr.stable.db.dao.BaseDAO; +import com.fr.stable.db.dao.DAOProvider; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingDIngDBAccess extends AbstractDecisionDBAccessProvider { + + private static DBAccessor dbAccessor; + + public DBAccessor getDbAccessor() { + return dbAccessor; + } + + @Override + public DAOProvider[] registerDAO() { + return new DAOProvider[]{ + new DAOProvider() { + @Override + public Class getEntityClass() { + return OutputDingTalkEntity.class; + } + + @Override + public Class getDAOClass() { + return OutputDingTalkDAO.class; + } + } + }; + } + + @Override + public void onDBAvailable(DBAccessor dbAccessor) { + DingDIngDBAccess.dbAccessor = dbAccessor; + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkFormulaProvider.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkFormulaProvider.java new file mode 100644 index 0000000..36f6b2c --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkFormulaProvider.java @@ -0,0 +1,27 @@ +package com.fr.plugin.yuyuan.dingding; + +import com.fr.main.workbook.ResultWorkBook; +import com.fr.plugin.yuyuan.dingding.bean.OutputDingTalk; +import com.fr.schedule.base.provider.impl.AbstractOutputFormulaProvider; +import com.fr.schedule.extension.report.util.ScheduleParameterUtils; + +import java.util.List; +import java.util.Map; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkFormulaProvider extends AbstractOutputFormulaProvider { + @Override + public void dealWithFormulaParam(OutputDingTalk action, ResultWorkBook result, List> mapList) throws Exception { + action.setSubject(ScheduleParameterUtils.dealWithParameter(action.getSubject(), mapList.get(0), result)); + action.setContent(ScheduleParameterUtils.dealWithParameter(action.getContent(), mapList.get(0), result)); + } + + @Override + public String getActionClassName() { + return OutputDingTalk.class.getName(); + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkLocaleFinder.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkLocaleFinder.java new file mode 100644 index 0000000..81984c7 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkLocaleFinder.java @@ -0,0 +1,22 @@ +package com.fr.plugin.yuyuan.dingding; + +import com.fr.stable.fun.impl.AbstractLocaleFinder; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkLocaleFinder extends AbstractLocaleFinder { + private static final int CURRENT_LEVEL = 1; + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + + @Override + public String find() { + return "com/fr/plugin/rongchuang/dingding/locale/dingtalk"; + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkOutputActionHandler.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkOutputActionHandler.java new file mode 100644 index 0000000..53591e1 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkOutputActionHandler.java @@ -0,0 +1,100 @@ +package com.fr.plugin.yuyuan.dingding; + +import com.fr.decision.authority.AuthorityContext; +import com.fr.decision.authority.data.User; +import com.fr.general.PropertiesUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.yuyuan.dingding.bean.OutputDingTalk; +import com.fr.plugin.yuyuan.dingding.bean.msg.DingTalkMessage; +import com.fr.plugin.yuyuan.dingding.bean.msg.DingTalkOAMessage; +import com.fr.plugin.yuyuan.dingding.bean.msg.OA; +import com.fr.plugin.yuyuan.dingding.util.DesECBUtil; +import com.fr.plugin.yuyuan.dingding.util.HttpUtil; +import com.fr.schedule.base.constant.ScheduleConstants; +import com.fr.schedule.feature.output.OutputActionHandler; +import com.fr.stable.StringUtils; +import com.fr.stable.query.QueryFactory; +import com.fr.stable.query.restriction.RestrictionFactory; + +import java.net.URLEncoder; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkOutputActionHandler extends OutputActionHandler { + + private static final String key = "xxxx"; + + private String yuyuan_syscode; + + private String msg_type; + + private String host; + + public DingTalkOutputActionHandler() { + this.yuyuan_syscode = PropertiesUtils.getProperties("dingtalk").getProperty("yuyuan_syscode"); + this.msg_type = PropertiesUtils.getProperties("dingtalk").getProperty("msg_type"); + this.host = PropertiesUtils.getProperties("dingtalk").getProperty("host"); + } + + @Override + public void doAction(OutputDingTalk action, Map map) throws Exception { + if (StringUtils.isBlank(yuyuan_syscode) || StringUtils.isBlank(msg_type) || StringUtils.isBlank(host)) { + throw new Exception("ding talk config is null!"); + } + try { + String[] users = (String[]) map.get(ScheduleConstants.USERNAMES); + String scheduleUsername = (String) map.get(ScheduleConstants.USERNAME); + Set userSet = new HashSet(); + if (StringUtils.isNotBlank(scheduleUsername)) { + userSet.add(scheduleUsername); + } else { + userSet.addAll(Arrays.asList(users)); + } + List getUsers = AuthorityContext.getInstance().getUserController().find(QueryFactory.create().addRestriction(RestrictionFactory.in("userName", userSet))); + Set collect = getUsers.stream().filter(e -> StringUtils.isNotBlank(e.getEmail())).map(e -> e.getEmail()).collect(Collectors.toSet()); + if (collect.isEmpty()) { + throw new Exception("user email is null"); + } + DingTalkMessage message = DingTalkMessage.getDingTalkMessage(action, map); + if (message instanceof DingTalkOAMessage) { + DingTalkOAMessage linkMessage = (DingTalkOAMessage) message; + for (User user : getUsers) { + delaSign(linkMessage, user); + String msgid = HttpUtil.sendMessage(linkMessage, user.getEmail(), msg_type); + } + } else { + String msgid = HttpUtil.sendMessage(message, com.fr.third.org.apache.commons.lang3.StringUtils.join(collect, ","), msg_type); + } + //HttpUtil.getMessage(msgid); + } catch (Exception e) { + throw e; + } + + } + + private void delaSign(DingTalkOAMessage linkMessage, User user) { + try { + String encode = URLEncoder.encode(DesECBUtil.encryptDES(user.getUserName(), key),"UTF-8"); + OA oa = linkMessage.getOa(); + if (oa.getMessageUrl().indexOf("?") != -1) { + oa.setMessageUrl(oa.getMessageUrl() + "&result_sign=" + encode); + } else { + oa.setMessageUrl(oa.getMessageUrl() + "?result_sign=" + encode); + } + + if (oa.getMessageUrlPC().indexOf("?") != -1) { + oa.setMessageUrlPC(oa.getMessageUrlPC() + "&result_sign=" + encode); + } else { + oa.setMessageUrlPC(oa.getMessageUrlPC() + "?result_sign=" + encode); + } + + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkOutputFormulaExtractor.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkOutputFormulaExtractor.java new file mode 100644 index 0000000..554a332 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/DingTalkOutputFormulaExtractor.java @@ -0,0 +1,26 @@ +package com.fr.plugin.yuyuan.dingding; + +import com.fr.plugin.yuyuan.dingding.bean.OutputDingTalk; +import com.fr.schedule.extension.report.job.output.formula.extract.impl.AbstractOutputFormulaExtractorProvider; +import com.fr.schedule.extension.report.util.ScheduleParameterUtils; + +import java.util.Map; +import java.util.regex.Pattern; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkOutputFormulaExtractor extends AbstractOutputFormulaExtractorProvider { + @Override + public String getActionClassName() { + return OutputDingTalk.class.getName(); + } + + @Override + public void addFormulaToMap(OutputDingTalk outputDingTalk, Pattern pattern, Map map) { + ScheduleParameterUtils.addFormulaToMap(outputDingTalk.getSubject(), pattern, map); + ScheduleParameterUtils.addFormulaToMap(outputDingTalk.getContent(), pattern, map); + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/OutputPluginLifecycleMonitor.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/OutputPluginLifecycleMonitor.java new file mode 100644 index 0000000..1acfa42 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/OutputPluginLifecycleMonitor.java @@ -0,0 +1,31 @@ +package com.fr.plugin.yuyuan.dingding; + +import com.fr.plugin.context.PluginContext; +import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; +import com.fr.plugin.yuyuan.dingding.bean.OutputDingTalk; +import com.fr.plugin.yuyuan.dingding.entity.OutputDingTalkEntity; +import com.fr.plugin.yuyuan.dingding.format.PNGOutputFormat; +import com.fr.schedule.extension.report.job.output.BaseOutputFormat; +import com.fr.schedule.feature.ScheduleOutputActionEntityRegister; +import com.fr.schedule.feature.output.OutputActionHandler; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class OutputPluginLifecycleMonitor extends AbstractPluginLifecycleMonitor { + @Override + public void afterRun(PluginContext pluginContext) { + BaseOutputFormat.registerOutputFormat(new PNGOutputFormat()); + OutputActionHandler.registerHandler(new DingTalkOutputActionHandler(), OutputDingTalk.class.getName()); + ScheduleOutputActionEntityRegister.getInstance().addClass(OutputDingTalkEntity.class); + } + + @Override + public void beforeStop(PluginContext pluginContext) { + + OutputActionHandler.removeOutputHandler(OutputDingTalk.class.getName()); + ScheduleOutputActionEntityRegister.getInstance().removeClass(OutputDingTalkEntity.class); + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/OutputDingTalk.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/OutputDingTalk.java new file mode 100644 index 0000000..c29eae5 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/OutputDingTalk.java @@ -0,0 +1,125 @@ +package com.fr.plugin.yuyuan.dingding.bean; + +import com.fr.plugin.yuyuan.dingding.entity.OutputDingTalkEntity; +import com.fr.schedule.base.bean.output.BaseOutputAction; +import com.fr.schedule.base.entity.AbstractScheduleEntity; +import com.fr.schedule.base.type.RunType; +import com.fr.third.fasterxml.jackson.annotation.JsonSubTypes; +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +@JsonSubTypes.Type(value = OutputDingTalk.class, name = "OutputDingTalk") +public class OutputDingTalk extends BaseOutputAction { + private int terminal = 32; + + private String subject; + + private String content; + + private int type; + + private int linkOpenType = -1; + + private String mediaId; + + private String customizeLink; + + private int runType = RunType.CLIENT_NOTIFICATION.getValue(); + + @Override + public boolean willExecuteByUser() { + return true; + } + + @Override + public RunType runType() { + return RunType.CLIENT_NOTIFICATION; + } + + @Override + public Class outputActionEntityClass() { + return OutputDingTalkEntity.class; + } + + @Override + public OutputDingTalkEntity createOutputActionEntity() { + OutputDingTalkEntity entity = new OutputDingTalkEntity(); + entity.setId(this.getId()); + entity.setContent(this.getContent()); + entity.setSubject(this.getSubject()); + entity.setTerminal(this.getTerminal()); + entity.setType(this.getType()); + entity.setLinkOpenType(this.getLinkOpenType()); + entity.setCustomizeLink(this.getCustomizeLink()); + entity.setMediaId(this.getMediaId()); + return entity; + } + + + public int getTerminal() { + return terminal; + } + + public void setTerminal(int terminal) { + this.terminal = terminal; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public int getLinkOpenType() { + return linkOpenType; + } + + public void setLinkOpenType(int linkOpenType) { + this.linkOpenType = linkOpenType; + } + + public String getCustomizeLink() { + return customizeLink; + } + + public void setCustomizeLink(String customizeLink) { + this.customizeLink = customizeLink; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public int getRunType() { + return runType; + } + + public void setRunType(int runType) { + this.runType = runType; + } + +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkFileMessage.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkFileMessage.java new file mode 100644 index 0000000..2f097e0 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkFileMessage.java @@ -0,0 +1,36 @@ +package com.fr.plugin.yuyuan.dingding.bean.msg; + +import com.fr.json.JSONException; +import com.fr.json.JSONObject; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkFileMessage extends DingTalkMessage { + + //必填 + private String mediaId; + + public DingTalkFileMessage(String mediaId) { + super(); + this.mediaId = mediaId; + } + + @Override + public String getMessageType() { + return DingTalkMessageType.FILE; + } + + @Override + public JSONObject createMessageJSONObject() throws JSONException { + JSONObject jo = JSONObject.create(); + JSONObject message = createMessageBaseJSONObject(); + JSONObject file = JSONObject.create(); + file.put("media_id", mediaId); + message.put("file", file); + jo.put("msg", message); + return jo; + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkLinkMessage.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkLinkMessage.java new file mode 100644 index 0000000..120ba94 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkLinkMessage.java @@ -0,0 +1,84 @@ +package com.fr.plugin.yuyuan.dingding.bean.msg; + +import com.fr.json.JSONException; +import com.fr.json.JSONObject; +import com.fr.third.javax.annotation.Nonnull; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkLinkMessage extends DingTalkMessage { + + //必填 + private Link link; + + public DingTalkLinkMessage(@Nonnull Link link) { + super(); + this.link = link; + } + + @Override + public String getMessageType() { + return DingTalkMessageType.LINK; + } + + public Link getLink() { + return link; + } + + @Override + public JSONObject createMessageJSONObject() throws JSONException { + JSONObject jo = JSONObject.create(); + JSONObject message = createMessageBaseJSONObject(); + JSONObject linkObject = JSONObject.create(); + linkObject.put("messageUrl",link.getMessageUrl()); + linkObject.put("picUrl",link.getPicUrl()); + linkObject.put("title",link.getTitle()); + linkObject.put("text",link.getText()); + message.put("link",linkObject); + jo.put("msg", message); + return jo; + } + + + public static class Link{ + //必填 + private String messageUrl; + private String picUrl; + private String title; + private String text; + + public Link(@Nonnull String messageUrl, @Nonnull String picUrl, @Nonnull String title, @Nonnull String text) { + this.messageUrl = messageUrl; + this.picUrl = picUrl; + this.title = title; + this.text = text; + } + + public String getMessageUrl() { + return messageUrl; + } + + public String getPicUrl() { + return picUrl; + } + + public String getTitle() { + return title; + } + + public String getText() { + return text; + } + + public void setMessageUrl(String messageUrl) { + this.messageUrl = messageUrl; + } + + public void setPicUrl(String picUrl) { + this.picUrl = picUrl; + } + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkMessage.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkMessage.java new file mode 100644 index 0000000..51d13dc --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkMessage.java @@ -0,0 +1,221 @@ +package com.fr.plugin.yuyuan.dingding.bean.msg; + +import com.fr.cache.Attachment; +import com.fr.decision.mobile.MobileConstant; +import com.fr.decision.mobile.MobileUtil; +import com.fr.io.utils.ResourceIOUtils; +import com.fr.json.JSONException; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.yuyuan.dingding.bean.OutputDingTalk; +import com.fr.plugin.yuyuan.dingding.constant.DingTalkApiConstants; +import com.fr.plugin.yuyuan.dingding.constant.DingTalkConstants; +import com.fr.plugin.yuyuan.dingding.util.HttpUtil; +import com.fr.schedule.base.constant.ScheduleConstants; +import com.fr.stable.CodeUtils; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.web.AttachmentHelper; +import com.fr.workspace.WorkContext; + +import java.util.Map; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public abstract class DingTalkMessage { + //必填 + private String msgType; + + public DingTalkMessage() { + this.msgType = getMessageType(); + } + + public static DingTalkMessage getDingTalkMessage(OutputDingTalk action, Map map) { + DingTalkMessage message = null; + int type = action.getType(); + switch (type) { + case DingTalkConstants.MessageType.LINK://链接 + message = createLinkMessage(action,map); + break; + case DingTalkConstants.MessageType.FILE://文件 + message = createFileMessage(action, map); + break; + case DingTalkConstants.MessageType.NEWS://图文 + message = createOAMessage(action, map); + break; + case DingTalkConstants.MessageType.TEXT://文本 + message = createTextMessage(action); + break; + default: + message = createTextMessage(action); + break; + } + return message; + } + + private static DingTalkMessage createFileMessage(OutputDingTalk messageBody,Map map){ + FineLoggerFactory.getLogger().debug("开始构建文件消息对象。。。"); + String mediaId = messageBody.getMediaId(); + String[] filePaths = (String[]) map.get(ScheduleConstants.OUTPUT_FILES); + String messageMediaId = StringUtils.EMPTY; + String[] suffixs = getSuffixByAttachType(Integer.valueOf(mediaId)); + String path = StringUtils.EMPTY; + outer: + for (String s : filePaths) { + for (String suff : suffixs) { + if (suff == null) { + break; + } + if (s.endsWith(suff)) { + path = s; + break outer; + } + } + } + + long fileSize = ResourceIOUtils.getLength(path); + if (fileSize > DingTalkConstants.MAX_PUSH_FILE_SIZE) { + String errMsg = "定时调度生成的文件大小超过10MB,钉钉推送消息失败"; + FineLoggerFactory.getLogger().error(errMsg); + throw new RuntimeException(errMsg); + } + final JSONObject result = HttpUtil.uploadMedia(path, DingTalkApiConstants.TYPE_FILE); + if (HttpUtil.isOk(result)) { + messageMediaId = result.getJSONObject("url").getString("media_id"); + FineLoggerFactory.getLogger().debug("调用上传文件接口成功!获取到的media_id为:" + messageMediaId); + } else { + FineLoggerFactory.getLogger().warn("调用钉钉上传文件接口失败!"); + } + FineLoggerFactory.getLogger().debug("文件消息对象构建结束。"); + return new DingTalkFileMessage(messageMediaId); + + + } + + public static String[] getSuffixByAttachType(int attachType) { + String[] suffixs = new String[2]; + switch (attachType) { + case DingTalkConstants.AttachType.CPR: + suffixs[0] = DingTalkConstants.Suffix.CPR; + break; + case DingTalkConstants.AttachType.EXCEL_03: + suffixs[0] = DingTalkConstants.Suffix.XLS; + break; + case DingTalkConstants.AttachType.EXCEL_07: + suffixs[0] = DingTalkConstants.Suffix.XLSX; + break; + case DingTalkConstants.AttachType.PDF: + suffixs[0] = DingTalkConstants.Suffix.PDF; + break; + case DingTalkConstants.AttachType.WORD: + suffixs[0] = DingTalkConstants.Suffix.DOC; + suffixs[1] = DingTalkConstants.Suffix.DOCX; + break; + default: + break; + } + return suffixs; + } + + private static DingTalkMessage createOAMessage(OutputDingTalk action, Map map) { + OA.Body body = new OA.Body(); + JSONObject result = JSONObject.create(); + String mediaId = action.getMediaId(); + if (StringUtils.isNotEmpty(mediaId)) { + String path = getOutputImagePathById(mediaId); + result = HttpUtil.uploadMedia(path,DingTalkApiConstants.TYPE_IMAGE); + } + if (HttpUtil.isOk(result)) { + String imageMediaId = result.getJSONObject("url").getString("media_id"); + FineLoggerFactory.getLogger().debug("调用上传文件接口成功!获取到的media_id为:" + imageMediaId); + body.setImage(imageMediaId); + } else { + FineLoggerFactory.getLogger().warn("调用钉钉上传文件接口失败!"); + } + OA oa = createOAObject(action, body, map); + return new DingTalkOAMessage(oa); + } + + public static String getOutputImagePathById(String id) { + String path = MobileUtil.getFilePath(StableUtils.pathJoin(MobileConstant.SCHEDULE, DingTalkConstants.DING_TALK), id); + if (WorkContext.getWorkResource().exist(path)) { + return path; + } else { + // 如果持久化路径没找到,就返回附件路径,两个原因:兼容不是在启动做的;持久化附件事件是异步的 + return getAttachmentPathById(id); + } + } + + public static String getAttachmentPathById(String attachId) { + String path = StringUtils.EMPTY; + if (StringUtils.isNotEmpty(attachId)) { + Attachment attach = AttachmentHelper.getAttachment(attachId); + if (attach != null) { + path = attach.getPath(); + } else { + FineLoggerFactory.getLogger().warn(String.format("获取%s附件结果为空!", attachId)); + } + } + + return path; + } + + private static DingTalkMessage createTextMessage(OutputDingTalk action) { + String content = action.getContent(); + return new DingTalkTextMessage(content); + } + + private static DingTalkMessage createLinkMessage(OutputDingTalk messageBody, Map map) { + OA oa = createOAObject(messageBody, new OA.Body(),map); + return new DingTalkOAMessage(oa); + } + private static OA createOAObject(OutputDingTalk messageBody, OA.Body body, Map map) { + String entryUrl = StringUtils.EMPTY; + String entryUrlPC = StringUtils.EMPTY; + if(StringUtils.isNotBlank(messageBody.getCustomizeLink())){ + entryUrl = messageBody.getCustomizeLink(); + entryUrlPC = messageBody.getCustomizeLink(); + }else{ + String taskName = CodeUtils.encodeURIComponent((String) map.get(ScheduleConstants.TASK_NAME)); + String path = CodeUtils.encodeURIComponent((String) map.get(ScheduleConstants.SAVE_DIRECTORY)); + path = path.replaceAll("\\+", "%20"); + String showType = (String) map.get(ScheduleConstants.SHOW_TYPE); + int taskType = (Integer) map.get(ScheduleConstants.TASK_TYPE); + String scheduleUsername = (String) map.get(ScheduleConstants.USERNAME); + String pcUrl = "/schedule/result?taskName=" + taskName + "&username=" + scheduleUsername + "&path=" + path + "&showType=" + showType + "&taskType=" + taskType; + String mobileUrl = "/url/mobile/schedule/result?taskName=" + taskName + "&username=" + scheduleUsername + "&path=" + path + "&showType=" + showType + "&taskType=" + taskType; + entryUrl = messageBody.getResultURL()+ mobileUrl; + entryUrlPC = messageBody.getResultURL()+ pcUrl; + } + + + OA.Head head = new OA.Head("#FFBBBBBB", ""); + String content = messageBody.getContent(); + String title = messageBody.getSubject(); + body.setContent(content); + body.setTitle(title); + return new OA(entryUrl, entryUrlPC,head, body); + } + + protected JSONObject createMessageBaseJSONObject() throws JSONException { + JSONObject jsonObject = JSONObject.create(); + jsonObject.put("msgtype", msgType); + return jsonObject; + } + + public abstract JSONObject createMessageJSONObject() throws JSONException; + + public abstract String getMessageType(); + + public String getMsgType() { + return msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkMessageType.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkMessageType.java new file mode 100644 index 0000000..a8af7e0 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkMessageType.java @@ -0,0 +1,24 @@ +package com.fr.plugin.yuyuan.dingding.bean.msg; + +import com.fr.decision.system.message.type.MessageType; +import com.fr.plugin.yuyuan.dingding.constant.DingTalkConstants; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkMessageType extends MessageType { + private static final long serialVersionUID = -9086829986481786437L; + public static final DingTalkMessageType KEY = new DingTalkMessageType(); + + public static final String FILE = "file"; + public static final String OA = "oa"; + public static final String LINK = "link"; + public static final String TEXT = "text"; + + @Override + public int toInteger() { + return DingTalkConstants.DINGTALK_MESSAGE_TYP; + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkOAMessage.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkOAMessage.java new file mode 100644 index 0000000..5df68cf --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkOAMessage.java @@ -0,0 +1,38 @@ +package com.fr.plugin.yuyuan.dingding.bean.msg; + +import com.fr.json.JSONException; +import com.fr.json.JSONObject; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkOAMessage extends DingTalkMessage { + + private OA oa; + + public DingTalkOAMessage(OA oa) { + super(); + this.oa = oa; + } + + public OA getOa() { + return oa; + } + + @Override + public String getMessageType() { + return DingTalkMessageType.OA; + } + + @Override + public JSONObject createMessageJSONObject() throws JSONException { + JSONObject jo = JSONObject.create(); + JSONObject message = createMessageBaseJSONObject(); + message.put("oa", oa.toJSONObject()); + jo.put("msg", message); + return jo; + } + +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkTextMessage.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkTextMessage.java new file mode 100644 index 0000000..bce18ee --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/DingTalkTextMessage.java @@ -0,0 +1,36 @@ +package com.fr.plugin.yuyuan.dingding.bean.msg; + +import com.fr.json.JSONException; +import com.fr.json.JSONObject; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkTextMessage extends DingTalkMessage { + + //必填 + private String content; + + public DingTalkTextMessage(String content) { + super(); + this.content = content; + } + + @Override + public String getMessageType() { + return DingTalkMessageType.TEXT; + } + + @Override + public JSONObject createMessageJSONObject() throws JSONException { + JSONObject jo = JSONObject.create(); + JSONObject message = createMessageBaseJSONObject(); + JSONObject text = JSONObject.create(); + text.put("content",content); + message.put("text", text); + jo.put("msg", message); + return jo; + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/OA.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/OA.java new file mode 100644 index 0000000..d7c33cb --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/bean/msg/OA.java @@ -0,0 +1,127 @@ +package com.fr.plugin.yuyuan.dingding.bean.msg; + +import com.fr.json.JSONException; +import com.fr.json.JSONObject; +import com.fr.stable.StringUtils; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class OA { + + //必选 + private String messageUrl; + private String messageUrlPC; + private Head head; + private Body body; + + public OA(String messageUrl, String messageUrlPC, Head head, Body body) { + this.messageUrl = messageUrl; + this.messageUrlPC = messageUrlPC; + this.head = head; + this.body = body; + } + + public String getMessageUrl() { + return messageUrl; + } + + public void setMessageUrl(String messageUrl) { + this.messageUrl = messageUrl; + } + + public String getMessageUrlPC() { + return messageUrlPC; + } + + public void setMessageUrlPC(String messageUrlPC) { + this.messageUrlPC = messageUrlPC; + } + + public static class Head { + //必选 + private String bgColor; + private String text; + + public Head(String bgColor, String text) { + this.bgColor = bgColor; + this.text = text; + } + + public String getBgColor() { + return bgColor; + } + + public void setBgColor(String bgColor) { + this.bgColor = bgColor; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + } + + public static class Body { + //可选 + private String title = StringUtils.EMPTY; + private String content = StringUtils.EMPTY; + private String image = StringUtils.EMPTY; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + } + + public JSONObject toJSONObject() throws JSONException { + JSONObject oa = JSONObject.create(); + oa.put("message_url", messageUrl); + oa.put("pc_message_url", messageUrlPC); + + JSONObject headObj = JSONObject.create(); + headObj.put("bgcolor", head.getBgColor()); + headObj.put("text", head.getText()); + oa.put("head", headObj); + + JSONObject bodyObj = JSONObject.create(); + if (body.getContent() != null) { + bodyObj.put("content", body.getContent()); + } + + if (body.getImage() != null) { + bodyObj.put("image", body.getImage()); + } + + if (body.getTitle() != null) { + bodyObj.put("title", body.getTitle()); + } + oa.put("body", bodyObj); + return oa; + } + +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/constant/DingTalkApiConstants.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/constant/DingTalkApiConstants.java new file mode 100644 index 0000000..05a23a4 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/constant/DingTalkApiConstants.java @@ -0,0 +1,31 @@ +package com.fr.plugin.yuyuan.dingding.constant; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkApiConstants { + + private DingTalkApiConstants(){ + + } + + public static final String KEY_DING_TALK_ERR_CODE = "errcode"; + public static final String KEY_DING_TALK_ERR_MSG = "errmsg"; + public static final String KEY_DING_TALK_ACCESS_TOKEN = "access_token"; + public static final String KEY_DING_TALK_TICKET = "ticket"; + + public static final int ERROR_CODE_UNKNOWN = -999; + public static final int ERROR_CODE_OK = 0; + public static final int ERROR_CODE_DEP_NOT_AUTH = 50004; + public static final int ERROR_CODE_IP_CONFIG_NOT_AVAILABLE = 60020; + public static final int ERROR_CODE_CHAT_GROUP_MESSAGE_FAIL = 34015; + + public static final String TYPE_FILE = "file"; + public static final String TYPE_IMAGE = "image"; + + public static final int MAX_LENGTH_OF_PUSH_MESSAGE_STRING = 4500; + + public static final int STATUS_CODE_SUCCESS = 200; +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/constant/DingTalkConstants.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/constant/DingTalkConstants.java new file mode 100644 index 0000000..cd52621 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/constant/DingTalkConstants.java @@ -0,0 +1,183 @@ +package com.fr.plugin.yuyuan.dingding.constant; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DingTalkConstants { + + private DingTalkConstants() { + + } + + public static final String DING_TALK = "dingtalk"; + + public static final long TERMINATE_DINGTALK = 64; + public static final int DINGTALK_PRIORITY_LEVEL = 998; + public static final String DINGTALK_PLUGIN_ID = "com.fr.plugin.dingtalk"; + public static final String HTML5_PLUGIN_ID = "com.fr.wei.plugin.h5reportnew"; + public static final String DINGTALK_START_UP_THREAD = "DingTalkStartUpThread"; + public static final String DINGTALK_AGENT_DATA_CHANGE_THREAD = "DingTalkAgentDataChangeThread"; + + public static double JS_TICKET_EXPIRE_TIME = 1.5 * 60 * 60 * 1000; //过期时间是2小时,每1个半小时请求一次 + public static double TOKEN_EXPIRE_TIME = 1.5 * 60 * 60 * 1000; + + + //插件中的请求的错误码的key值(注意与钉钉API中的错误码的key值区分) + public static final String KEY_PLUGIN_ERROR_CODE = "errorCode"; + public static final String KEY_PLUGIN_ERROR_MSG = "errorMsg"; + public static final String KEY_STATUS = "status"; + public static final String VALUE_SUCCESS = "success"; + + //错误码相关 + public static final int ERROR_CODE_OK = 0; + public static final int ERROR_CODE_EXPIRE = 11100016; + public static final int ERROR_CODE_VERSION_LOW = 11205010; + public static final int ERROR_CODE_DELETE_AGENT_FAIL = 11205011; + public static final int ERROR_CODE_SAVE_REPORT_SERVER_FAIL = 11205012; + public static final int ERROR_CODE_SAVE_AGENT_FAIL = 11205013; + public static final int ERROR_CODE_UPDATE_AGENT_FAIL = 11205014; + public static final int ERROR_CODE_SAVE_TIMING_TASK_FAIL = 11205015; + public static final int ERROR_CODE_ERROR_APP_KEY_APP_SECRET = 11205016; + public static final int ERROR_CODE_ERROR_APPKEY_ID_AGENT_ID = 11205017; + public static final int ERROR_CODE_DUPLICATE_AGENT_NAME = 11205018; + public static final int ERROR_CODE_SAVE_MATCH_METHOD_FAIL = 11205019; + public static final int ERROR_CODE_DUPLICATE_AGENT_ID = 11205020; + public static final int ERROR_CODE_SAVE_PROXY_SERVER_FAIL = 11205023; + public static final int ERROR_CODE_PROXY_SERVER_CONNECTED_FAIL = 11205024; + public static final int ERROR_CODE_ILLEGAL_PARAMETERS = 11205025; + public static final int ERROR_CODE_SAVE_USER_RELATION_FAIL = 11205026; + public static final int ERROR_CODE_LOGIN_FAIL = 11205027; + public static final int ERROR_CODE_GET_JSTICKET_FAIL = 11205028; + public static final int ERROR_CODE_TOKEN_EMPTY_ERR = 11205031; + public static final int ERROR_CODE_GET_REPORT_SERVER_FAIL = 11205035; + public static final int ERROR_CODE_IP_CONFIG_NOT_AVAILABLE = 11205036; + public static final int ERROR_CODE_NETWORK_INVALID = 11205037; + public static final int ERROR_CODE_LEVEL_SET_FAIL = 11205038; + public static final int ERROR_CODE_DOWNLOAD_LOG_FAIL = 11205039; + public static final int ERROR_CODE_MATCH_DINGTALK_USER_FAIL = 11205040; + public static final int ERROR_CODE_CREATE_CHAT_GROUP = 11205041; + + public static final int SCHEDULE_RESULT_LINK = 0; + + + public static class Suffix { + public static final String XLS = ".xls"; + public static final String XLSX = ".xlsx"; + public static final String PDF = ".pdf"; + public static final String DOC = ".doc"; + public static final String DOCX = ".docx"; + public static final String CPR = ".cpr"; + } + + public static class AttachType { + public static final int CPR = 0; + public static final int EXCEL_03 = 8; + public static final int EXCEL_07 = 1; + public static final int WORD = 4; + public static final int PDF = 2; + + } + + public static class DeviceType { + public static final String ANDROID = "android"; + public static final String ANDROID_PAD = "androidPad"; + public static final String IPAD = "iPad"; + public static final String IPHONE = "iPhone"; + public static final String UNKNOWN = "unknown"; + } + + public static class scheduleTaskType { + public static final int FR = 1; + public static final int NULL = 0; + public static final int BI = 2; + } + + + public static final int PERIOD_TIMING_TASK_EVERYDAY = 0; + public static final int PERIOD_TIMING_TASK_EVERYWEEK = 1; + + public static final int MAX_PUSH_FILE_SIZE = 10 * 1024 * 1024; + + + public static final int DINGTALK_PLATFORM_DEFAULT = 1; + public static final int DINGTALK_PLATFORM_REPORTLET = 2; + + public static final String DEPENT_HTML5_VERSION = "5.0.5"; + + public static class MessageType { + public static final int LINK = 1; + public static final String LINK_TYPE = "link"; + public static final int NEWS = 2; + public static final String NEWS_TYPE = "oa"; + public static final int FILE = 3; + public static final String FILE_TYPE = "file"; + public static final int TEXT = 4; + public static final String TEXT_TYPE = "text"; + public static final int UNKNOWN = 0; + } + + public static final int DINGTALK_MESSAGE_TYP = 5; + + public static final String DINGTALK_PNG = "/dingtalk.png"; + + public static final String SINGLE_LOGIN_TERMINAL = "&terminal=H5"; + public static final String SINGLE_LOGIN_DEVICE = "&__device__=iPhone"; + public static final String SINGLE_LOGIN_DEVICE_TYPE = "&deviceType=iPhone"; + public static final String DINGTALK_PUBLIC_URL_PATH = "/plugin/public/" + DINGTALK_PLUGIN_ID; + public static final String DINGTALK_SCHEDULE_URL = "/schedule/result"; + public static final String DINGTALK_ATTACH_PATH = "assets/temp_attach/"; + public static final String DINGTALK_SINGLE_LOGIN_URL = "/dingtalk/single/login"; + public static final String DINGTALK_SCHEDULE_URL_HEAD = "dingtalk://dingtalkclient/action/openapp?container_type=work_platform&redirect_type=jump"; + public static final String DINGTALK_JSAPI_PATH = "/com/fr/plugin/dingtalk/dist/js/dingtalk.custom.api.min.js"; + + public static final String MESSAGE_ORIGIN = "dingtalkhandpush"; + + public static final String DINGTALK_LOGGER = "com.fr.plugin.dingtalk"; + public static final String SCHEDULE = "schedule"; + public static final String LOGIN = "login"; + public static final String SYN_MEMBER = "syn_member"; + + public static final String FILE_APPENDER = "dingtalk_file_appender"; + public static final String CONSOLE_APPENDER = "dingtalk_console_appender"; + + public static final String LOG_NAME = "dingtalk.log"; + public static final String LOG_PATH = System.getProperty("LOG_HOME") + "/../logs/dingtalk/" + LOG_NAME; + public static final String LOG_DOWNLOAD_ZIP_NAME = "dingtalk_log.zip"; + public static final String LOG_DOWNLOAD_ZIP_KEY = "logs/"; + + public static final String DINGTALK_FILTER = "dingtalk_filter"; + + public static class MatchingFSWay { + public static final int MATCHING_USER_BY_DINGTALK_NUMBER = 0; // 根据钉钉工号匹配FS用户 + public static final int MATCHING_USER_BY_DINGTALK_MOBILE = 1; // 根据钉钉手机号匹配FS用户 + public static final int MATCHING_USER_MANUALLY = 2; // 手动匹配FS用户 + public static final int MATCHING_USER_BY_DATASET = 3; // 数据集匹配 + } + + public static final String PUSH_USER_SEPRATOR = ","; + + public static final String MODULE_ID = "DingTalkSystemOption"; + + public static final String SUFFIX_JPG = ".jpg"; + + public static final int AGENT_TYPE_VALID = 1; + public static final int AGENT_TYPE_TOKEN_EMPTY = 2; + + public static final int NONE_SELECT = -1; + public static final int MULTI_SELECT = 1; + public static final int ALL_SELECT = 2; + + public static final int ADDRESSEE_CHAT = 1; + + public static final String HELP_DOCUMENT_LINK = "https://help.fanruan.com/finereport/doc-view-3906.html"; + + public static final int MAX_OUTPUT_LOG_LENGTH = 128; + + public static final String MATCH_SUCCESS_USER_LIST = "match_success_user_list"; + public static final String MATCH_FAIL_USER_LIST = "match_fail_user_list"; + + public static final String SCHEDULE_SUCCESS_NUMBER = "success_number"; + public static final String SCHEDULE_FAIL_MESSAGE = "fail_message"; +} \ No newline at end of file diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/dao/OutputDingTalkDAO.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/dao/OutputDingTalkDAO.java new file mode 100644 index 0000000..eda5f6a --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/dao/OutputDingTalkDAO.java @@ -0,0 +1,21 @@ +package com.fr.plugin.yuyuan.dingding.dao; + +import com.fr.plugin.yuyuan.dingding.entity.OutputDingTalkEntity; +import com.fr.stable.db.dao.BaseDAO; +import com.fr.stable.db.session.DAOSession; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class OutputDingTalkDAO extends BaseDAO { + public OutputDingTalkDAO(DAOSession daoSession) { + super(daoSession); + } + + @Override + protected Class getEntityClass() { + return OutputDingTalkEntity.class; + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/entity/OutputDingTalkEntity.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/entity/OutputDingTalkEntity.java new file mode 100644 index 0000000..2682d3d --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/entity/OutputDingTalkEntity.java @@ -0,0 +1,154 @@ +package com.fr.plugin.yuyuan.dingding.entity; + +import com.fr.plugin.yuyuan.dingding.bean.OutputDingTalk; +import com.fr.schedule.base.entity.AbstractScheduleEntity; +import com.fr.stable.db.constant.EntityConstant; +import com.fr.stable.db.entity.TableAssociation; +import com.fr.third.javax.persistence.Column; +import com.fr.third.javax.persistence.Entity; +import com.fr.third.javax.persistence.Table; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +@Entity +@Table(name = "fine_dingding_output") +@TableAssociation(associated = true) +public class OutputDingTalkEntity extends AbstractScheduleEntity { + private static final String COLUMN_TERMINAL = "terminal"; + private static final String COLUMN_AGENTID = "agentId"; + private static final String COLUMN_SUBJECT = "subject"; + private static final String COLUMN_CONTENT = "content"; + private static final String COLUMN_LINK_OPEN_TYPE = "linkOpenType"; + private static final String COLUMN_CUSTOMIZE_LINK = "customizeLink"; + private static final String COLUMN_TYPE = "type"; + private static final String COLUMN_MEDIA_ID = "mediaId"; + private static final String COLUMN_ADDRESSEE = "addressee"; + private static final String COLUMN_CHAT_GROUPS = "chatGroups"; + + @Column(name = COLUMN_TERMINAL) + private int terminal = 32; + + @Column(name = COLUMN_AGENTID) + private String agentId = null; + + @Column(name = COLUMN_SUBJECT, length = EntityConstant.STRING_LONG_SIZE) + private String subject; + + @Column(name = COLUMN_CONTENT, length = EntityConstant.STRING_LONG_SIZE) + private String content; + + @Column(name = COLUMN_LINK_OPEN_TYPE) + private int linkOpenType = -1; + + @Column(name = COLUMN_CUSTOMIZE_LINK, length = EntityConstant.STRING_LONG_SIZE) + private String customizeLink; + + @Column(name = COLUMN_TYPE) + private int type; + + @Column(name = COLUMN_MEDIA_ID) + private String mediaId; + + @Column(name = COLUMN_ADDRESSEE) + private int[] addressee; + + @Column(name = COLUMN_CHAT_GROUPS, length = EntityConstant.STRING_LONG_SIZE) + private String[] chatGroups; + + @Override + public OutputDingTalk createBean() { + OutputDingTalk bean = new OutputDingTalk(); + bean.setId(this.getId()); + bean.setTerminal(this.getTerminal()); + bean.setSubject(this.getSubject()); + bean.setContent(this.getContent()); + bean.setLinkOpenType(this.getLinkOpenType()); + bean.setCustomizeLink(this.getCustomizeLink()); + bean.setType(this.getType()); + bean.setMediaId(this.getMediaId()); + return bean; + } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + public int getTerminal() { + return terminal; + } + + public void setTerminal(int terminal) { + this.terminal = terminal; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public int getLinkOpenType() { + return linkOpenType; + } + + public void setLinkOpenType(int linkOpenType) { + this.linkOpenType = linkOpenType; + } + + public String getCustomizeLink() { + return customizeLink; + } + + public void setCustomizeLink(String customizeLink) { + this.customizeLink = customizeLink; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public int[] getAddressee() { + return addressee; + } + + public void setAddressee(int[] addressee) { + this.addressee = addressee; + } + + public String[] getChatGroups() { + return chatGroups; + } + + public void setChatGroups(String[] chatGroups) { + this.chatGroups = chatGroups; + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/format/PNGOutputFormat.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/format/PNGOutputFormat.java new file mode 100644 index 0000000..396b8e6 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/format/PNGOutputFormat.java @@ -0,0 +1,40 @@ +package com.fr.plugin.yuyuan.dingding.format; + +import com.fr.io.exporter.ImageExporter; +import com.fr.main.workbook.ResultWorkBook; +import com.fr.schedule.extension.report.job.output.BaseOutputFormat; + +import java.io.OutputStream; +import java.util.List; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class PNGOutputFormat extends BaseOutputFormat { + public static final int CONVERT_TO_PNG = 64; + + public PNGOutputFormat() { + } + + @Override + public int getFormat() { + return CONVERT_TO_PNG; + } + + @Override + public String getFileSuffix() { + return ".png"; + } + + @Override + public boolean withParentPath() { + return true; + } + + @Override + public void flushWithParentPath(OutputStream var1, ResultWorkBook var2, String var3, final List var4) throws Exception { + new ImageExporter("png", 96).export(var1, var2); + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/js/FileDef.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/js/FileDef.java new file mode 100644 index 0000000..7f65949 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/js/FileDef.java @@ -0,0 +1,55 @@ +package com.fr.plugin.yuyuan.dingding.js; + +import com.fr.plugin.transform.ExecuteFunctionRecord; +import com.fr.web.struct.Component; +import com.fr.web.struct.Filter; +import com.fr.web.struct.browser.RequestClient; +import com.fr.web.struct.category.ScriptPath; +import com.fr.web.struct.category.StylePath; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class FileDef extends Component { + public static final FileDef KEY = new FileDef(); + private FileDef(){} + /** + * 返回需要引入的JS脚本路径 + * @param client 请求客户端描述 + * @return JS脚本路径 + */ + @Override + public ScriptPath script(RequestClient client ) { + //如果不需要就直接返回 ScriptPath.EMPTY + return ScriptPath.build("com/fr/plugin/yuyuan/dingding/theme.js"); + } + + /** + * 返回需要引入的CSS样式路径 + * @param client 请求客户端描述 + * @return CSS样式路径 + */ + @Override + public StylePath style(RequestClient client ) { + //如果不需要就直接返回 StylePath.EMPTY; + return StylePath.EMPTY; + } + + /** + * 通过给定的资源过滤器控制是否加载这个资源 + * @return 资源过滤器 + */ + @ExecuteFunctionRecord + @Override + public Filter filter() { + return new Filter(){ + @Override + public boolean accept() { + //任何情况下我们都在平台组件加载时加载我们的组件 + return true; + } + }; + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/js/JSCSSBridge.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/js/JSCSSBridge.java new file mode 100644 index 0000000..b353d8d --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/js/JSCSSBridge.java @@ -0,0 +1,28 @@ +package com.fr.plugin.yuyuan.dingding.js; + +import com.fr.decision.fun.impl.AbstractWebResourceProvider; +import com.fr.decision.web.MainComponent; +import com.fr.plugin.transform.FunctionRecorder; +import com.fr.web.struct.Atom; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +@FunctionRecorder +public class JSCSSBridge extends AbstractWebResourceProvider { + @Override + public Atom attach() { + //在平台主组件加载时添加我们自己的组件 + return MainComponent.KEY; + } + + + @Override + public Atom[] clients() { + return new Atom[]{ + FileDef.KEY, + }; + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/DesECBUtil.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/DesECBUtil.java new file mode 100644 index 0000000..c8b3459 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/DesECBUtil.java @@ -0,0 +1,66 @@ +package com.fr.plugin.yuyuan.dingding.util; + +import com.fr.third.org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class DesECBUtil { + /** + * 加密数据 + * + * @param encryptString + * @param encryptKey + * @return + * @throws Exception + */ + public static String encryptDES(String encryptString, String encryptKey) throws Exception { + Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(getKey(encryptKey), "DES")); + byte[] encryptedData = cipher.doFinal(encryptString.getBytes("UTF-8")); + return Base64.encodeBase64String(encryptedData); + } + + /** + * key 不足8位补位 + * + * @param + */ + public static byte[] getKey(String keyRule) { + Key key = null; + byte[] keyByte = keyRule.getBytes(); + // 创建一个空的八位数组,默认情况下为0 + byte[] byteTemp = new byte[8]; + // 将用户指定的规则转换成八位数组 + for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) { + byteTemp[i] = keyByte[i]; + } + key = new SecretKeySpec(byteTemp, "DES"); + return key.getEncoded(); + } + + /*** + * 解密数据 + * @param decryptString + * @param decryptKey + * @return + * @throws Exception + */ + + public static String decryptDES(String decryptString, String decryptKey) throws Exception { + byte[] sourceBytes = Base64.decodeBase64(decryptString); + Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(getKey(decryptKey), "DES")); + byte[] decoded = cipher.doFinal(sourceBytes); + return new String(decoded, "UTF-8"); + + } + +} + diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/HttpUtil.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/HttpUtil.java new file mode 100644 index 0000000..276030f --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/HttpUtil.java @@ -0,0 +1,132 @@ +package com.fr.plugin.yuyuan.dingding.util; + +import com.fr.general.PropertiesUtils; +import com.fr.io.utils.ResourceIOUtils; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.yuyuan.dingding.bean.msg.DingTalkMessage; +import com.fr.plugin.yuyuan.dingding.constant.DingTalkApiConstants; +import com.fr.plugin.yuyuan.dingding.constant.DingTalkConstants; +import com.fr.stable.StringUtils; +import com.fr.third.org.apache.http.NameValuePair; +import com.fr.third.org.apache.http.client.entity.UrlEncodedFormEntity; +import com.fr.third.org.apache.http.entity.ContentType; +import com.fr.third.org.apache.http.entity.mime.HttpMultipartMode; +import com.fr.third.org.apache.http.entity.mime.MultipartEntityBuilder; +import com.fr.third.org.apache.http.message.BasicNameValuePair; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class HttpUtil { + + + public static JSONObject uploadMedia(String path, String type) { + JSONObject result = null; + InputStream fileInputStream = ResourceIOUtils.read(path); + String fileName = ResourceIOUtils.getName(path); + // 定时调度图片没有后缀名,用钉钉上传文件接口以type=image的方式传会返回错误,这里伪造一个后缀 + fileName = addSuffixToScheduleImage(fileName, DingTalkConstants.SUFFIX_JPG); + if (fileInputStream == null || StringUtils.isEmpty(fileName)) { + FineLoggerFactory.getLogger().warn(String.format("%s路径下未能找到文件!", path)); + } else { + try { + MultipartEntityBuilder builder = MultipartEntityBuilder.create() + .setMode(HttpMultipartMode.BROWSER_COMPATIBLE) + .setContentType(ContentType.MULTIPART_FORM_DATA) + .addBinaryBody("media", ResourceIOUtils.read(path), ContentType.MULTIPART_FORM_DATA, new String(fileName.getBytes("UTF-8"), "ISO_8859_1")); + Map header = new HashMap(); + header.put("Content-type", "multipart/form-data"); + String res = HttpsUtil.doEntityPost(uploadMediaUrl(type),null,builder.build()); + result = new JSONObject(res); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(),e); + } + } + return result; + } + + public static String uploadMediaUrl(String type) { + return String.format(getBaseUrl() + "/addons/sjwdingtalk/msg/upload?yuyuan_syscode=%s&type=%s", getCode(), type); + } + + private static String getCode() { + String property = PropertiesUtils.getProperties("dingtalk").getProperty("yuyuan_syscode"); + return property; + } + + private static String getBaseUrl() { + String property = PropertiesUtils.getProperties("dingtalk").getProperty("host"); + return property; + } + + public static String addSuffixToScheduleImage(String fileName, String suffix) { + if (!StringUtils.contains(fileName, ".")) { + return fileName + suffix; + } + return fileName; + } + + public static boolean isOk(JSONObject result) { + return result != null && result.optInt("code", DingTalkApiConstants.ERROR_CODE_UNKNOWN) + ==1; + } + + public static String sendMessageUrl(String token) { + return getBaseUrl() + "/addons/sjwdingtalk/msg/send?yuyuan_syscode=" + token; + } + + public static String sendMessage(DingTalkMessage message, String userSet, String msg_type) throws IOException { + JSONObject object = message.createMessageJSONObject(); + String result = null; + try { + List params = new ArrayList(); + params.add(new BasicNameValuePair("msg_type", msg_type)); + params.add(new BasicNameValuePair("email_list", userSet)); + params.add(new BasicNameValuePair("msg", object.getJSONObject("msg").toString())); + UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(params, "UTF-8"); + Map header = new HashMap(); + header.put("Content-type", "application/x-www-form-urlencoded"); + result = HttpsUtil.doEntityPost(sendMessageUrl(getCode()),header,urlEncodedFormEntity); + FineLoggerFactory.getLogger().info("send message result is {}", result); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + throw e; + } + JSONObject res = new JSONObject(result); + return res.getJSONObject("data").getString("msg_id"); + } + + public static void getMessage(String msgid) throws Exception { + List params = new ArrayList(); + params.add(new BasicNameValuePair("msg_id", msgid)); + UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(params, "UTF-8"); + Map header = new HashMap(); + header.put("Content-type", "application/x-www-form-urlencoded"); + String result = null; + try { + result = HttpsUtil.doEntityPost(messageUrl(getCode()),header,urlEncodedFormEntity); + FineLoggerFactory.getLogger().info("query message result is {}", result); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + throw e; + } + JSONObject res = new JSONObject(result); + if (res.getInt("code") == 0) { + throw new Exception("get message error is" + res.getString("msg")); + } + } + + private static String messageUrl(String token) { + return getBaseUrl() + "/addons/sjwdingtalk/msg/query?yuyuan_syscode=" + token; + } +} diff --git a/推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/HttpsUtil.java b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/HttpsUtil.java new file mode 100644 index 0000000..f34d120 --- /dev/null +++ b/推送/src/main/java/com/fr/plugin/yuyuan/dingding/util/HttpsUtil.java @@ -0,0 +1,346 @@ +package com.fr.plugin.yuyuan.dingding.util; + +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.third.org.apache.http.HttpEntity; +import com.fr.third.org.apache.http.HttpResponse; +import com.fr.third.org.apache.http.HttpStatus; +import com.fr.third.org.apache.http.client.HttpClient; +import com.fr.third.org.apache.http.client.methods.HttpPost; +import com.fr.third.org.apache.http.config.Registry; +import com.fr.third.org.apache.http.config.RegistryBuilder; +import com.fr.third.org.apache.http.conn.socket.ConnectionSocketFactory; +import com.fr.third.org.apache.http.conn.socket.PlainConnectionSocketFactory; +import com.fr.third.org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import com.fr.third.org.apache.http.entity.StringEntity; +import com.fr.third.org.apache.http.impl.client.HttpClients; +import com.fr.third.org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import com.fr.third.org.apache.http.util.EntityUtils; + +import javax.net.ssl.*; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.security.cert.CertificateException; +import java.util.Iterator; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @Author fr.open + * @Date 2021/08/22 + * @Description + **/ +public class HttpsUtil { + + private static HostnameVerifier hv = new HostnameVerifier() { + @Override + public boolean verify(String urlHostName, SSLSession session) { + System.out.println("Warning: URL Host: " + urlHostName + " vs. " + + session.getPeerHost()); + return true; + } + }; + + /** + * 发送get请求 + * + * @param url + * @param param + * @param header + * @return + * @throws IOException + */ + public static String sendGet(String url, Map param, Map header) { + String result = ""; + BufferedReader in = null; + String urlNameString = url; + try { + if (param != null) { + urlNameString += "?"; + urlNameString += param.entrySet() + .stream() + .map(entry -> entry.getKey() + "=" + entry.getValue()) + .collect(Collectors.joining("&")); + } + + URL realUrl = new URL(urlNameString); + // 打开和URL之间的连接 + HttpURLConnection connection; + if (url.startsWith("https")) { + trustAllHttpsCertificates(); + HttpsURLConnection.setDefaultHostnameVerifier(hv); + connection = (HttpURLConnection) realUrl.openConnection(); + } else { + connection = (HttpURLConnection) realUrl.openConnection(); + } + //设置超时时间 + connection.setDoInput(true); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(15000); + // 设置通用的请求属性 + if (header != null) { + Iterator> it = header.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + System.out.println(entry.getKey() + ":::" + entry.getValue()); + connection.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + connection.setRequestProperty("accept", "*/*"); + connection.setRequestProperty("connection", "Keep-Alive"); + connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + // 建立实际的连接 + connection.connect(); + // 定义 BufferedReader输入流来读取URL的响应,设置utf8防止中文乱码 + in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8")); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + if (in != null) { + in.close(); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, "get url error ,url is:{},error is {}", urlNameString, e.getMessage()); + } + return result; + } + + public static String sendPost(String url, Map header, JSONObject body) { + PrintWriter out = null; + BufferedReader in = null; + String result = null; + String res = null; + try { + String urlNameString = url; + + URL realUrl = new URL(urlNameString); + // 打开和URL之间的连接 + HttpURLConnection conn; + if (url.startsWith("https")) { + trustAllHttpsCertificates(); + HttpsURLConnection.setDefaultHostnameVerifier(hv); + conn = (HttpURLConnection) realUrl.openConnection(); + } else { + conn = (HttpURLConnection) realUrl.openConnection(); + } + // 设置通用的请求属性 + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); +// conn.setRequestProperty("user-agent", +// "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); + if (header != null) { + header.forEach((k, v) -> { + conn.setRequestProperty(k, String.valueOf(v)); + }); + } + // 发送POST请求必须设置如下两行 + conn.setDoOutput(true); + conn.setDoInput(true); + //获取请求头 + + // 获取URLConnection对象对应的输出流 + out = new PrintWriter(conn.getOutputStream()); + // 发送请求参数 + if (body != null) { + FineLoggerFactory.getLogger().error("content data: {}", body.toString()); + FineLoggerFactory.getLogger().error("content cover data: {}", new String(body.toString().getBytes("UTF-8"), "UTF-8")); + out.print(new String(body.toString().getBytes("UTF-8"), "UTF-8")); + } + // flush输出流的缓冲 + out.flush(); + // 定义BufferedReader输入流来读取URL的响应 + in = new BufferedReader( + new InputStreamReader(conn.getInputStream())); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + res = result; + if (res.startsWith("null")) { + res = res.replace("null", ""); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + //使用finally块来关闭输出流、输入流 + finally { + try { + if (out != null) { + out.close(); + } + if (in != null) { + in.close(); + } + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + return res; + } + + + public static String doPost(String url, Map header, JSONObject json) { + HttpClient client = HttpClients.createDefault(); + if (url.startsWith("https")) { + SSLContext sslcontext = createIgnoreVerifySSL(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.INSTANCE) + .register("https", new SSLConnectionSocketFactory(sslcontext)) + .build(); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + HttpClients.custom().setConnectionManager(connManager); + client = HttpClients.custom().setConnectionManager(connManager).build(); + } + HttpPost post = new HttpPost(url); + post.setHeader("accept", "*/*"); + post.setHeader("connection", "Keep-Alive"); + post.setHeader("Content-Type", "application/json"); + if (header != null) { + header.forEach((k, v) -> { + post.setHeader(k, String.valueOf(v)); + }); + } + try { + StringEntity s = new StringEntity(json.toString(),"UTF-8"); + s.setContentEncoding("UTF-8"); + s.setContentType("application/json; charset=UTF-8");//发送json数据需要设置contentType + post.setEntity(s); + HttpResponse res = client.execute(post); + if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + String result = EntityUtils.toString(res.getEntity());// 返回json格式: + return result; + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(),e); + } + return null; + } + + + public static String doEntityPost(String url, Map header, HttpEntity entity) { + HttpClient client = HttpClients.createDefault(); + if (url.startsWith("https")) { + SSLContext sslcontext = createIgnoreVerifySSL(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.INSTANCE) + .register("https", new SSLConnectionSocketFactory(sslcontext)) + .build(); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + HttpClients.custom().setConnectionManager(connManager); + client = HttpClients.custom().setConnectionManager(connManager).build(); + } + HttpPost post = new HttpPost(url); + post.setHeader("accept", "*/*"); + post.setHeader("connection", "Keep-Alive"); + if (header != null) { + header.forEach((k, v) -> { + post.setHeader(k, String.valueOf(v)); + }); + } + try { + post.setEntity(entity); + HttpResponse res = client.execute(post); + if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + String result = EntityUtils.toString(res.getEntity());// 返回json格式: + return result; + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(),e); + } + return null; + } + + private static void trustAllHttpsCertificates() throws Exception { + TrustManager[] trustAllCerts = new TrustManager[1]; + TrustManager tm = new miTM(); + trustAllCerts[0] = tm; + SSLContext sc = SSLContext.getInstance("SSL", "SunJSSE"); + sc.init(null, trustAllCerts, null); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + } + + + /** + * encode url by UTF-8 + * + * @param url url before encoding + * @return url after encoding + */ + public static String encodeUrl(String url) { + String eurl = url; + try { + eurl = URLEncoder.encode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + } + return eurl; + } + + private static class miTM implements TrustManager, + X509TrustManager { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + public boolean isServerTrusted( + java.security.cert.X509Certificate[] certs) { + return true; + } + + public boolean isClientTrusted( + java.security.cert.X509Certificate[] certs) { + return true; + } + + @Override + public void checkServerTrusted( + java.security.cert.X509Certificate[] certs, String authType) + throws CertificateException { + return; + } + + @Override + public void checkClientTrusted( + java.security.cert.X509Certificate[] certs, String authType) + throws CertificateException { + return; + } + } + + public static SSLContext createIgnoreVerifySSL() { + try { + SSLContext sc = SSLContext.getInstance("SSLv3"); + + // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法 + X509TrustManager trustManager = new X509TrustManager() { + @Override + public void checkClientTrusted( + java.security.cert.X509Certificate[] paramArrayOfX509Certificate, + String paramString) throws CertificateException { + } + + @Override + public void checkServerTrusted( + java.security.cert.X509Certificate[] paramArrayOfX509Certificate, + String paramString) throws CertificateException { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + + sc.init(null, new TrustManager[]{trustManager}, null); + return sc; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return null; + } +} diff --git a/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk.properties b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk.properties new file mode 100644 index 0000000..92d8203 --- /dev/null +++ b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk.properties @@ -0,0 +1,165 @@ +Dec-Module-DingTalk_Manager=Dec-Module-DingTalk_Manager +Dec-DingTalk_Basic=Dec-DingTalk_Basic +Dec-DingTalk_Recive_Data_URL=Dec-DingTalk_Recive_Data_URL +Dec-DingTalk_Corp_ID=Dec-DingTalk_Corp_ID +Dec-DingTalk_Secret=Dec-DingTalk_Secret +Dec-DingTalk_Member_Management=Dec-DingTalk_Member_Management +Dec-DingTalk_User-Same-With-FS=Dec-DingTalk_User-Same-With-FS +Dec-DingTalk_Mobile-Same-With-FS=Dec-DingTalk_Mobile-Same-With-FS +Dec-DingTalk_Manual-Matching-FS=Dec-DingTalk_Manual-Matching-FS +Dec-DingTalk_Custom-Matching-FS=Dec-DingTalk_Custom-Matching-FS +Dec-DingTalk_UserID=Dec-DingTalk_UserID +Dec-DingTalk_DecUserName=Dec-DingTalk_DecUserName +Dec-DingTalk_Name=Dec-DingTalk_Name +Dec-DingTalk_Department=Dec-DingTalk_Department +Dec-DingTalk_User_Job_Name=Dec-DingTalk_User_Job_Name +Dec-Schedule-Notification_DingTalk=Dec-Schedule-Notification_DingTalk +Dec-Schedule-Notification_DingTalk_CorpID=Dec-Schedule-Notification_DingTalk_CorpID +Dec-Schedule-Notification_DingTalk_Users=Dec-Schedule-Notification_DingTalk_Users +Dec-Schedule-Notification_DingTalk_DepID=Dec-Schedule-Notification_DingTalk_DepID +Dec-Schedule-Notification_DingTalk_Content=Dec-Schedule-Notification_DingTalk_Content +Dec-Schedule-Notification_DingTalk_WithLink=Dec-Schedule-Notification_DingTalk_WithLink +Dec-Schedule_Mobile-Push-DingTalkId-Not-Null=Dec-Schedule_Mobile-Push-DingTalkId-Not-Null +Dec-DingTalk_UrlHint=Dec-DingTalk_UrlHint +Dec-DingTalk_Token_Path=Dec-DingTalk_Token_Path +Dec-DingTalk_Refresh_User=Dec-DingTalk_Refresh_User +Dec-DingTalk_Mobile=Dec-DingTalk_Mobile +Dec-DingTalk_Matching_Way=Dec-DingTalk_Matching_Way +Dec-DingTalk_Hint=Dec-DingTalk_Hint +Dec-DingTalk_Loading=Dec-DingTalk_Loading +Dec-DingTalk_Mobile_Not_Supported=Dec-DingTalk_Mobile_Not_Supported +Dec-DingTalk_Mobile-Push-DingTalk-Terminal=DingTalk +Dec-DingTalk_Addressee_Chat_Group=Dec-DingTalk_Addressee_Chat_Group +Dec-DingTalk_Addressee_Chat_Group_Disable_Tip=Dec-DingTalk_Addressee_Chat_Group_Disable_Tip +Dec-DingTalk_Mobile-Push-DingTalk-AgentId=AgentID +Dec-DingTalk_Expired_Error=Dec-DingTalk_Expired_Error +Dec-DingTalk_Expired_Solution=Dec-DingTalk_Expired_Solution +Dec-DingTalk_Agent-Management=Dec-DingTalk_Agent-Management +Dec-DingTalk_Member-Management=Dec-DingTalk_Member-Management +Dec-DingTalk_Agent-Config=Dec-DingTalk_Agent-Config +Dec-DingTalk_Agent-Name=Dec-DingTalk_Agent-Name +Dec-DingTalk_Agent-Id=Dec-DingTalk_Agent-Id +Dec-DingTalk_Organizational-Structure=Dec-DingTalk_Organizational-Structure +Dec-DingTalk_Tag=Dec-DingTalk_Tag +Dec-DingTalk_Server=Dec-DingTalk_Server +Dec-DingTalk_Save=Dec-DingTalk_Save +Dec-DingTalk_Start_With_Http=Dec-DingTalk_Start_With_Http +Dec-DingTalk_Server_Url=Dec-DingTalk_Server_Url +Dec-DingTalk_Server_Tip=Dec-DingTalk_Server_Tip +Dec-DingTalk_Enterprise-DingDing=Dec-DingTalk_Enterprise-DingDing +Dec-DingTalk_New-Agent=Dec-DingTalk_New-Agent +Dec-DingTalk_Non-Adapted-Agent=Dec-DingTalk_Non-Adapted-Agent +Dec-DingTalk_Modify-Agent=Dec-DingTalk_Modify-Agent +Dec-DingTalk_DeleteAgent-Confirm-Popup=Dec-DingTalk_DeleteAgent-Confirm-Popup +Dec-DingTalk_Confirm=Dec-DingTalk_Confirm +Dec-DingTalk_Cancel=Dec-DingTalk_Cancel +Dec-DingTalk_Save-Agent-Fail=Dec-DingTalk_Save-Agent-Fail +Dec-DingTalk_Unknown-Agent=Dec-DingTalk_Unknown-Agent +Dec-DingTalk_Agent-Name-Exist=Dec-DingTalk_Agent-Name-Exist +Dec-DingTalk_Match-Way=Dec-DingTalk_Match-Way +Dec-DingTalk_Match-Setting=Dec-DingTalk_Match-Setting +Dec-DingTalk_DataSet=Dec-DingTalk_DataSet +Dec-DingTalk_Address-Book=Dec-DingTalk_Address-Book +Dec-DingTalk_Member-Update=Dec-DingTalk_Member-Update +Dec-DingTalk_Set-Update=Dec-DingTalk_Set-Update +Dec-DingTalk_Not-Null=Dec-DingTalk_Not-Null +Dec-DingTalk_Start-Update=Dec-DingTalk_Start-Update +Dec-DingTalk_Per=Dec-DingTalk_Per +Dec-DingTalk_Day=Dec-DingTalk_Day +Dec-DingTalk_Week=Dec-DingTalk_Week +Dec-DingTalk_Monday=Dec-DingTalk_Monday +Dec-DingTalk_Tuesday=Dec-DingTalk_Tuesday +Dec-DingTalk_Wednesday=Dec-DingTalk_Wednesday +Dec-DingTalk_Thursday=Dec-DingTalk_Thursday +Dec-DingTalk_Friday=Dec-DingTalk_Friday +Dec-DingTalk_Saturday=Dec-DingTalk_Saturday +Dec-DingTalk_Sunday=Dec-DingTalk_Sunday +Dec-DingTalk_Hour=Dec-DingTalk_Hour +Dec-DingTalk_Minute=Dec-DingTalk_Minute +Dec-DingTalk_Update-Once=Dec-DingTalk_Update-Once +Dec-DingTalk_Illegal=Dec-DingTalk_Illegal +Dec-DingTalk_Proxy=Dec-DingTalk_Proxy +Dec-DingTalk_Proxy_Address=Dec-DingTalk_Proxy_Address +Dec-DingTalk_Proxy_Address_Tip=Dec-DingTalk_Proxy_Address_Tip +Dec-DingTalk_Test_And_Save-Proxy-Address=Dec-DingTalk_Test_And_Save-Proxy-Address +Dec-DingTalk_Start-With-Http=Dec-DingTalk_Start-With-Http +Dec-DingTalk_Test-Connection=Dec-DingTalk_Test-Connection +Dec-DingTalk_Connection-Success=Dec-DingTalk_Connection-Success +Dec-DingTalk_Connection-Fail=Dec-DingTalk_Connection-Fail +Dec-DingTalk_Unknown-Agent-Id=Dec-DingTalk_Unknown-Agent-Id +Dec-DingTalk_Delete-Agent-Fail=Dec-DingTalk_Delete-Agent-Fail +Dec-DingTalk_Agent-Id-Exist=Dec-DingTalk_Agent-Id-Exist +Dec-DingTalk_Save-ReportServer-Url-Fail=Dec-DingTalk_Save-ReportServer-Url-Fail +Dec-DingTalk_Save-Timing-Task-Fail=Dec-DingTalk_Save-Timing-Task-Fail +Dec-DingTalk_Error-AppKey-And-AppSecret=Dec-DingTalk_Error-AppKey-And-AppSecret +Dec-DingTalk_Error-AppKey-And-AgentId=Dec-DingTalk_Error-AppKey-And-AgentId +Dec-DingTalk_Duplicate-Agent-Name=Dec-DingTalk_Duplicate-Agent-Name +Dec-DingTalk_Save-Match-Method-Fail=Dec-DingTalk_Save-Match-Method-Fail +Dec-DingTalk_Duplicate-Agent-Id=Dec-DingTalk_Duplicate-Agent-Id +Dec-DingTalk_Save-Proxy-Server-Fail=Dec-DingTalk_Save-Proxy-Server-Fail +Dec-DingTalk_Connect-Proxy-Server-Fail=Dec-DingTalk_Connect-Proxy-Server-Fail +Dec-DingTalk_NetWork-Anomaly=Dec-DingTalk_NetWork-Anomaly +Dec-DingTalk_Create-DingTalk-Url=Dec-DingTalk_Create-DingTalk-Url +Dec-DingTalk_Platform-Page=Dec-DingTalk_Platform_Page +Dec-DingTalk_Platform-Report=Dec-DingTalk_Platform-Report +Dec-DingTalk_Platform=Dec-DingTalk_Platform +Dec-DingTalk_Parameter_Setting=Dec-DingTalk_Parameter_Setting +Dec-DingTalk_Create-Url=Dec-DingTalk_Create-Url +Dec-DingTalk_DingTalk_Url=Dec-DingTalk_DingTalk_Url +Dec-DingTalk_Copy-Url=Dec-DingTalk_Copy-Url +Dec-DingTalk_Copy-Success=Dec-DingTalk_Copy-Success +Dec-DingTalk_Input-Hint=Dec-DingTalk_Input-Hint +Dec-DingTalk_Save-User-Relation-Fail=Dec-DingTalk_Save-User-Relation-Fail +BI-Basic_Search=BI-Basic_Search +Dec-DingTalk_Match-Way-Not-Null=Dec-DingTalk_Match-Way-Not-Null +Dec-DingTalk_Not-Select=Dec-DingTalk_Not-Select +Dec-DingTalk_Tip-Get-ReportServer-Url-Fail=Dec-DingTalk_Tip-Get-ReportServer-Url-Fail +Dec-DingTalk_Create-Agent-Tip=Dec-DingTalk_Create-Agent-Tip +Dec-DingTalk_IP-Config-Not-Available=Dec-DingTalk_IP-Config-Not-Available +Dec-DingTalk_NetWork-Invalid=Dec-DingTalk_NetWork-Invalid +Dec-DingTalk_Not_Trusted_Domain_Error=Dec-DingTalk_Not_Trusted_Domain_Error +Dec-DingTalk_Not_Trusted_Domain_Exception=Dec-DingTalk_Not_Trusted_Domain_Exception +Dec-DingTalk_Debugger-Set-Level=Dec-DingTalk_Debugger-Set-Level +Dec-DingTalk_Debugger-Level=Dec-DingTalk_Debugger-Level +Dec-DingTalk_Debugger-Parameter-List=Dec-DingTalk_Debugger-Parameter-List +Dec-DingTalk_Debugger-Content=Dec-DingTalk_Debugger-Content +Dec-DingTalk_Debugger-Type-Get-Access-Token=Dec-DingTalk_Debugger-Type-Get-Access-Token +Dec-DingTalk_Debugger-Type-Check-Ip=Dec-DingTalk_Debugger-Type-Check-Ip +Dec-DingTalk_Debugger-Start-Check=Dec-DingTalk_Debugger-Start-Check +Dec-DingTalk_Debugger-Show-Result=Dec-DingTalk_Debugger-Show-Result +Dec-DingTalk_Debugger-Type-Check-Request-Time=Dec-DingTalk_Debugger-Type-Check-Request-Time +Dec-DingTalk_Debugger-Type-Check-Request-Time-Result=Dec-DingTalk_Debugger-Type-Check-Request-Time-Result +Dec-DingTalk_Debugger-Tip-Curl-Invalid=Dec-DingTalk_Debugger-Tip-Curl-Invalid +Dec-DingTalk_Debugger-DownLoad_Log=Dec-DingTalk_Debugger-DownLoad_Log +Dec-DingTalk_Click-To-Download=Dec-DingTalk_Click-To-Download +Dec-DingTalk_Download-Fail=Dec-DingTalk_Download-Fail +Dec-DingTalk_Not_Null=Dec-DingTalk_Not_Null +Dec-DingTalk_ErrorDetail=Dec-DingTalk_ErrorDetail +Dec-DingTalk_Debugger-Check-Ip-Result=Dec-DingTalk_Debugger-Check-Ip-Result +Dec-DingTalk_Debugger-Get-Token=Dec-DingTalk_Debugger-Get-Token +Dec-DingTalk_Agent_Deleted_Tip=Dec-DingTalk_Agent_Deleted_Tip +Dec-DingTalk_Parse_Parameters=Dec-DingTalk_Parse_Parameters +Dec-DingTalk_Parse_Parameters_Tip=Dec-DingTalk_Parse_Parameters_Tip +Dec-DingTalk_Enterprise_Agent=Dec-DingTalk_Enterprise_Agent +Dec-DingTalk_Chatgroup_Name=Dec-DingTalk_Chatgroup_Name +Dec-DingTalk_Chat_Group=Dec-DingTalk_Chat_Group +Dec-DingTalk_New_Chat_Group=Dec-DingTalk_New_Chat_Group +Dec-DingTalk_Delete_ChatGroup_Confirm=Dec-DingTalk_Delete_ChatGroup_Confirm +Dec-DingTalk_Chat_Group_Member_Tip=Dec-DingTalk_Chat_Group_Member_Tip +Dec-DingTalk_Chat_Group_Leader=Dec-DingTalk_Chat_Group_Leader +Dec-DingTalk_Chat_Group_Member=Dec-DingTalk_Chat_Group_Member +Dec-DingTalk_New_Chat_Group_Tip1=Dec-DingTalk_New_Chat_Group_Tip1 +Dec-DingTalk_New_Chat_Group_Tip2=Dec-DingTalk_New_Chat_Group_Tip2 +Dec-DingTalk_New_Chat_Group_Message=Dec-DingTalk_New_Chat_Group_Message +Dec-DingTalk_Common_Error_Tip=Dec-DingTalk_Common_Error_Tip +Dec-DingTalk_Chat_Group_Name_Length_Tip=Dec-DingTalk_Chat_Group_Name_Length_Tip +Dec-DingTalk_Create-Chat-Group-Fail=Dec-DingTalk_Create-Chat-Group-Fail +Dec-DingTalk_Output_User_Empty=Dec-DingTalk_Output_User_Empty +Dec-DingTalk_Message_Agent=Dec-DingTalk_Message_Agent +Dec-DingTalk_Message_Group=Dec-DingTalk_Message_Group +Dec-DingTalk_DingTalk=Dec-DingTalk_DingTalk +Dec-DingTalk_Output_User_Fail_Partly_Header=Dec-DingTalk_Output_User_Fail_Partly_Header +Dec-DingTalk_Output_User_Fail_Partly_Tip=Dec-DingTalk_Output_User_Fail_Partly_Tip +Dec-DingTalk_Output_Group_Fail_Partly_Header=Dec-DingTalk_Output_Group_Fail_Partly_Header +Dec-DingTalk_Output_Group_Fail_Partly_Tip=Dec-DingTalk_Output_Group_Fail_Partly_Tip +Dec-DingTalk_User_Match_Dec_User_Fail=Dec-DingTalk_User_Match_Dec_User_Fail diff --git a/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_en_US.properties b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_en_US.properties new file mode 100644 index 0000000..894eb9b --- /dev/null +++ b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_en_US.properties @@ -0,0 +1,165 @@ +Dec-Module-DingTalk_Manager=DingTalk Management +Dec-DingTalk_Basic=Basic +Dec-Schedule-Notification_DingTalk=Push DingTalk Message +Dec-Schedule-Notification_DingTalk_CorpID=App Agent ID\: +Dec-Schedule-Notification_DingTalk_Users=DingTalk Users\: +Dec-Schedule-Notification_DingTalk_DepID=Department ID\: +Dec-Schedule-Notification_DingTalk_Content=Message\: +Dec-Schedule-Notification_DingTalk_WithLink=Cpr Link +Dec-Schedule_Mobile-Push-DingTalkId-Not-Null=Please set which DingTalk app to push. +Dec-DingTalk_Recive_Data_URL=Recive Data Url +Dec-DingTalk_Corp_ID=DingTalk Corp ID +Dec-DingTalk_Secret=Management group document key +Dec-DingTalk_Member_Management=DingTalk member management +Dec-DingTalk_User-Same-With-FS=matching FS user according to the job number +Dec-DingTalk_Mobile-Same-With-FS=matching FS user according to the phone number +Dec-DingTalk_Manual-Matching-FS=matching FS user manually +Dec-DingTalk_Custom-Matching-FS=custom matching +Dec-DingTalk_UserID=DingTalk Member ID +Dec-DingTalk_DecUserName=User name +Dec-DingTalk_Name=Name +Dec-DingTalk_Department=DingTalk Department +Dec-DingTalk_UrlHint=Server Url\: +Dec-DingTalk_User_Job_Name=DingTalk Job Number +Dec-DingTalk_Token_Path=Token Path +Dec-DingTalk_Refresh_User=Refresh +Dec-DingTalk_Mobile=DingTalk member mobile +Dec-DingTalk_Matching_Way=The matching way to FS user +Dec-DingTalk_Hint=Hint +Dec-DingTalk_Loading=Loading users... +Dec-DingTalk_Mobile_Not_Supported=The html5 report does not support matching FS user by mobile, please upgrade your html5 plugin +Dec-DingTalk_Mobile-Push-DingTalk-Terminal=DingTalk +Dec-DingTalk_Addressee_Chat_Group=Push to DingTalk chat group +Dec-DingTalk_Addressee_Chat_Group_Disable_Tip=If the results are generated separately according to the users in the default user group, the dingtalk group cannot be notified +Dec-DingTalk_Mobile-Push-DingTalk-AgentId=AgentID +Dec-DingTalk_Expired_Error=Error Code\: 11100016 You are using unregistered function--DingTalk integration +Dec-DingTalk_Expired_Solution=DingTalk plugin is not registered. If necessary, please contact sales. +Dec-DingTalk_Agent-Management=Application managementaa +Dec-DingTalk_Member-Management=Member management +Dec-DingTalk_Agent-Config=Application shortcut configuration +Dec-DingTalk_Agent-Name=Name +Dec-DingTalk_Agent-Id=AgentID +Dec-DingTalk_Organizational-Structure=organizational structure +Dec-DingTalk_Tag=Tag +Dec-DingTalk_Server=Server +Dec-DingTalk_Save=Save +Dec-DingTalk_Start_With_Http=The server address must begin with HTTP or HTTPS +Dec-DingTalk_Server_Url=Server address +Dec-DingTalk_Server_Tip=1.This address is the address of the application server where fansoft is to access the proxy server, that is, the forward proxy address, so that fansoft application server can access the external spike server through the proxy server;\n2.The address format is http://domain name: Port +Dec-DingTalk_Enterprise-DingDing=Enterprise dingding +Dec-DingTalk_New-Agent=New dingtalk application +Dec-DingTalk_Non-Adapted-Agent=Prompt: Please confirm whether the application of ID is correct +Dec-DingTalk_Modify-Agent=Modified dingtalk application +Dec-DingTalk_DeleteAgent-Confirm-Popup=Determine to delete the enterprise dingtalk application +Dec-DingTalk_Confirm=Confirm +Dec-DingTalk_Cancel=Cancel +Dec-DingTalk_Save-Agent-Fail=Save agent fail +Dec-DingTalk_Unknown-Agent=Network anomaly or please confirm that the CorpId and Secret that are currently used are correct. +Dec-DingTalk_Agent-Name-Exist=The application name has already existed +Dec-DingTalk_Match-Way=Matching method +Dec-DingTalk_Match-Setting=Matching settings +Dec-DingTalk_DataSet=Data set +Dec-DingTalk_Address-Book=Dingtalk address book +Dec-DingTalk_Member-Update=Refresh +Dec-DingTalk_Set-Update=Setting auto update +Dec-DingTalk_Not-Null=Not allowed to be empty +Dec-DingTalk_Start-Update=Enable automatic update +Dec-DingTalk_Per=Per +Dec-DingTalk_Day=Day +Dec-DingTalk_Week=Week +Dec-DingTalk_Monday=Monday +Dec-DingTalk_Tuesday=Tuesday +Dec-DingTalk_Wednesday=Wednesday +Dec-DingTalk_Thursday=Thursday +Dec-DingTalk_Friday=Friday +Dec-DingTalk_Saturday=Saturday +Dec-DingTalk_Sunday=Sunday +Dec-DingTalk_Hour=Hour +Dec-DingTalk_Minute=Minute +Dec-DingTalk_Update-Once=to update once +Dec-DingTalk_Illegal=Illegal +Dec-DingTalk_Proxy=Dingtalk proxy jump +Dec-DingTalk_Proxy_Address=Proxy address +Dec-DingTalk_Proxy_Address_Tip=1.This address will be used to generate platform single point links, template single point links, and push result links in quick configuration;\n2.This address needs to be accessible through the Internet. The address format is http://Domain Name: port/decision or https://domain name: port/decision. Please save after configuration +Dec-DingTalk_Test_And_Save-Proxy-Address= +Dec-DingTalk_Start-With-Http=The server address must begin with HTTP or HTTPS +Dec-DingTalk_Test-Connection=Test the connection... +Dec-DingTalk_Connection-Success=Connection success +Dec-DingTalk_Connection-Fail=Connection failed +Dec-DingTalk_Unknown-Agent-Id=Incorrect application of ID +Dec-DingTalk_Delete-Agent-Fail=Delete application failure +Dec-DingTalk_Agent-Id-Exist=The application of ID has already existed +Dec-DingTalk_Save-ReportServer-Url-Fail=Save server address failure +Dec-DingTalk_Save-Timing-Task-Fail=Save time task failure +Dec-DingTalk_Error-AppKey-And-AppSecret=Please verify that the AppKey and AppSecret currently used are correct. +Dec-DingTalk_Error-AppKey-And-AgentId=Please confirm whether the current application ID and AppKey is corresponding +Dec-DingTalk_Duplicate-Agent-Name=The application name has already existed +Dec-DingTalk_Save-Match-Method-Fail=Storage members manage configuration information failure +Dec-DingTalk_Duplicate-Agent-Id=The application of ID has already existed +Dec-DingTalk_Save-Proxy-Server-Fail=Save the proxy server failure +Dec-DingTalk_Connect-Proxy-Server-Fail=Test connection failure of nail proxy server +Dec-DingTalk_NetWork-Anomaly=Network exception, please check the network configuration +Dec-DingTalk_Create-DingTalk-Url=Generating DingTalk links +Dec-DingTalk_Platform-Page=Link page +Dec-DingTalk_Platform-Report=A single model +Dec-DingTalk_Platform=Decision platform +Dec-DingTalk_Parameter_Setting=Set Parameter +Dec-DingTalk_Create-Url=Generating link +Dec-DingTalk_DingTalk_Url=DingTalk link +Dec-DingTalk_Copy-Url=Copy +Dec-DingTalk_Copy-Success=Replicating success +Dec-DingTalk_Input-Hint=Please enter +Dec-DingTalk_Save-User-Relation-Fail=Manual matching failure +BI-Basic_Search=search +Dec-DingTalk_Match-Way-Not-Null=Matching settings can not be empty +Dec-DingTalk_Not-Select=No select +Dec-DingTalk_Tip-Get-ReportServer-Url-Fail=Please configure the server address +Dec-DingTalk_Create-Agent-Tip=If there is no AppKey, please fill in CorpId and CorpSecret in Appkey and AppSecret respectively. +Dec-DingTalk_IP-Config-Not-Available=Access IP is not on the whitelist +Dec-DingTalk_NetWork-Invalid=Network anomaly +Dec-DingTalk_Not_Trusted_Domain_Error=Error code: 11205040, the redirectUrl domain name is inconsistent with the background configuration +Dec-DingTalk_Not_Trusted_Domain_Exception=Check whether the domain name and report server address are consistent +Dec-DingTalk_Debugger-Set-Level= +Dec-DingTalk_Debugger-Level= +Dec-DingTalk_Debugger-Parameter-List= +Dec-DingTalk_Debugger-Content= +Dec-DingTalk_Debugger-Type-Get-Access-Token= +Dec-DingTalk_Debugger-Type-Check-Ip= +Dec-DingTalk_Debugger-Start-Check= +Dec-DingTalk_Debugger-Show-Result= +Dec-DingTalk_Debugger-Type-Check-Request-Time=Test request time consuming +Dec-DingTalk_Debugger-Type-Check-Request-Time-Result=Detection result +Dec-DingTalk_Debugger-Tip-Curl-Invalid=Tip: if the server system is windows, you need to install curl tool to support detection +Dec-DingTalk_Debugger-DownLoad_Log=Download log +Dec-DingTalk_Click-To-Download=Click To Download +Dec-DingTalk_Download-Fail=Download failed +Dec-DingTalk_Not_Null= +Dec-DingTalk_ErrorDetail= +Dec-DingTalk_Debugger-Check-Ip-Result= +Dec-DingTalk_Debugger-Get-Token= +Dec-DingTalk_Agent_Deleted_Tip= +Dec-DingTalk_Parse_Parameters= +Dec-DingTalk_Parse_Parameters_Tip= +Dec-DingTalk_Enterprise_Agent=DingTalk agent +Dec-DingTalk_Chatgroup_Name=DingTalk chat group name +Dec-DingTalk_Chat_Group=DingTalk chat group +Dec-DingTalk_New_Chat_Group=Create DingTalk chat group +Dec-DingTalk_Delete_ChatGroup_Confirm=Confirm delete? +Dec-DingTalk_Chat_Group_Member_Tip=No less than 2 person except group leader +Dec-DingTalk_Chat_Group_Leader=Group leader +Dec-DingTalk_Chat_Group_Member=Group member +Dec-DingTalk_New_Chat_Group_Tip1= +Dec-DingTalk_New_Chat_Group_Tip2= +Dec-DingTalk_New_Chat_Group_Message=You have joined the group chat +Dec-DingTalk_Common_Error_Tip=An error occurred. The error code is: +Dec-DingTalk_Chat_Group_Name_Length_Tip=The group name is limited to 20 characters +Dec-DingTalk_Create-Chat-Group-Fail=Failed to create dingtalk group +Dec-DingTalk_Output_User_Empty= +Dec-DingTalk_Message_Agent= +Dec-DingTalk_Message_Group= +Dec-DingTalk_DingTalk= +Dec-DingTalk_Output_User_Fail_Partly_Header= +Dec-DingTalk_Output_User_Fail_Partly_Tip= +Dec-DingTalk_Output_Group_Fail_Partly_Header= +Dec-DingTalk_Output_Group_Fail_Partly_Tip= +Dec-DingTalk_User_Match_Dec_User_Fail= diff --git a/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_ja_JP.properties b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_ja_JP.properties new file mode 100644 index 0000000..4112a23 --- /dev/null +++ b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_ja_JP.properties @@ -0,0 +1,165 @@ +Dec-Module-DingTalk_Manager=\u30DE\u30A4\u30AF\u30ED\u4FE1\u7BA1\u7406 +Dec-DingTalk_Basic=\u57FA\u672C\u60C5\u5831 +Dec-Schedule-Notification_DingTalk=\u30D7\u30C3\u30B7\u30E5\u9489\u9489\u30CB\u30E5\u30FC\u30B9 +Dec-Schedule-Notification_DingTalk_CorpID=\u5FDC\u7528AgentID\uFF1A +Dec-Schedule-Notification_DingTalk_Users=\u9489\u9489\u30E6\u30FC\u30B6\u30FC\uFF1A +Dec-Schedule-Notification_DingTalk_DepID=\u90E8\u9580ID\uFF1A +Dec-Schedule-Notification_DingTalk_Content=\u30CB\u30E5\u30FC\u30B9\u306E\u5185\u5BB9\uFF1A +Dec-Schedule-Notification_DingTalk_WithLink=\u6642\u9650\u7D50\u679C\u8A2A\u554F\u30EA\u30F3\u30AF +Dec-Schedule_Mobile-Push-DingTalkId-Not-Null=\u30C4\u30A4\u30C3\u30BF\u30FC\u3092\u30BB\u30C3\u30C8\u3057\u3066\u4E0B\u3055\u3044 +Dec-DingTalk_Recive_Data_URL=\u53D7\u4FE1\u30C7\u30FC\u30BFURL +Dec-DingTalk_Corp_ID=\u9489\u9489\u30A8\u30F3\u30BF\u30FC\u30D7\u30E9\u30A4\u30BAID +Dec-DingTalk_Secret=\u7BA1\u7406\u30B0\u30EB\u30FC\u30D7\u8A3C\u6191\u30AD\u30FC +Dec-DingTalk_Member_Management=\u9489\u9489\u30E1\u30F3\u30D0\u30FC\u7BA1\u7406 +Dec-DingTalk_User-Same-With-FS=\u91D8\u6253\u3061\u5DE5\u53F7\u306B\u3088\u308B\u30DE\u30C3\u30C1\u30F3\u30B0 +Dec-DingTalk_Mobile-Same-With-FS=\u96FB\u8A71\u306B\u3088\u308B\u30DE\u30C3\u30C1\u30F3\u30B0 +Dec-DingTalk_Manual-Matching-FS=\u624B\u52D5\u306B\u6574\u5408 +Dec-DingTalk_Custom-Matching-FS=\u30AB\u30B9\u30BF\u30DE\u30A4\u30BA +Dec-DingTalk_UserID=\u91D8\u91D8\u30E1\u30F3\u30D0\u30FCID +Dec-DingTalk_DecUserName=\u30E6\u30FC\u30B6\u540D +Dec-DingTalk_Name=\u6C0F\u540D +Dec-DingTalk_Department=\u9489\u9489\u90E8\u9580 +Dec-DingTalk_UrlHint=\u30B5\u30FC\u30D0\u30FC\u306EUrl\u4FDD\u5B58 +Dec-DingTalk_User_Job_Name=\u91D8\u6253\u3061\u5DE5\u53F7 +Dec-DingTalk_Token_Path=\u8A2D\u7F6EToken\u53D6\u5F97\u7D4C\u8DEF +Dec-DingTalk_Refresh_User=\u66F4\u65B0\u901A\u4FE1\u9332 +Dec-DingTalk_Mobile=\u9489\u9489\u30E1\u30F3\u30D0\u30FC\u306E\u96FB\u8A71 +Dec-DingTalk_Matching_Way=\u30DE\u30C3\u30C1\u30F3\u30B0\u65B9\u5F0F +Dec-DingTalk_Hint=\u30D2\u30F3\u30C8 +Dec-DingTalk_Loading=\u30ED\u30FC\u30C9\u4E2D... +Dec-DingTalk_Mobile_Not_Supported=HTML5\u30B0\u30E9\u30D5\u306F\u643A\u5E2F\u756A\u53F7\u3068\u30DE\u30C3\u30C1\u3059\u308B\u306E\u306F\u30B5\u30DD\u30FC\u30C8\u3057\u307E\u305B\u3093\u3001HTML5\u30D7\u30E9\u30B0\u30A4\u30F3\u3092\u66F4\u65B0\u3057\u3066\u304F\u3060\u3055\u3044\u3002 +Dec-DingTalk_Mobile-Push-DingTalk-Terminal=\u91D8\u4ED8\u3051\u306E\u901A\u77E5 +Dec-DingTalk_Addressee_Chat_Group= +Dec-DingTalk_Addressee_Chat_Group_Disable_Tip= +Dec-DingTalk_Mobile-Push-DingTalk-AgentId=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3ID +Dec-DingTalk_Expired_Error=\u30A8\u30E9\u30FC\u30B3\u30FC\u30C9\:11100016 \u672A\u767B\u9332\u306E\u6A5F\u80FD\u304C\u4F7F\u7528\u3055\u308C\u307E\u3057\u305F--DingTalk\u96C6\u7A4D +Dec-DingTalk_Expired_Solution=\u91D8\u4ED8\u3051\u6A5F\u80FD\u304C\u767B\u9332\u3055\u308C\u3066\u3044\u306A\u3044\u306E\u3067\u3001\u3054\u5229\u7528\u306E\u3088\u3046\u306B\u3054\u9023\u7D61\u304F\u3060\u3055\u3044 +Dec-DingTalk_Agent-Management=\u5FDC\u7528\u7BA1\u7406 +Dec-DingTalk_Member-Management=\u30E1\u30F3\u30D0\u30FC\u7BA1\u7406 +Dec-DingTalk_Agent-Config=\u5FDC\u7528\u30B7\u30E7\u30FC\u30C8\u30AB\u30C3\u30C8\u3092\u5FDC\u7528\u3059\u308B +Dec-DingTalk_Agent-Name=\u5FDC\u7528\u540D +Dec-DingTalk_Agent-Id=\u91D8\u3065\u3051ID +Dec-DingTalk_Organizational-Structure=\u7D44\u7E54\u69CB\u9020 +Dec-DingTalk_Tag=\u30E9\u30D9\u30EB +Dec-DingTalk_Server=\u30B5\u30FC\u30D0 +Dec-DingTalk_Save=\u4FDD\u5B58 +Dec-DingTalk_Start_With_Http=\u30B5\u30FC\u30D0\u30FC\u306E\u30A2\u30C9\u30EC\u30B9\u306F\u3001http :/ tpp\u3092\u59CB\u3081\u306A\u3051\u308C\u3070\u306A\u3089\u306A\u3044 +Dec-DingTalk_Server_Url=\u30B5\u30FC\u30D0\u306E\u30A2\u30C9\u30EC\u30B9 +Dec-DingTalk_Server_Tip= +Dec-DingTalk_Enterprise-DingDing=\u4F01\u696D\u306E\u91D8 +Dec-DingTalk_New-Agent=\u65B0\u7BC9\u306E\u91D8\u4ED8\u3051 +Dec-DingTalk_Non-Adapted-Agent=\u30D2\u30F3\u30C8\uFF1A\u4F7F\u7528id\u304C\u6B63\u3057\u3044\u304B\u3069\u3046\u304B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044 +Dec-DingTalk_Modify-Agent=\u91D8\u4ED8\u3051\u3092\u4FEE\u6B63\u3059\u308B +Dec-DingTalk_DeleteAgent-Confirm-Popup=\u3053\u306E\u4F01\u696D\u306E\u91D8\u4ED8\u3051\u306E\u524A\u9664\u3092\u78BA\u5B9A\u3059\u308B +Dec-DingTalk_Confirm=\u78BA\u5B9A +Dec-DingTalk_Cancel=\u30AD\u30E3\u30F3\u30BB\u30EB +Dec-DingTalk_Save-Agent-Fail=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u3092\u4FDD\u5B58\u3057\u3066\u5931\u6557\u3059\u308B +Dec-DingTalk_Unknown-Agent=\u30CD\u30C3\u30C8\u306E\u7570\u5E38\u3084\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044\u5F53\u9762\u4F7F\u7528\u306ECorpId\u3068Secret\u304C\u6B63\u3057\u3044\u304B\u3069\u3046\u304B +Dec-DingTalk_Agent-Name-Exist=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059 +Dec-DingTalk_Match-Way=\u30DE\u30C3\u30C1\u30F3\u30B0\u65B9\u5F0F +Dec-DingTalk_Match-Setting=\u6574\u5408\u8A2D\u5B9A +Dec-DingTalk_DataSet=\u30C7\u30FC\u30BF\u96C6 +Dec-DingTalk_Address-Book=\u91D8\u3092\u6253\u3064 +Dec-DingTalk_Member-Update=\u3059\u3050\u306B\u66F4\u65B0\u3059\u308B +Dec-DingTalk_Set-Update=\u81EA\u52D5\u66F4\u65B0\u3092\u8A2D\u5B9A +Dec-DingTalk_Not-Null=\u7A7A\u306E\u305F\u3081\u306B\u306F\u8A31\u3055\u308C\u306A\u3044 +Dec-DingTalk_Start-Update=\u81EA\u52D5\u66F4\u65B0\u3092\u6709\u52B9\u306B\u3059\u308B +Dec-DingTalk_Per=\u3059\u3079\u3066 +Dec-DingTalk_Day=\u65E5 +Dec-DingTalk_Week=\u9031\u9593 +Dec-DingTalk_Monday=\u6708\u66DC\u65E5 +Dec-DingTalk_Tuesday=\u706B\u66DC\u65E5 +Dec-DingTalk_Wednesday=\u6C34\u66DC\u65E5 +Dec-DingTalk_Thursday=\u6728\u66DC\u65E5 +Dec-DingTalk_Friday=\u91D1\u66DC\u65E5 +Dec-DingTalk_Saturday=\u571F\u66DC\u65E5 +Dec-DingTalk_Sunday=\u65E5\u66DC\u65E5 +Dec-DingTalk_Hour=\u6642 +Dec-DingTalk_Minute=\u5206 +Dec-DingTalk_Update-Once=\u30BF\u30A4\u30DF\u30F3\u30B0\u306E\u540C\u671F +Dec-DingTalk_Illegal=\u5408\u6CD5\u7684\u3067\u306A\u3044 +Dec-DingTalk_Proxy=\u91D8\u4ED8\u3051\u4EE3\u7406 +Dec-DingTalk_Proxy_Address=\u30B5\u30FC\u30D0\u30FC\u306E\u30A2\u30C9\u30EC\u30B9 +Dec-DingTalk_Proxy_Address_Tip= +Dec-DingTalk_Test_And_Save-Proxy-Address= +Dec-DingTalk_Start-With-Http=\u30B5\u30FC\u30D0\u30FC\u306E\u30A2\u30C9\u30EC\u30B9\u306F\u3001http :/ tpp\u3092\u59CB\u3081\u306A\u3051\u308C\u3070\u306A\u3089\u306A\u3044 +Dec-DingTalk_Test-Connection=\u30C6\u30B9\u30C8\u63A5\u7D9A\u4E2D... +Dec-DingTalk_Connection-Success=\u63A5\u7D9A\u304C\u6210\u529F\u3059\u308B +Dec-DingTalk_Connection-Fail=\u63A5\u7D9A\u5931\u6557 +Dec-DingTalk_Unknown-Agent-Id=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3ID\u304C\u6B63\u3057\u304F\u306A\u3044 +Dec-DingTalk_Delete-Agent-Fail=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u306E\u524A\u9664\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +Dec-DingTalk_Agent-Id-Exist=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3ID\u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059 +Dec-DingTalk_Save-ReportServer-Url-Fail=\u30B5\u30FC\u30D0\u30A2\u30C9\u30EC\u30B9\u306E\u4FDD\u5B58\u306B\u5931\u6557\u3059\u308B +Dec-DingTalk_Save-Timing-Task-Fail=\u30BF\u30A4\u30E0\u30BF\u30B9\u30AF\u306E\u5931\u6557\u3092\u4FDD\u5B58\u3059\u308B +Dec-DingTalk_Error-AppKey-And-AppSecret=\u73FE\u5728\u4F7F\u7528\u3055\u308C\u3066\u3044\u308BAppKey\u3068AppSecret\u304C\u6B63\u3057\u3044\u304B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002 +Dec-DingTalk_Error-AppKey-And-AgentId=\u73FE\u5728\u306E\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3ID\u3068AppKey\u306E\u5BFE\u5FDC\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044 +Dec-DingTalk_Duplicate-Agent-Name=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059 +Dec-DingTalk_Save-Match-Method-Fail=\u30E1\u30F3\u30D0\u30FC\u7BA1\u7406\u914D\u7F6E\u60C5\u5831\u306E\u5931\u6557 +Dec-DingTalk_Duplicate-Agent-Id=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3ID\u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059 +Dec-DingTalk_Save-Proxy-Server-Fail=\u4EE3\u7406\u30B5\u30FC\u30D0\u306E\u4FDD\u5B58\u306B\u5931\u6557\u3057\u305F +Dec-DingTalk_Connect-Proxy-Server-Fail=\u91D8\u4ED8\u3051\u4EE3\u7406\u30B5\u30FC\u30D0\u30FC\u30C6\u30B9\u30C8\u63A5\u7D9A\u5931\u6557 +Dec-DingTalk_NetWork-Anomaly=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u7570\u5E38\u306F\u3001\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u914D\u7F6E\u3092\u30C1\u30A7\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044 +Dec-DingTalk_Create-DingTalk-Url=\u30EA\u30F3\u30AF\u3092\u751F\u6210\u3059\u308B +Dec-DingTalk_Platform-Page=\u30EA\u30F3\u30AF\u30DA\u30FC\u30B8 +Dec-DingTalk_Platform-Report=\u5358\u4E00\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 +Dec-DingTalk_Platform=\u6C7A\u5B9A\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0 +Dec-DingTalk_Parameter_Setting=\u30D1\u30E9\u30E1\u30FC\u30BF\u8A2D\u5B9A +Dec-DingTalk_Create-Url=\u30EA\u30F3\u30AF\u3092\u751F\u6210 +Dec-DingTalk_DingTalk_Url=\u30EA\u30F3\u30AF\u3092\u6253\u3064 +Dec-DingTalk_Copy-Url=\u30B3\u30D4\u30FC\u3059\u308B +Dec-DingTalk_Copy-Success=\u30B3\u30D4\u30FC\u6210\u529F +Dec-DingTalk_Input-Hint=\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044 +Dec-DingTalk_Save-User-Relation-Fail=\u624B\u52D5\u4E00\u81F4\u5931\u6557 +BI-Basic_Search=\u691C\u7D22 +Dec-DingTalk_Match-Way-Not-Null=\u6574\u5408\u8A2D\u5B9A\u304C\u7A7A\u3051\u306A\u3044 +Dec-DingTalk_Not-Select=\u9078\u3070\u306A\u3044 +Dec-DingTalk_Tip-Get-ReportServer-Url-Fail=\u30B5\u30FC\u30D0\u30FC\u306E\u30A2\u30C9\u30EC\u30B9\u3092\u914D\u7F6E\u3057\u3066\u304F\u3060\u3055\u3044 +Dec-DingTalk_Create-Agent-Tip=CorpId\u3068CorpSecret\u306E\u8A18\u5165\u306F\u3001CorpId\u3068CorpSecret\u306B\u6DFB\u4ED8\u3055\u308C\u3066\u3044\u307E\u3059\u3002 +Dec-DingTalk_IP-Config-Not-Available=\u30A2\u30AF\u30BB\u30B9IP\u304C\u767D\u306E\u30EA\u30B9\u30C8\u306B\u306F\u3042\u308A\u307E\u305B\u3093 +Dec-DingTalk_NetWork-Invalid=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u7570\u5E38 +Dec-DingTalk_Not_Trusted_Domain_Error=\u30A8\u30E9\u30FC\u30B3\u30FC\u30C9\uFF1A11205040,redirectUrl\u30C9\u30E1\u30A4\u30F3\u540D\u3068\u30D0\u30C3\u30AF\u30B0\u30E9\u30A6\u30F3\u30C9\u69CB\u6210\u304C\u4E00\u81F4\u3057\u3066\u3044\u307E\u305B\u3093\u3002 +Dec-DingTalk_Not_Trusted_Domain_Exception=\u30C9\u30E1\u30A4\u30F3\u540D\u3068\u30B5\u30FC\u30D0\u30FC\u30A2\u30C9\u30EC\u30B9\u304C\u4E00\u81F4\u3057\u3066\u3044\u308B\u304B\u78BA\u8A8D\u3057\u307E\u3059 +Dec-DingTalk_Debugger-Set-Level= +Dec-DingTalk_Debugger-Level= +Dec-DingTalk_Debugger-Parameter-List= +Dec-DingTalk_Debugger-Content= +Dec-DingTalk_Debugger-Type-Get-Access-Token= +Dec-DingTalk_Debugger-Type-Check-Ip= +Dec-DingTalk_Debugger-Start-Check= +Dec-DingTalk_Debugger-Show-Result= +Dec-DingTalk_Debugger-Type-Check-Request-Time= +Dec-DingTalk_Debugger-Type-Check-Request-Time-Result= +Dec-DingTalk_Debugger-Tip-Curl-Invalid= +Dec-DingTalk_Debugger-DownLoad_Log= +Dec-DingTalk_Click-To-Download= +Dec-DingTalk_Download-Fail= +Dec-DingTalk_Not_Null= +Dec-DingTalk_ErrorDetail= +Dec-DingTalk_Debugger-Check-Ip-Result= +Dec-DingTalk_Debugger-Get-Token= +Dec-DingTalk_Agent_Deleted_Tip= +Dec-DingTalk_Parse_Parameters= +Dec-DingTalk_Parse_Parameters_Tip= +Dec-DingTalk_Enterprise_Agent= +Dec-DingTalk_Chatgroup_Name= +Dec-DingTalk_Chat_Group= +Dec-DingTalk_New_Chat_Group= +Dec-DingTalk_Delete_ChatGroup_Confirm= +Dec-DingTalk_Chat_Group_Member_Tip= +Dec-DingTalk_Chat_Group_Leader= +Dec-DingTalk_Chat_Group_Member= +Dec-DingTalk_New_Chat_Group_Tip1= +Dec-DingTalk_New_Chat_Group_Tip2= +Dec-DingTalk_New_Chat_Group_Message= +Dec-DingTalk_Common_Error_Tip= +Dec-DingTalk_Chat_Group_Name_Length_Tip= +Dec-DingTalk_Create-Chat-Group-Fail= +Dec-DingTalk_Output_User_Empty= +Dec-DingTalk_Message_Agent= +Dec-DingTalk_Message_Group= +Dec-DingTalk_DingTalk= +Dec-DingTalk_Output_User_Fail_Partly_Header= +Dec-DingTalk_Output_User_Fail_Partly_Tip= +Dec-DingTalk_Output_Group_Fail_Partly_Header= +Dec-DingTalk_Output_Group_Fail_Partly_Tip= +Dec-DingTalk_User_Match_Dec_User_Fail= \ No newline at end of file diff --git a/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_zh_CN.properties b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_zh_CN.properties new file mode 100644 index 0000000..2154aa5 --- /dev/null +++ b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_zh_CN.properties @@ -0,0 +1,165 @@ +Dec-Module-DingTalk_Manager=\u9489\u9489\u7BA1\u7406 +Dec-DingTalk_Basic=\u57FA\u672C\u4FE1\u606F +Dec-Schedule-Notification_DingTalk=\u63A8\u9001\u9489\u9489\u6D88\u606F +Dec-Schedule-Notification_DingTalk_CorpID=\u5E94\u7528AgentID\uFF1A +Dec-Schedule-Notification_DingTalk_Users=\u9489\u9489\u7528\u6237\uFF1A +Dec-Schedule-Notification_DingTalk_DepID=\u90E8\u95E8ID\uFF1A +Dec-Schedule-Notification_DingTalk_Content=\u6D88\u606F\u5185\u5BB9\uFF1A +Dec-Schedule-Notification_DingTalk_WithLink=\u5B9A\u65F6\u7ED3\u679C\u8BBF\u95EE\u94FE\u63A5 +Dec-Schedule_Mobile-Push-DingTalkId-Not-Null=\u8BF7\u8BBE\u7F6E\u63A8\u9001\u7684\u9489\u9489\u5E94\u7528 +Dec-DingTalk_Recive_Data_URL=\u63A5\u6536\u6570\u636EURL +Dec-DingTalk_Corp_ID=\u9489\u9489\u4F01\u4E1A\u53F7ID +Dec-DingTalk_Secret=\u7BA1\u7406\u7EC4\u51ED\u8BC1\u5BC6\u94A5 +Dec-DingTalk_Member_Management=\u9489\u9489\u6210\u5458\u7BA1\u7406 +Dec-DingTalk_User-Same-With-FS=\u9489\u9489\u5DE5\u53F7\u5339\u914D +Dec-DingTalk_Mobile-Same-With-FS=\u624B\u673A\u53F7\u5339\u914D +Dec-DingTalk_Manual-Matching-FS=\u624B\u52A8\u5339\u914D +Dec-DingTalk_Custom-Matching-FS=\u81EA\u5B9A\u4E49\u5339\u914D +Dec-DingTalk_UserID=\u9489\u9489\u6210\u5458ID +Dec-DingTalk_DecUserName=\u7528\u6237\u540D +Dec-DingTalk_Name=\u59D3\u540D +Dec-DingTalk_Department=\u9489\u9489\u90E8\u95E8 +Dec-DingTalk_UrlHint=\u670D\u52A1\u5668\u4FDD\u5B58\u7684Url\uFF1A +Dec-DingTalk_User_Job_Name=\u9489\u9489\u5DE5\u53F7 +Dec-DingTalk_Token_Path=\u8BBE\u7F6EToken\u83B7\u53D6\u8DEF\u5F84 +Dec-DingTalk_Refresh_User=\u66F4\u65B0\u901A\u8BAF\u5F55 +Dec-DingTalk_Mobile=\u9489\u9489\u6210\u5458\u624B\u673A\u53F7 +Dec-DingTalk_Matching_Way=\u7528\u6237\u5339\u914D\u65B9\u5F0F +Dec-DingTalk_Hint=\u63D0\u793A +Dec-DingTalk_Loading=\u6B63\u5728\u52A0\u8F7D\u7528\u6237... +Dec-DingTalk_Mobile_Not_Supported=\u5F53\u524DHTML5\u62A5\u8868\u4E0D\u652F\u6301\u6839\u636E\u624B\u673A\u53F7\u5339\u914D\uFF0C\u8BF7\u5347\u7EA7HTML5\u63D2\u4EF6 +Dec-DingTalk_Mobile-Push-DingTalk-Terminal=\u9489\u9489\u901A\u77E5 +Dec-DingTalk_Addressee_Chat_Group=\u9489\u9489\u7FA4 +Dec-DingTalk_Addressee_Chat_Group_Disable_Tip=\u5982\u679C\u6839\u636E\u9ED8\u8BA4\u7528\u6237\u7EC4\u5185\u7684\u7528\u6237\u5355\u72EC\u751F\u6210\u7ED3\u679C\uFF0C\u5219\u65E0\u6CD5\u901A\u77E5\u5230\u9489\u9489\u7FA4 +Dec-DingTalk_Mobile-Push-DingTalk-AgentId=\u5E94\u7528ID +Dec-DingTalk_Expired_Error=\u9519\u8BEF\u4EE3\u7801:11100016 \u60A8\u4F7F\u7528\u4E86\u672A\u6CE8\u518C\u7684\u529F\u80FD\u2014\u2014\u9489\u9489\u96C6\u6210 +Dec-DingTalk_Expired_Solution=\u9489\u9489\u529F\u80FD\u672A\u6CE8\u518C\uFF0C\u5982\u9700\u4F7F\u7528\u8BF7\u8054\u7CFB\u9500\u552E +Dec-DingTalk_Agent-Management=\u5E94\u7528\u7BA1\u7406 +Dec-DingTalk_Member-Management=\u6210\u5458\u7BA1\u7406 +Dec-DingTalk_Agent-Config=\u5E94\u7528\u5FEB\u6377\u914D\u7F6E +Dec-DingTalk_Agent-Name=\u9489\u9489\u5E94\u7528\u540D\u79F0 +Dec-DingTalk_Agent-Id=\u9489\u9489\u5E94\u7528ID +Dec-DingTalk_Organizational-Structure=\u7EC4\u7EC7\u67B6\u6784 +Dec-DingTalk_Tag=\u6807\u7B7E +Dec-DingTalk_Server=\u670D\u52A1\u5668 +Dec-DingTalk_Save=\u4FDD\u5B58 +Dec-DingTalk_Start_With_Http=\u670D\u52A1\u5668\u5730\u5740\u5FC5\u987B\u4EE5http\u6216https\u5F00\u5934 +Dec-DingTalk_Server_Url=\u670D\u52A1\u5668\u5730\u5740 +Dec-DingTalk_Server_Tip=1\u3001\u8BE5\u5730\u5740\u5C06\u7528\u4E8E\u5FEB\u6377\u914D\u7F6E\u4E2D\u751F\u6210\u5E73\u53F0\u5355\u70B9\u94FE\u63A5\u3001\u6A21\u677F\u5355\u70B9\u94FE\u63A5\uFF0C\u4EE5\u53CA\u63A8\u9001\u7684\u7ED3\u679C\u94FE\u63A5\uFF1B\n2\u3001\u8BE5\u5730\u5740\u9700\u8981\u5916\u7F51\u53EF\u8BBF\u95EE\uFF0C\u5730\u5740\u683C\u5F0F\u4E3Ahttp://\u57DF\u540D:\u7AEF\u53E3/decision\u6216https://\u57DF\u540D:\u7AEF\u53E3/decision\uFF0C\u914D\u7F6E\u540E\u8BF7\u4FDD\u5B58 +Dec-DingTalk_Enterprise-DingDing=\u4F01\u4E1A\u9489\u9489 +Dec-DingTalk_New-Agent=\u65B0\u5EFA\u9489\u9489\u5E94\u7528 +Dec-DingTalk_Non-Adapted-Agent=\u63D0\u793A\uFF1A\u8BF7\u786E\u8BA4\u5E94\u7528id\u662F\u5426\u6B63\u786E +Dec-DingTalk_Modify-Agent=\u4FEE\u6539\u9489\u9489\u5E94\u7528 +Dec-DingTalk_DeleteAgent-Confirm-Popup=\u786E\u5B9A\u5220\u9664\u6B64\u4F01\u4E1A\u9489\u9489\u5E94\u7528 +Dec-DingTalk_Confirm=\u786E\u5B9A +Dec-DingTalk_Cancel=\u53D6\u6D88 +Dec-DingTalk_Save-Agent-Fail=\u5B58\u50A8\u5E94\u7528\u4FE1\u606F\u5931\u8D25 +Dec-DingTalk_Unknown-Agent=\u7F51\u7EDC\u5F02\u5E38\u6216\u8005\u8BF7\u786E\u8BA4\u5F53\u524D\u4F7F\u7528\u7684CorpId\u548CSecret\u662F\u5426\u6B63\u786E +Dec-DingTalk_Agent-Name-Exist=\u5E94\u7528\u540D\u79F0\u5DF2\u5B58\u5728 +Dec-DingTalk_Match-Way=\u5339\u914D\u65B9\u5F0F +Dec-DingTalk_Match-Setting=\u5339\u914D\u8BBE\u7F6E +Dec-DingTalk_DataSet=\u6570\u636E\u96C6 +Dec-DingTalk_Address-Book=\u9489\u9489\u901A\u8BAF\u5F55 +Dec-DingTalk_Member-Update=\u7ACB\u5373\u66F4\u65B0 +Dec-DingTalk_Set-Update=\u8BBE\u7F6E\u81EA\u52A8\u66F4\u65B0 +Dec-DingTalk_Not-Null=\u4E0D\u5141\u8BB8\u4E3A\u7A7A +Dec-DingTalk_Start-Update=\u542F\u7528\u81EA\u52A8\u66F4\u65B0 +Dec-DingTalk_Per=\u6BCF +Dec-DingTalk_Day=\u5929 +Dec-DingTalk_Week=\u5468 +Dec-DingTalk_Monday=\u5468\u4E00 +Dec-DingTalk_Tuesday=\u5468\u4E8C +Dec-DingTalk_Wednesday=\u5468\u4E09 +Dec-DingTalk_Thursday=\u5468\u56DB +Dec-DingTalk_Friday=\u5468\u4E94 +Dec-DingTalk_Saturday=\u5468\u516D +Dec-DingTalk_Sunday=\u5468\u65E5 +Dec-DingTalk_Hour=\u65F6 +Dec-DingTalk_Minute=\u5206 +Dec-DingTalk_Update-Once=\u5B9A\u65F6\u540C\u6B65\u4E00\u6B21 +Dec-DingTalk_Illegal=\u4E0D\u5408\u6CD5 +Dec-DingTalk_Proxy=\u9489\u9489\u4EE3\u7406\u8DF3\u8F6C +Dec-DingTalk_Proxy_Address=\u4EE3\u7406\u670D\u52A1\u5668\u5730\u5740 +Dec-DingTalk_Proxy_Address_Tip=1\u3001\u8BE5\u5730\u5740\u586B\u5199\u5E06\u8F6F\u6240\u5728\u5E94\u7528\u670D\u52A1\u5668\u8BBF\u95EE\u4EE3\u7406\u670D\u52A1\u5668\u7684\u5730\u5740\uFF0C\u5373\u6B63\u5411\u4EE3\u7406\u5730\u5740\uFF0C\u4ECE\u800C\u4F7F\u5E06\u8F6F\u5E94\u7528\u670D\u52A1\u5668\u80FD\u591F\u901A\u8FC7\u4EE3\u7406\u670D\u52A1\u5668\u8BBF\u95EE\u5230\u5916\u7F51\u9489\u9489\u670D\u52A1\u5668\uFF1B\n2\u3001\u5730\u5740\u683C\u5F0F\u4E3Ahttp://\u57DF\u540D:\u7AEF\u53E3 +Dec-DingTalk_Test_And_Save-Proxy-Address=\u6D4B\u8BD5\u8FDE\u63A5\u5E76\u4FDD\u5B58 +Dec-DingTalk_Start-With-Http=\u670D\u52A1\u5668\u5730\u5740\u5FC5\u987B\u4EE5http\u6216https\u5F00\u5934 +Dec-DingTalk_Test-Connection=\u6D4B\u8BD5\u8FDE\u63A5\u4E2D... +Dec-DingTalk_Connection-Success=\u8FDE\u63A5\u6210\u529F +Dec-DingTalk_Connection-Fail=\u8FDE\u63A5\u5931\u8D25 +Dec-DingTalk_Unknown-Agent-Id=\u5E94\u7528ID\u4E0D\u6B63\u786E +Dec-DingTalk_Delete-Agent-Fail=\u5220\u9664\u5E94\u7528\u5931\u8D25 +Dec-DingTalk_Agent-Id-Exist=\u5E94\u7528ID\u5DF2\u5B58\u5728 +Dec-DingTalk_Save-ReportServer-Url-Fail=\u4FDD\u5B58\u670D\u52A1\u5668\u5730\u5740\u5931\u8D25 +Dec-DingTalk_Save-Timing-Task-Fail=\u4FDD\u5B58\u5B9A\u65F6\u4EFB\u52A1\u5931\u8D25 +Dec-DingTalk_Error-AppKey-And-AppSecret=\u8BF7\u786E\u8BA4\u5F53\u524D\u4F7F\u7528\u7684AppKey\u548CAppSecret\u662F\u5426\u6B63\u786E +Dec-DingTalk_Error-AppKey-And-AgentId=\u8BF7\u786E\u8BA4\u5F53\u524D\u5E94\u7528ID\u548CAppKey\u662F\u5426\u5BF9\u5E94 +Dec-DingTalk_Duplicate-Agent-Name=\u5E94\u7528\u540D\u79F0\u5DF2\u5B58\u5728 +Dec-DingTalk_Save-Match-Method-Fail=\u5B58\u50A8\u6210\u5458\u7BA1\u7406\u914D\u7F6E\u4FE1\u606F\u5931\u8D25 +Dec-DingTalk_Duplicate-Agent-Id=\u5E94\u7528ID\u5DF2\u5B58\u5728 +Dec-DingTalk_Save-Proxy-Server-Fail=\u4FDD\u5B58\u4EE3\u7406\u670D\u52A1\u5668\u5931\u8D25 +Dec-DingTalk_Connect-Proxy-Server-Fail=\u9489\u9489\u4EE3\u7406\u670D\u52A1\u5668\u6D4B\u8BD5\u8FDE\u63A5\u5931\u8D25 +Dec-DingTalk_NetWork-Anomaly=\u7F51\u7EDC\u5F02\u5E38\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u914D\u7F6E +Dec-DingTalk_Create-DingTalk-Url=\u751F\u6210\u9489\u9489\u94FE\u63A5 +Dec-DingTalk_Platform-Page=\u94FE\u63A5\u9875\u9762 +Dec-DingTalk_Platform-Report=\u5355\u4E2A\u6A21\u677F +Dec-DingTalk_Platform=\u51B3\u7B56\u5E73\u53F0 +Dec-DingTalk_Parameter_Setting=\u53C2\u6570\u8BBE\u7F6E +Dec-DingTalk_Create-Url=\u751F\u6210\u94FE\u63A5 +Dec-DingTalk_DingTalk_Url=\u9489\u9489\u94FE\u63A5 +Dec-DingTalk_Copy-Url=\u590D\u5236 +Dec-DingTalk_Copy-Success=\u590D\u5236\u6210\u529F +Dec-DingTalk_Input-Hint=\u8BF7\u8F93\u5165 +Dec-DingTalk_Save-User-Relation-Fail=\u624B\u52A8\u5339\u914D\u5931\u8D25 +BI-Basic_Search=\u641C\u7D22 +Dec-DingTalk_Match-Way-Not-Null=\u5339\u914D\u8BBE\u7F6E\u4E0D\u80FD\u4E3A\u7A7A +Dec-DingTalk_Not-Select=\u4E0D\u9009 +Dec-DingTalk_Tip-Get-ReportServer-Url-Fail=\u8BF7\u914D\u7F6E\u670D\u52A1\u5668\u5730\u5740 +Dec-DingTalk_Create-Agent-Tip=\u82E5\u65E0AppKey\uFF0C\u8BF7\u5728Appkey\u548CAppSecret\u4E2D\u5206\u522B\u586B\u5199CorpId\u548CCorpSecret +Dec-DingTalk_IP-Config-Not-Available=\u8BBF\u95EEIP\u4E0D\u5728\u767D\u540D\u5355\u4E4B\u4E2D +Dec-DingTalk_NetWork-Invalid=\u7F51\u7EDC\u5F02\u5E38 +Dec-DingTalk_Not_Trusted_Domain_Error=\u9519\u8BEF\u4EE3\u7801\uFF1A11205040\uFF0CredirectUrl\u57DF\u540D\u4E0E\u540E\u53F0\u914D\u7F6E\u4E0D\u4E00\u81F4 +Dec-DingTalk_Not_Trusted_Domain_Exception=\u68C0\u67E5\u57DF\u540D\u4E0E\u670D\u52A1\u5668\u5730\u5740\u662F\u5426\u4E00\u81F4 +Dec-DingTalk_Debugger-Set-Level=\u8BBE\u7F6E\u65E5\u5FD7\u7EA7\u522B +Dec-DingTalk_Debugger-Level=\u65E5\u5FD7\u7EA7\u522B +Dec-DingTalk_Debugger-Parameter-List=\u53C2\u6570\u5217\u8868 +Dec-DingTalk_Debugger-Content=\u8C03\u8BD5\u5185\u5BB9 +Dec-DingTalk_Debugger-Type-Get-Access-Token=\u83B7\u53D6access_token +Dec-DingTalk_Debugger-Type-Check-Ip=\u68C0\u67E5ip\u767D\u540D\u5355 +Dec-DingTalk_Debugger-Start-Check=\u5F00\u59CB\u68C0\u6D4B +Dec-DingTalk_Debugger-Show-Result=\u68C0\u6D4B\u7ED3\u679C +Dec-DingTalk_Debugger-Type-Check-Request-Time=\u68C0\u6D4B\u8BF7\u6C42\u8017\u65F6 +Dec-DingTalk_Debugger-Type-Check-Request-Time-Result=\u68C0\u6D4B\u7ED3\u679C +Dec-DingTalk_Debugger-Tip-Curl-Invalid=\u63D0\u793A\uFF1A\u670D\u52A1\u5668\u7CFB\u7EDF\u82E5\u4E3Awindows\u5219\u9700\u8981\u5B89\u88C5curl\u5DE5\u5177\u624D\u80FD\u652F\u6301\u68C0\u6D4B +Dec-DingTalk_Debugger-DownLoad_Log=\u4E0B\u8F7D\u65E5\u5FD7 +Dec-DingTalk_Click-To-Download=\u70B9\u51FB\u4E0B\u8F7D +Dec-DingTalk_Download-Fail=\u4E0B\u8F7D\u5931\u8D25 +Dec-DingTalk_Not_Null=\u4E0D\u53EF\u4E3A\u7A7A +Dec-DingTalk_ErrorDetail=\u9519\u8BEF\u4FE1\u606F +Dec-DingTalk_Debugger-Check-Ip-Result=\u68C0\u67E5\u7ED3\u679C +Dec-DingTalk_Debugger-Get-Token=access_token +Dec-DingTalk_Agent_Deleted_Tip=\u65E0\u6CD5\u83B7\u53D6\u8BE5\u9489\u9489\u5E94\u7528\uFF0C\u8BF7\u68C0\u67E5\u914D\u7F6E\u9879\u662F\u5426\u6709\u8BEF +Dec-DingTalk_Parse_Parameters=\u89E3\u6790\u53C2\u6570\u503C +Dec-DingTalk_Parse_Parameters_Tip=\u5FAE\u4FE1\uFF0F\u9489\u9489\u96C6\u6210\u94FE\u63A5\u5FC5\u987B\u52FE\u9009\u89E3\u6790\u53C2\u6570\u503C\uFF0C\u5426\u5219\u5C06\u5BFC\u81F4\u53C2\u6570\u4E22\u5931\uFF1B\u6A21\u677F\u6D88\u606F\u63A8\u9001\u7684\u6D88\u606F\u94FE\u63A5\u53EF\u9009\u62E9\u4E0D\u89E3\u6790\u53C2\u6570\u503C\uFF0C\u4ECE\u800C\u5B9E\u73B0\u63A8\u9001\u65F6\u7684\u5B9E\u65F6\u516C\u5F0F\u8BA1\u7B97\u3002 +Dec-DingTalk_Enterprise_Agent=\u9489\u9489\u5E94\u7528 +Dec-DingTalk_Chatgroup_Name=\u9489\u9489\u7FA4\u540D\u79F0 +Dec-DingTalk_Chat_Group=\u9489\u9489\u7FA4 +Dec-DingTalk_New_Chat_Group=\u65B0\u5EFA\u9489\u9489\u7FA4 +Dec-DingTalk_Delete_ChatGroup_Confirm=\u786E\u8BA4\u5220\u9664\u9489\u9489\u7FA4\uFF1F +Dec-DingTalk_Chat_Group_Member_Tip=\u9664\u7FA4\u4E3B\u5916\uFF0C\u4E0D\u53EF\u5C11\u4E8E2\u4EBA +Dec-DingTalk_Chat_Group_Leader=\u7FA4\u4E3B +Dec-DingTalk_Chat_Group_Member=\u7FA4\u6210\u5458 +Dec-DingTalk_New_Chat_Group_Tip1=\u7FA4\u6210\u5458\u8D85\u8FC730\u4EBA\u65F6\uFF0C\u5EFA\u8BAE\u5728\u9489\u9489\u5BA2\u6237\u7AEF\u6DFB\u52A0\u66F4\u591A\u7FA4\u6210\u5458\u3002 +Dec-DingTalk_New_Chat_Group_Tip2=\u5BA2\u6237\u7AEF\u6DFB\u52A0\u7684\u6210\u5458\u82E5\u4E0D\u5728\u5E94\u7528\u53EF\u89C1\u8303\u56F4\u5185\uFF0C\u5C06\u65E0\u6CD5\u5355\u70B9\u767B\u5F55\u67E5\u770B\u6A21\u677F\u3002 +Dec-DingTalk_New_Chat_Group_Message=\u60A8\u5DF2\u52A0\u5165\u7FA4\u804A +Dec-DingTalk_Common_Error_Tip=\u53D1\u751F\u9519\u8BEF\uFF0C\u9519\u8BEF\u7801\u4E3A\uFF1A +Dec-DingTalk_Chat_Group_Name_Length_Tip=\u7FA4\u540D\u79F0\u957F\u5EA6\u965020\u4E2A\u5B57\u7B26 +Dec-DingTalk_Create-Chat-Group-Fail=\u521B\u5EFA\u9489\u9489\u7FA4\u5931\u8D25 +Dec-DingTalk_Output_User_Empty=\u63A8\u9001\u4EBA\u4E3A\u7A7A\uFF01 +Dec-DingTalk_Message_Agent=\u5E94\u7528\u6D88\u606F +Dec-DingTalk_Message_Group=\u7FA4\u6D88\u606F +Dec-DingTalk_DingTalk=\u9489\u9489 +Dec-DingTalk_Output_User_Fail_Partly_Header=\u4E2A\u7528\u6237\u63A8\u9001\u5931\u8D25\uFF1A +Dec-DingTalk_Output_User_Fail_Partly_Tip=...\uFF0C\u53EF\u5728\u65E5\u5FD7\u4E2D\u67E5\u770B\u5B8C\u6574\u7528\u6237\u540D\u5355 +Dec-DingTalk_Output_Group_Fail_Partly_Header=\u4E2A\u7FA4\u63A8\u9001\u5931\u8D25\uFF1A +Dec-DingTalk_Output_Group_Fail_Partly_Tip=...\uFF0C\u53EF\u5728\u65E5\u5FD7\u4E2D\u67E5\u770B\u5B8C\u6574\u7FA4\u540D\u5355 +Dec-DingTalk_User_Match_Dec_User_Fail=\u9489\u9489\u7528\u6237\u5339\u914D\u5E73\u53F0\u7528\u6237\u5931\u8D25\uFF01 \ No newline at end of file diff --git a/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_zh_TW.properties b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_zh_TW.properties new file mode 100644 index 0000000..6cb089c --- /dev/null +++ b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/locale/dingtalk_zh_TW.properties @@ -0,0 +1,165 @@ +Dec-Module-DingTalk_Manager=\u91D8\u91D8\u7BA1\u7406 +Dec-DingTalk_Basic=\u57FA\u672C\u8CC7\u8A0A +Dec-Schedule-Notification_DingTalk=\u63A8\u9001\u91D8\u91D8\u8A0A\u606F +Dec-Schedule-Notification_DingTalk_CorpID=\u61C9\u7528AgentID\uFF1A +Dec-Schedule-Notification_DingTalk_Users=\u91D8\u91D8\u4F7F\u7528\u8005\uFF1A +Dec-Schedule-Notification_DingTalk_DepID=\u90E8\u9580ID\uFF1A +Dec-Schedule-Notification_DingTalk_Content=\u8A0A\u606F\u5167\u5BB9\uFF1A +Dec-Schedule-Notification_DingTalk_WithLink=\u5B9A\u6642\u7D50\u679C\u8A2A\u554F\u9023\u7D50 +Dec-Schedule_Mobile-Push-DingTalkId-Not-Null=\u8ACB\u8A2D\u5B9A\u63A8\u9001\u7684\u91D8\u91D8\u61C9\u7528 +Dec-DingTalk_Recive_Data_URL=\u63A5\u6536\u8CC7\u6599URL +Dec-DingTalk_Corp_ID=\u91D8\u91D8\u4F01\u696D\u865FID +Dec-DingTalk_Secret=\u7BA1\u7406\u7D44\u6191\u8B49\u91D1\u9470 +Dec-DingTalk_Member_Management=\u91D8\u91D8\u6210\u54E1\u7BA1\u7406 +Dec-DingTalk_User-Same-With-FS=\u91D8\u91D8\u5DE5\u865F\u5339\u914D +Dec-DingTalk_Mobile-Same-With-FS=\u624B\u6A5F\u865F\u5339\u914D +Dec-DingTalk_Manual-Matching-FS=\u624B\u52D5\u5339\u914D +Dec-DingTalk_Custom-Matching-FS=\u81EA\u8A02\u5339\u914D +Dec-DingTalk_UserID=\u91D8\u91D8\u6210\u54E1ID +Dec-DingTalk_DecUserName=\u4F7F\u7528\u8005\u540D\u7A31 +Dec-DingTalk_Name=\u59D3\u540D +Dec-DingTalk_Department=\u91D8\u91D8\u90E8\u9580 +Dec-DingTalk_UrlHint=\u4F3A\u670D\u5668\u5132\u5B58\u7684Url\uFF1A +Dec-DingTalk_User_Job_Name=\u91D8\u91D8\u5DE5\u865F +Dec-DingTalk_Token_Path=\u8A2D\u5B9AToken\u7372\u53D6\u8DEF\u5F91 +Dec-DingTalk_Refresh_User=\u66F4\u65B0\u901A\u8A0A\u9304 +Dec-DingTalk_Mobile=\u91D8\u91D8\u6210\u54E1\u624B\u6A5F\u865F +Dec-DingTalk_Matching_Way=\u4F7F\u7528\u8005\u5339\u914D\u65B9\u5F0F +Dec-DingTalk_Hint=\u63D0\u793A +Dec-DingTalk_Loading=\u6B63\u5728\u8F09\u5165\u4F7F\u7528\u8005... +Dec-DingTalk_Mobile_Not_Supported=\u7576\u524DHTML5\u5831\u8868\u4E0D\u652F\u63F4\u6839\u64DA\u624B\u6A5F\u865F\u5339\u914D\uFF0C\u8ACB\u5347\u7D1AHTML5\u63D2\u4EF6 +Dec-DingTalk_Mobile-Push-DingTalk-Terminal=\u91D8\u91D8\u901A\u77E5 +Dec-DingTalk_Addressee_Chat_Group=\u91D8\u91D8\u7FA4 +Dec-DingTalk_Addressee_Chat_Group_Disable_Tip=\u5982\u679C\u6839\u64DA\u9ED8\u8A8D\u7528\u6236\u7D44\u5167\u7684\u7528\u6236\u55AE\u7368\u751F\u6210\u7D50\u679C\uFF0C\u5247\u7121\u6CD5\u901A\u77E5\u5230\u91D8\u91D8\u7FA4 +Dec-DingTalk_Mobile-Push-DingTalk-AgentId=\u61C9\u7528ID +Dec-DingTalk_Expired_Error=\u932F\u8AA4\u7A0B\u5F0F\u78BC:11100016 \u60A8\u4F7F\u7528\u4E86\u672A\u8A3B\u518A\u7684\u529F\u80FD\u2014\u2014\u91D8\u91D8\u6574\u5408 +Dec-DingTalk_Expired_Solution=\u91D8\u91D8\u529F\u80FD\u672A\u8A3B\u518A\uFF0C\u5982\u9700\u4F7F\u7528\u8ACB\u806F\u7D61\u92B7\u552E +Dec-DingTalk_Agent-Management=\u61C9\u7528\u7BA1\u7406 +Dec-DingTalk_Member-Management=\u6210\u54E1\u7BA1\u7406 +Dec-DingTalk_Agent-Config=\u61C9\u7528\u5FEB\u6377\u914D\u7F6E +Dec-DingTalk_Agent-Name=\u91D8\u91D8\u61C9\u7528\u540D\u7A31 +Dec-DingTalk_Agent-Id=\u91D8\u91D8\u61C9\u7528ID +Dec-DingTalk_Organizational-Structure=\u7D44\u7E54\u67B6\u69CB +Dec-DingTalk_Tag=\u6A19\u7C64 +Dec-DingTalk_Server=\u4F3A\u670D\u5668 +Dec-DingTalk_Save=\u5132\u5B58 +Dec-DingTalk_Start_With_Http=\u4F3A\u670D\u5668\u5730\u5740\u5FC5\u9808\u4EE5http\u6216https\u958B\u982D +Dec-DingTalk_Server_Url=\u4F3A\u670D\u5668\u5730\u5740 +Dec-DingTalk_Server_Tip=1\u3001\u8A72\u5730\u5740\u5C07\u7528\u65BC\u5FEB\u6377\u914D\u7F6E\u4E2D\u751F\u6210\u5E73\u53F0\u55AE\u9EDE\u9023\u7D50\u3001\u7BC4\u672C\u55AE\u9EDE\u9023\u7D50\uFF0C\u4EE5\u53CA\u63A8\u9001\u7684\u7D50\u679C\u9023\u7D50\uFF1B\n2\u3001\u8A72\u5730\u5740\u9700\u8981\u5916\u7DB2\u53EF\u8A2A\u554F\uFF0C\u5730\u5740\u683C\u5F0F\u70BAhttp://\u57DF\u540D:\u57E0/decision\u6216https://\u57DF\u540D:\u57E0/decision\uFF0C\u914D\u7F6E\u5F8C\u8ACB\u5132\u5B58 +Dec-DingTalk_Enterprise-DingDing=\u4F01\u696D\u91D8\u91D8 +Dec-DingTalk_New-Agent=\u65B0\u5EFA\u91D8\u91D8\u61C9\u7528 +Dec-DingTalk_Non-Adapted-Agent=\u63D0\u793A\uFF1A\u8ACB\u78BA\u8A8D\u61C9\u7528id\u662F\u5426\u6B63\u78BA +Dec-DingTalk_Modify-Agent=\u4FEE\u6539\u91D8\u91D8\u61C9\u7528 +Dec-DingTalk_DeleteAgent-Confirm-Popup=\u78BA\u5B9A\u522A\u9664\u6B64\u4F01\u696D\u91D8\u91D8\u61C9\u7528 +Dec-DingTalk_Confirm=\u78BA\u5B9A +Dec-DingTalk_Cancel=\u53D6\u6D88 +Dec-DingTalk_Save-Agent-Fail=\u5132\u5B58\u61C9\u7528\u8CC7\u8A0A\u5931\u6557 +Dec-DingTalk_Unknown-Agent=\u7DB2\u8DEF\u7570\u5E38\u6216\u8005\u8ACB\u78BA\u8A8D\u7576\u524D\u4F7F\u7528\u7684CorpId\u548CSecret\u662F\u5426\u6B63\u78BA +Dec-DingTalk_Agent-Name-Exist=\u61C9\u7528\u540D\u7A31\u5DF2\u5B58\u5728 +Dec-DingTalk_Match-Way=\u5339\u914D\u65B9\u5F0F +Dec-DingTalk_Match-Setting=\u5339\u914D\u8A2D\u5B9A +Dec-DingTalk_DataSet=\u8CC7\u6599\u96C6 +Dec-DingTalk_Address-Book=\u91D8\u91D8\u901A\u8A0A\u9304 +Dec-DingTalk_Member-Update=\u7ACB\u5373\u66F4\u65B0 +Dec-DingTalk_Set-Update=\u8A2D\u5B9A\u81EA\u52D5\u66F4\u65B0 +Dec-DingTalk_Not-Null=\u4E0D\u5141\u8A31\u70BA\u7A7A +Dec-DingTalk_Start-Update=\u555F\u7528\u81EA\u52D5\u66F4\u65B0 +Dec-DingTalk_Per=\u6BCF +Dec-DingTalk_Day=\u5929 +Dec-DingTalk_Week=\u5468 +Dec-DingTalk_Monday=\u9031\u4E00 +Dec-DingTalk_Tuesday=\u9031\u4E8C +Dec-DingTalk_Wednesday=\u9031\u4E09 +Dec-DingTalk_Thursday=\u9031\u56DB +Dec-DingTalk_Friday=\u9031\u4E94 +Dec-DingTalk_Saturday=\u9031\u516D +Dec-DingTalk_Sunday=\u9031\u65E5 +Dec-DingTalk_Hour=\u6642 +Dec-DingTalk_Minute=\u5206 +Dec-DingTalk_Update-Once=\u5B9A\u6642\u540C\u6B65\u4E00\u6B21 +Dec-DingTalk_Illegal=\u4E0D\u5408\u6CD5 +Dec-DingTalk_Proxy=\u91D8\u91D8\u4EE3\u7406\u8DF3\u8F49 +Dec-DingTalk_Proxy_Address=\u4EE3\u7406\u4F3A\u670D\u5668\u5730\u5740 +Dec-DingTalk_Proxy_Address_Tip=1\u3001\u8A72\u5730\u5740\u586B\u5BEB\u5E06\u8EDF\u6240\u5728\u61C9\u7528\u4F3A\u670D\u5668\u8A2A\u554F\u4EE3\u7406\u4F3A\u670D\u5668\u7684\u5730\u5740\uFF0C\u5373\u6B63\u5411\u4EE3\u7406\u5730\u5740\uFF0C\u5F9E\u800C\u4F7F\u5E06\u8EDF\u61C9\u7528\u4F3A\u670D\u5668\u80FD\u5920\u901A\u904E\u4EE3\u7406\u4F3A\u670D\u5668\u8A2A\u554F\u5230\u5916\u7DB2\u91D8\u91D8\u4F3A\u670D\u5668\uFF1B\n2\u3001\u5730\u5740\u683C\u5F0F\u70BAhttp://\u57DF\u540D:\u57E0 +Dec-DingTalk_Test_And_Save-Proxy-Address= +Dec-DingTalk_Start-With-Http=\u4F3A\u670D\u5668\u5730\u5740\u5FC5\u9808\u4EE5http\u6216https\u958B\u982D +Dec-DingTalk_Test-Connection=\u6E2C\u8A66\u9023\u7DDA\u4E2D... +Dec-DingTalk_Connection-Success=\u9023\u7DDA\u6210\u529F +Dec-DingTalk_Connection-Fail=\u9023\u7DDA\u5931\u6557 +Dec-DingTalk_Unknown-Agent-Id=\u61C9\u7528ID\u4E0D\u6B63\u78BA +Dec-DingTalk_Delete-Agent-Fail=\u522A\u9664\u61C9\u7528\u5931\u6557 +Dec-DingTalk_Agent-Id-Exist=\u61C9\u7528ID\u5DF2\u5B58\u5728 +Dec-DingTalk_Save-ReportServer-Url-Fail=\u5132\u5B58\u4F3A\u670D\u5668\u5730\u5740\u5931\u6557 +Dec-DingTalk_Save-Timing-Task-Fail=\u5132\u5B58\u5B9A\u6642\u4EFB\u52D9\u5931\u6557 +Dec-DingTalk_Error-AppKey-And-AppSecret=\u8ACB\u78BA\u8A8D\u7576\u524D\u4F7F\u7528\u7684AppKey\u548CAppSecret\u662F\u5426\u6B63\u78BA +Dec-DingTalk_Error-AppKey-And-AgentId=\u8ACB\u78BA\u8A8D\u7576\u524D\u61C9\u7528ID\u548CAppKey\u662F\u5426\u5C0D\u61C9 +Dec-DingTalk_Duplicate-Agent-Name=\u61C9\u7528\u540D\u7A31\u5DF2\u5B58\u5728 +Dec-DingTalk_Save-Match-Method-Fail=\u5132\u5B58\u6210\u54E1\u7BA1\u7406\u914D\u7F6E\u8CC7\u8A0A\u5931\u6557 +Dec-DingTalk_Duplicate-Agent-Id=\u61C9\u7528ID\u5DF2\u5B58\u5728 +Dec-DingTalk_Save-Proxy-Server-Fail=\u5132\u5B58\u4EE3\u7406\u4F3A\u670D\u5668\u5931\u6557 +Dec-DingTalk_Connect-Proxy-Server-Fail=\u91D8\u91D8\u4EE3\u7406\u4F3A\u670D\u5668\u6E2C\u8A66\u9023\u7DDA\u5931\u6557 +Dec-DingTalk_NetWork-Anomaly=\u7DB2\u8DEF\u7570\u5E38\uFF0C\u8ACB\u6AA2\u67E5\u7DB2\u8DEF\u914D\u7F6E +Dec-DingTalk_Create-DingTalk-Url=\u751F\u6210\u91D8\u91D8\u9023\u7D50 +Dec-DingTalk_Platform-Page=\u9023\u7D50\u9801\u9762 +Dec-DingTalk_Platform-Report=\u55AE\u500B\u7BC4\u672C +Dec-DingTalk_Platform=\u6C7A\u7B56\u5E73\u53F0 +Dec-DingTalk_Parameter_Setting=\u53C3\u6578\u8A2D\u5B9A +Dec-DingTalk_Create-Url=\u751F\u6210\u9023\u7D50 +Dec-DingTalk_DingTalk_Url=\u91D8\u91D8\u9023\u7D50 +Dec-DingTalk_Copy-Url=\u8907\u88FD +Dec-DingTalk_Copy-Success=\u8907\u88FD\u6210\u529F +Dec-DingTalk_Input-Hint=\u8ACB\u8F38\u5165 +Dec-DingTalk_Save-User-Relation-Fail=\u624B\u52D5\u5339\u914D\u5931\u6557 +BI-Basic_Search=\u641C\u5C0B +Dec-DingTalk_Match-Way-Not-Null=\u5339\u914D\u8A2D\u5B9A\u4E0D\u80FD\u70BA\u7A7A +Dec-DingTalk_Not-Select=\u4E0D\u9078 +Dec-DingTalk_Tip-Get-ReportServer-Url-Fail=\u8ACB\u914D\u7F6E\u4F3A\u670D\u5668\u5730\u5740 +Dec-DingTalk_Create-Agent-Tip=\u82E5\u7121AppKey\uFF0C\u8ACB\u5728Appkey\u548CAppSecret\u4E2D\u5206\u5225\u586B\u5BEBCorpId\u548CCorpSecret +Dec-DingTalk_IP-Config-Not-Available=\u8A2A\u554FIP\u4E0D\u5728\u767D\u540D\u55AE\u4E4B\u4E2D +Dec-DingTalk_NetWork-Invalid=\u7DB2\u8DEF\u7570\u5E38 +Dec-DingTalk_Not_Trusted_Domain_Error=\u932F\u8AA4\u7A0B\u5F0F\u78BC\uFF1A11205040\uFF0CredirectUrl\u57DF\u540D\u8207\u5F8C\u53F0\u914D\u7F6E\u4E0D\u4E00\u81F4 +Dec-DingTalk_Not_Trusted_Domain_Exception=\u6AA2\u67E5\u57DF\u540D\u8207\u4F3A\u670D\u5668\u5730\u5740\u662F\u5426\u4E00\u81F4 +Dec-DingTalk_Debugger-Set-Level=\u8A2D\u5B9A\u65E5\u8A8C\u7D1A\u5225 +Dec-DingTalk_Debugger-Level=\u65E5\u8A8C\u7D1A\u5225 +Dec-DingTalk_Debugger-Parameter-List=\u53C3\u6578\u5217\u8868 +Dec-DingTalk_Debugger-Content=\u9664\u932F\u5167\u5BB9 +Dec-DingTalk_Debugger-Type-Get-Access-Token=\u7372\u53D6access_token +Dec-DingTalk_Debugger-Type-Check-Ip=\u6AA2\u67E5ip\u767D\u540D\u55AE +Dec-DingTalk_Debugger-Start-Check=\u958B\u59CB\u6AA2\u6E2C +Dec-DingTalk_Debugger-Show-Result=\u6AA2\u6E2C\u7D50\u679C +Dec-DingTalk_Debugger-Type-Check-Request-Time=\u6AA2\u6E2C\u8ACB\u6C42\u8017\u6642 +Dec-DingTalk_Debugger-Type-Check-Request-Time-Result=\u6AA2\u6E2C\u7D50\u679C +Dec-DingTalk_Debugger-Tip-Curl-Invalid=\u63D0\u793A\uFF1A\u670D\u52D9\u5668\u7CFB\u7D71\u82E5\u70BAwindows\u5247\u9700\u8981\u5B89\u88DDcurl\u5DE5\u5177\u624D\u80FD\u652F\u6301\u6AA2\u6E2C +Dec-DingTalk_Debugger-DownLoad_Log=\u4E0B\u8F09\u65E5\u8A8C +Dec-DingTalk_Click-To-Download=\u9EDE\u64CA\u4E0B\u8F09 +Dec-DingTalk_Download-Fail=\u4E0B\u8F09\u5931\u6557 +Dec-DingTalk_Not_Null=\u4E0D\u53EF\u70BA\u7A7A +Dec-DingTalk_ErrorDetail=\u932F\u8AA4\u8CC7\u8A0A +Dec-DingTalk_Debugger-Check-Ip-Result=\u6AA2\u67E5\u7D50\u679C +Dec-DingTalk_Debugger-Get-Token=access_token +Dec-DingTalk_Agent_Deleted_Tip=\u7121\u6CD5\u7372\u53D6\u8A72\u91D8\u91D8\u61C9\u7528\uFF0C\u8ACB\u6AA2\u67E5\u914D\u7F6E\u9805\u662F\u5426\u6709\u8AA4 +Dec-DingTalk_Parse_Parameters=\u89E3\u6790\u53C3\u6578\u503C +Dec-DingTalk_Parse_Parameters_Tip=\u5FAE\u4FE1\uFF0F\u91D8\u91D8\u6574\u5408\u9023\u7D50\u5FC5\u9808\u52FE\u9078\u89E3\u6790\u53C3\u6578\u503C\uFF0C\u5426\u5247\u5C07\u5C0E\u81F4\u53C3\u6578\u4E1F\u5931\uFF1B\u7BC4\u672C\u8A0A\u606F\u63A8\u9001\u7684\u8A0A\u606F\u9023\u7D50\u53EF\u9078\u64C7\u4E0D\u89E3\u6790\u53C3\u6578\u503C\uFF0C\u5F9E\u800C\u5BE6\u73FE\u63A8\u9001\u6642\u7684\u5BE6\u6642\u516C\u5F0F\u8A08\u7B97\u3002 +Dec-DingTalk_Enterprise_Agent=\u91D8\u91D8\u61C9\u7528 +Dec-DingTalk_Chatgroup_Name=\u91D8\u91D8\u7FA4\u540D\u7A31 +Dec-DingTalk_Chat_Group=\u91D8\u91D8\u7FA4 +Dec-DingTalk_New_Chat_Group=\u65B0\u5EFA\u91D8\u91D8\u7FA4 +Dec-DingTalk_Delete_ChatGroup_Confirm=\u78BA\u8A8D\u5220\u9664\u91D8\u91D8\u7FA4\uFF1F +Dec-DingTalk_Chat_Group_Member_Tip=\u9664\u7FA4\u4E3B\u5916\uFF0C\u4E0D\u53EF\u5C11\u65BC2\u4EBA +Dec-DingTalk_Chat_Group_Leader=\u7FA4\u4E3B +Dec-DingTalk_Chat_Group_Member=\u7FA4\u6210\u54E1 +Dec-DingTalk_New_Chat_Group_Tip1= +Dec-DingTalk_New_Chat_Group_Tip2= +Dec-DingTalk_New_Chat_Group_Message=\u60A8\u5DF2\u52A0\u5165\u7FA4\u804A +Dec-DingTalk_Common_Error_Tip=\u767C\u751F\u932F\u8AA4\uFF0C\u932F\u8AA4\u78BC\u70BA\uFF1A +Dec-DingTalk_Chat_Group_Name_Length_Tip=\u7FA4\u540D\u7A31\u9577\u5EA6\u965020\u500B\u5B57\u5143 +Dec-DingTalk_Create-Chat-Group-Fail=\u5275\u5EFA\u91D8\u91D8\u7FA4\u5931\u6557 +Dec-DingTalk_Output_User_Empty= +Dec-DingTalk_Message_Agent= +Dec-DingTalk_Message_Group= +Dec-DingTalk_DingTalk= +Dec-DingTalk_Output_User_Fail_Partly_Header= +Dec-DingTalk_Output_User_Fail_Partly_Tip= +Dec-DingTalk_Output_Group_Fail_Partly_Header= +Dec-DingTalk_Output_Group_Fail_Partly_Tip= +Dec-DingTalk_User_Match_Dec_User_Fail= \ No newline at end of file diff --git a/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/theme.js b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/theme.js new file mode 100644 index 0000000..17ed165 --- /dev/null +++ b/推送/src/main/resources/com/fr/plugin/yuyuan/dingding/theme.js @@ -0,0 +1,51 @@ +!(function () { + var DingtalkTerminalType = 32; + + Dec.Plugin.OutPutActionProvider.items.push({ + version: 1.0, + + terminalType: DingtalkTerminalType, + + terminalText: BI.i18nText("钉钉消息推送"), + + getItem: function () { + var self = this; + return { + type: "bi.label", + text: BI.i18nText("提示:勾选钉钉消息推送将实现图文消息推送至默认用户组"), + textAlign: "left", + cls: "bi-disabled", + height: 24, + ref: function (_ref) { + self.welinkItem = _ref; + } + } + }, + + setValue: function (v) { + if (v.terminal && v.terminal === DingtalkTerminalType) { + this.value = v; + } + }, + + getValue: function () { + var self = this; + // actionName最后一个点后面的类名要和这个return的json的字段名一致 + // console.log(123); + return { + FeiShuPushBean: BI.extend(self.value, { + "@class": "com.fr.plugin.yuyuan.dingding.bean.OutputDingTalk", + actionName: "com.fr.plugin.yuyuan.dingding.bean.OutputDingTalk", + terminal: DingtalkTerminalType + }) + } + }, + + checkValid: function () { + return this.getValue()?true:false; + }, + + fireEvent: function (v) { + } + }); +}) (); \ No newline at end of file diff --git a/推送/src/main/resources/dingtalk.properties b/推送/src/main/resources/dingtalk.properties new file mode 100644 index 0000000..76f07ba --- /dev/null +++ b/推送/src/main/resources/dingtalk.properties @@ -0,0 +1,3 @@ +yuyuan_syscode=xxxx +msg_type=xxxx +host=https://xxxx \ No newline at end of file