commit 2e3c918958616f6c5e5006b2e60e7b768c78499b Author: Roger.Chen Date: Fri Feb 11 15:16:53 2022 +0800 DEC-22054 feat:短信平台解耦demo插件 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..991a9d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.iml +.idea/ +lib/report/*.jar +target/ +.DS_Store \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..c56b872 --- /dev/null +++ b/build.gradle @@ -0,0 +1,122 @@ + +apply plugin: 'java' + + +ext { + /** + * 项目中依赖的jar的路径 + * 1.如果依赖的jar需要打包到zip中,放置在lib根目录下 + * 2.如果依赖的jar仅仅是编译时需要,防止在lib下子目录下即可 + */ + libPath = "$projectDir/../webroot/WEB-INF/lib" + + /** + * 是否对插件的class进行加密保护,防止反编译 + */ + guard = false + + def pluginInfo = getPluginInfo() + pluginPre = "fine-plugin" + pluginName = pluginInfo.id + pluginVersion = pluginInfo.version + + outputPath = "$projectDir/../webroot/WEB-INF/plugins/plugin-" + pluginName + "-1.0/classes" +} + +group = 'com.fr.plugin' +version = '10.0' +sourceCompatibility = '8' + +sourceSets { + main { + java.outputDir = file(outputPath) + output.resourcesDir = file(outputPath) + } +} + +ant.importBuild("encrypt.xml") +//定义ant变量 +ant.projectDir = projectDir +ant.references["compile.classpath"] = ant.path { + fileset(dir: libPath, includes: '**/*.jar') + fileset(dir: ".",includes:"**/*.jar" ) +} + +classes.dependsOn('clean') + +task copyFiles(type: Copy,dependsOn: 'classes'){ + from outputPath + into "$projectDir/classes" +} + +task preJar(type:Copy,dependsOn: guard ? 'compile_encrypt_javas' : 'compile_plain_javas'){ + from "$projectDir/classes" + into "$projectDir/transform-classes" + include "**/*.*" +} +jar.dependsOn("preJar") + +task makeJar(type: Jar,dependsOn: preJar){ + from fileTree(dir: "$projectDir/transform-classes") + baseName pluginPre + appendix pluginName + version pluginVersion + destinationDir = file("$buildDir/libs") + + doLast(){ + delete file("$projectDir/classes") + delete file("$projectDir/transform-classes") + } +} + +task copyFile(type: Copy,dependsOn: ["makeJar"]){ + from "$buildDir/libs" + from("$projectDir/lib") { + include "*.jar" + } + from "$projectDir/plugin.xml" + into file("$buildDir/temp/plugin") +} + +task zip(type:Zip,dependsOn:["copyFile"]){ + from "$buildDir/temp/plugin" + destinationDir file("$buildDir/install") + baseName pluginPre + appendix pluginName + version pluginVersion +} + +//控制build时包含哪些文件,排除哪些文件 +processResources { +// exclude everything +// 用*.css没效果 +// exclude '**/*.css' +// except this file +// include 'xx.xml' +} + +/*读取plugin.xml中的version*/ +def getPluginInfo(){ + def xmlFile = file("plugin.xml") + if (!xmlFile.exists()) { + return ["id":"none", "version":"1.0.0"] + } + def plugin = new XmlParser().parse(xmlFile) + def version = plugin.version[0].text() + def id = plugin.id[0].text() + return ["id":id,"version":version] +} + +repositories { + mavenLocal() + maven { + url = uri('http://mvn.finedevelop.com/repository/maven-public/') + } +} + +dependencies { + //使用本地jar + implementation fileTree(dir: 'lib', include: ['**/*.jar']) + implementation fileTree(dir: libPath, include: ['**/*.jar']) +} + diff --git a/encrypt.xml b/encrypt.xml new file mode 100644 index 0000000..1401cd1 --- /dev/null +++ b/encrypt.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..9ad59af --- /dev/null +++ b/plugin.xml @@ -0,0 +1,20 @@ + + + com.fr.plugin.decision.third.sms.v11 + + yes + 1.0 + 11.0 + 2019-11-06 + Lanlan + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5b65836 --- /dev/null +++ b/pom.xml @@ -0,0 +1,45 @@ + + + + plugin + com.fr.maven + 10.0 + + 4.0.0 + + fine-decision-sms-new-demo + + + + + ${web-inf-path}/plugins/plugin-com.fr.plugin.decision.third.sms.v11-2.0/classes + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + + com.fr.core + core-plugin-interface + 10.0 + compile + + + com.fr.core + core-project-plugin-interface + 10.0 + compile + + + + \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..cccfa1f --- /dev/null +++ b/readme.md @@ -0,0 +1,28 @@ +# 第三方短信平台插件 + +## 开启短信 + +使用该插件可以不使用帆软内置的短信平台,只需要在购买短信功能点后,通过插件使用自己的短信平台即可,为了方便展示客户自己的账号信息,可以自己在插件中提供短信配置信息的接口,如下图所示: +![open](screenshots/open.png) + +给管理员绑定手机号: +![open2](screenshots/open2.png) + +绑定好后如图: +![open3](screenshots/open3.png) + +开启短信验证密码: +![open4](screenshots/open4.png) + +## 测试方式 + +可以在登录决策平台后,访问管理系统->系统管理->短信,点击信息测试处的发送测试短信。 + +## 测试时获取验证码 + +可以直接在日志中看到要短信发送的内容。 + + + + + diff --git a/screenshots/open.png b/screenshots/open.png new file mode 100644 index 0000000..dbabc97 Binary files /dev/null and b/screenshots/open.png differ diff --git a/screenshots/open2.png b/screenshots/open2.png new file mode 100644 index 0000000..abb2b83 Binary files /dev/null and b/screenshots/open2.png differ diff --git a/screenshots/open3.png b/screenshots/open3.png new file mode 100644 index 0000000..5808231 Binary files /dev/null and b/screenshots/open3.png differ diff --git a/screenshots/open4.png b/screenshots/open4.png new file mode 100644 index 0000000..b1a5705 Binary files /dev/null and b/screenshots/open4.png differ diff --git a/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsComponent.java b/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsComponent.java new file mode 100644 index 0000000..8b56e17 --- /dev/null +++ b/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsComponent.java @@ -0,0 +1,16 @@ +package com.fr.plugin.decision.third.sms; + +import com.fr.web.struct.Component; +import com.fr.web.struct.browser.RequestClient; +import com.fr.web.struct.category.ParserType; +import com.fr.web.struct.category.ScriptPath; + +public class ThirdSmsComponent extends Component { + + public static final ThirdSmsComponent KEY = new ThirdSmsComponent(); + + @Override + public ScriptPath script(RequestClient req) { + return ScriptPath.build("com/fr/plugin/decision/third/sms/web/sms.js", ParserType.PLAIN); + } +} diff --git a/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsControllerProvider.java b/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsControllerProvider.java new file mode 100644 index 0000000..105de90 --- /dev/null +++ b/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsControllerProvider.java @@ -0,0 +1,13 @@ +package com.fr.plugin.decision.third.sms; + +import com.fr.decision.fun.impl.AbstractControllerRegisterProvider; +import com.fr.plugin.decision.third.sms.controller.ThirdSmsController; + +public class ThirdSmsControllerProvider extends AbstractControllerRegisterProvider { + @Override + public Class[] getControllers() { + return new Class[] { + ThirdSmsController.class + }; + } +} diff --git a/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsLocaleFinder.java b/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsLocaleFinder.java new file mode 100644 index 0000000..a6c789a --- /dev/null +++ b/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsLocaleFinder.java @@ -0,0 +1,11 @@ +package com.fr.plugin.decision.third.sms; + +import com.fr.stable.fun.impl.AbstractLocaleFinder; + +public class ThirdSmsLocaleFinder extends AbstractLocaleFinder { + + @Override + public String find() { + return "com/fr/plugin/decision/third/sms/locale/sms"; + } +} diff --git a/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsServiceProvider.java b/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsServiceProvider.java new file mode 100644 index 0000000..7d5e26b --- /dev/null +++ b/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsServiceProvider.java @@ -0,0 +1,131 @@ +package com.fr.plugin.decision.third.sms; + +import com.fr.base.sms.SMSContext; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.decision.third.sms.fun.SMSXmlReader; +import com.fr.plugin.decision.third.sms.fun.SmsClient; +import com.fr.plugin.transform.ExecuteFunctionRecord; +import com.fr.plugin.transform.FunctionRecorder; +import com.fr.stable.fun.impl.AbstractSMSServiceProvider; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@FunctionRecorder +public class ThirdSmsServiceProvider extends AbstractSMSServiceProvider { + + private static final String SMS_PUBLIC_MODEL = "public-model"; + private static final String SMS_PRIVATE_MODEL = "private-model"; + + public ThirdSmsServiceProvider() { + startListener(); + } + + @Override + public String sign() { + return SmsClient.getInstance().getSign(); + } + + /** + * 必须大于1,且跟js文件中的优先级保持一致 + * @return + */ + @Override + public int priority() { + return 20; + } + + @Override + public boolean isSMSAvailable() { + //根据具体情况看短信服务是否可用 + return true; + } + + /** + * 这里解析sms_template.xml文件中的模板返回,实际获取短信服务的模板 + * + * @return + */ + @Override + public Map> getSMSTemplate() { + Map> result = new HashMap<>(); + Map> smsTemplates = SmsClient.getInstance().getSMSTemplate(); + result.put("publicModel", convertSMSTemplateBeanList(smsTemplates.get(SMS_PUBLIC_MODEL))); + result.put("privateModel", convertSMSTemplateBeanList(smsTemplates.get(SMS_PRIVATE_MODEL))); + return result; + } + + /** + * 读取sms_template_mapping.xml配置文件中的映射规则 + * @return + */ + @Override + public Map mapping() { + Map map = new HashMap<>(); + Map templateMappings = SMSXmlReader.getSMSTemplateMappings(); + for (Map.Entry entry : templateMappings.entrySet()) { + JSONObject jsonObject = JSONObject.mapFrom(entry.getValue()); + if (jsonObject == null) { + continue; + } + map.put(entry.getKey(), jsonObject.getString("content")); + } + return map; + } + + @Override + public Response sendTest(String mobile) { + SmsClient.getInstance().send(mobile); + return Response.create(Response.RES_STATUS_SUCCESS, "新插件发送测试短信成功", JSONObject.create()); + } + + @Override + @ExecuteFunctionRecord + public Response send(String template, String mobile, JSONObject para, String receiver) throws Exception { + SmsClient.getInstance().send(template, mobile, para, receiver); + FineLoggerFactory.getLogger().info("短信模板:{}, 手机号:{},参数:{}", template, mobile, para); + return Response.create(Response.RES_STATUS_SUCCESS, "新插件发送普通短信成功", JSONObject.create()); + } + + @Override + public Response batchSendSMS(String template, List mobiles, JSONArray params, List receivers) throws Exception { + SmsClient.getInstance().batchSend(template, mobiles, params, receivers); + return Response.create(Response.RES_STATUS_SUCCESS, "新插件发送批量短信成功", JSONObject.create()); + } + + /** + * 启动发送短信的监听器 + */ + private void startListener() { + SMSContext.addSmsListener(new Listener() { + + @Override + public void beforeSend(String text, List mobiles, JSONArray params, List receivers) { + System.out.println("发送短信前监听事件"); + FineLoggerFactory.getLogger().info("发送短信前监听事件"); + } + + @Override + public void afterSend(String text, List mobiles, JSONArray params, List receivers, Response response) { + System.out.println("发送短信后监听事件"); + FineLoggerFactory.getLogger().info("发送短信后监听事件"); + } + }); + } + + private List convertSMSTemplateBeanList(Map map) { + List beanList = new ArrayList<>(); + for (Object data : map.values()) { + JSONObject json = JSONObject.mapFrom(data); + if (json == null) { + continue; + } + beanList.add(SMSTemplateBean.create(json.getString("id"), json.getString("content"), json.getString("language"))); + } + return beanList; + } +} diff --git a/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsWebResourceProvider.java b/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsWebResourceProvider.java new file mode 100644 index 0000000..70c2227 --- /dev/null +++ b/src/main/java/com/fr/plugin/decision/third/sms/ThirdSmsWebResourceProvider.java @@ -0,0 +1,17 @@ +package com.fr.plugin.decision.third.sms; + +import com.fr.decision.fun.impl.AbstractWebResourceProvider; +import com.fr.decision.web.MainComponent; +import com.fr.web.struct.Atom; + +public class ThirdSmsWebResourceProvider extends AbstractWebResourceProvider { + @Override + public Atom attach() { + return MainComponent.KEY; + } + + @Override + public Atom client() { + return ThirdSmsComponent.KEY; + } +} diff --git a/src/main/java/com/fr/plugin/decision/third/sms/controller/ThirdSmsController.java b/src/main/java/com/fr/plugin/decision/third/sms/controller/ThirdSmsController.java new file mode 100644 index 0000000..87f671a --- /dev/null +++ b/src/main/java/com/fr/plugin/decision/third/sms/controller/ThirdSmsController.java @@ -0,0 +1,29 @@ +package com.fr.plugin.decision.third.sms.controller; + +import com.fr.decision.webservice.Response; +import com.fr.decision.webservice.annotation.VisitRefer; +import com.fr.plugin.decision.third.sms.fun.SmsClient; +import com.fr.third.springframework.stereotype.Controller; +import com.fr.third.springframework.web.bind.annotation.PathVariable; +import com.fr.third.springframework.web.bind.annotation.RequestMapping; +import com.fr.third.springframework.web.bind.annotation.RequestMethod; +import com.fr.third.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Controller +@RequestMapping("/{version}/third/sms") +public class ThirdSmsController { + + @RequestMapping(method = RequestMethod.GET) + @ResponseBody + @VisitRefer(required = false) + public Response getSMSConfig(HttpServletRequest req, + HttpServletResponse res, + @PathVariable("version") String version) throws Exception { + + return Response.ok(SmsClient.getInstance().getSmsConfig()); + } + +} diff --git a/src/main/java/com/fr/plugin/decision/third/sms/fun/SMSXmlReader.java b/src/main/java/com/fr/plugin/decision/third/sms/fun/SMSXmlReader.java new file mode 100644 index 0000000..3970beb --- /dev/null +++ b/src/main/java/com/fr/plugin/decision/third/sms/fun/SMSXmlReader.java @@ -0,0 +1,73 @@ +package com.fr.plugin.decision.third.sms.fun; + +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class SMSXmlReader { + + private static final Map> SMS_TEMPLATES_MAP = new ConcurrentHashMap<>(); + private static final String SMS_PUBLIC_MODEL = "public-model"; + private static final String SMS_PRIVATE_MODEL = "private-model"; + + private static final String SMS_TEMPLATE_XML = "sms_template.xml"; + private static final String SMS_TEMPLATE_MAPPING_XML = "sms_template_mapping.xml"; + + public static Map getPublicSMSTemplates() { + return getSMSTemplates(SMS_TEMPLATE_XML, SMS_PUBLIC_MODEL); + } + + public static Map getPrivateSMSTemplates() { + return getSMSTemplates(SMS_TEMPLATE_XML, SMS_PRIVATE_MODEL); + } + + public static Map getSMSTemplateMappings() { + return getSMSTemplates(SMS_TEMPLATE_MAPPING_XML, SMS_PUBLIC_MODEL); + } + + public static Map getSMSTemplates(String xmlPath, String type) { + if (!SMS_TEMPLATES_MAP.containsKey(type)) { + synchronized (com.fr.base.sms.SMSXmlReader.class) { + Map map = new ConcurrentHashMap<>(); + readXML(map, xmlPath, type); + if (!map.isEmpty()) { + SMS_TEMPLATES_MAP.put(type, map); + } + } + } + return SMS_TEMPLATES_MAP.get(type); + } + + private static void readXML(Map map, String xmlFile, String nodeName) { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + String xmlPath = "com/fr/plugin/decision/third/sms/xml/".concat(xmlFile); + try { + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + dbf.setXIncludeAware(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document document = db.parse(SMSXmlReader.class.getClassLoader().getResourceAsStream(xmlPath)); + NodeList bookList = document.getElementsByTagName(nodeName); + for (int i = 0; i < bookList.getLength(); i++) { + Node node = bookList.item(i); + String id = node.getAttributes().getNamedItem("id").getTextContent(); + JSONObject jsonObject = JSONObject.create(); + jsonObject.put("id", id); + jsonObject.put("content", node.getAttributes().getNamedItem("content").getTextContent()); + jsonObject.put("language", node.getAttributes().getNamedItem("language").getTextContent()); + map.put(id, jsonObject); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } +} diff --git a/src/main/java/com/fr/plugin/decision/third/sms/fun/SmsClient.java b/src/main/java/com/fr/plugin/decision/third/sms/fun/SmsClient.java new file mode 100644 index 0000000..c0219f1 --- /dev/null +++ b/src/main/java/com/fr/plugin/decision/third/sms/fun/SmsClient.java @@ -0,0 +1,106 @@ +package com.fr.plugin.decision.third.sms.fun; + +import com.fr.base.sms.SMSTemplateType; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import com.fr.stable.fun.SMSServiceProvider; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/11/8 + * 这个是短信发送的客户端,调用各家实际短信发送平台,这里只通过输出日志的方式提供一个示例 + */ +public class SmsClient { + + private static final SmsClient instance = new SmsClient(); + private static final String SMS_PUBLIC_MODEL = "public-model"; + private static final String SMS_PRIVATE_MODEL = "private-model"; + + public static SmsClient getInstance() { + return instance; + } + + public String getSign() { + return "第三方短信"; + } + + /** + * 获取短信配置信息 + * + * @return 短信配置信息 + */ + public Map getSmsConfig() { + Map result = new HashMap<>(); + result.put("username", "优先级20"); + result.put("balance", 102.20); + result.put("isSmsAvailable", true); + result.put("accountType", 1); + result.put("publicModel", JSONArray.create(SMSXmlReader.getPublicSMSTemplates())); + result.put("privateModel", JSONArray.create(SMSXmlReader.getPrivateSMSTemplates())); + result.put("sign", getSign()); + + initSmsModels(result, "publicModel"); + initSmsModels(result, "privateModel"); + return result; + } + + public boolean send(String mobile) { + System.out.println("新插件(20)发送测试短信成功"); + FineLoggerFactory.getLogger().info("新插件(20)发送测试短信成功"); + return true; + } + + public boolean send(String template, String mobile, JSONObject para, String receiver) { + System.out.println("新插件(20)发送普通短信成功"); + FineLoggerFactory.getLogger().info("新插件(20)发送普通短信成功"); + return true; + } + + public boolean batchSend(String template, List mobiles, JSONArray params, List receivers) { + System.out.println("新插件(20)发送批量短信成功"); + FineLoggerFactory.getLogger().info("新插件(20)发送批量短信成功"); + return true; + } + + private void initSmsModels(Map result, String key) { + if (result.containsKey(key)) { + List> smsModels = new ArrayList>(); + JSONArray ja = (JSONArray) result.get(key); + for (int i = 0; i < ja.length(); i++) { + JSONObject jo = ja.optJSONObject(i); + Map map = new HashMap(); + String language = jo.optString("language"); + if (StringUtils.isNotEmpty(language) && StringUtils.equals(key, "publicModel") && !StringUtils.equals(language, SMSTemplateType.MAINLAND_SMS_TEMPLATE.getLanguage())) { + continue; + } + map.put("id", jo.optString("id")); + map.put("content", jo.optString("content")); + map.put("language", language); + smsModels.add(map); + } + result.put(key, smsModels); + } + } + + public Map> getSMSTemplate() { + Map> result = new HashMap<>(); + result.put(SMS_PUBLIC_MODEL, SMSXmlReader.getPublicSMSTemplates()); + result.put(SMS_PRIVATE_MODEL, SMSXmlReader.getPrivateSMSTemplates()); + return result; + } + +} \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms.properties b/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms_en.properties b/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms_en.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms_ja_JP.properties b/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms_ja_JP.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms_ko_KR.properties b/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms_ko_KR.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms_zh.properties b/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms_zh.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms_zh_TW.properties b/src/main/resources/com/fr/plugin/decision/third/sms/locale/sms_zh_TW.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/com/fr/plugin/decision/third/sms/web/sms.js b/src/main/resources/com/fr/plugin/decision/third/sms/web/sms.js new file mode 100644 index 0000000..92e1362 --- /dev/null +++ b/src/main/resources/com/fr/plugin/decision/third/sms/web/sms.js @@ -0,0 +1,236 @@ +// 邮箱配置组件的注册过程一共分为4步: + +// 1.基础配置 +var PRIORITY = 20; // 优先级(需要跟ThirdSmsServiceProvider#priority方法返回值一致),必须大于1,当有多个组件注册时,只有优先级最高的组件才会起作用 +var WIDGET_TYPE = 'demo.system.sms.config'; // 组件名称 +var MODEL_TYPE = 'demo.model.system.sms.config'; // 模型名称 + +// 2.定义组件 +var LAYOUT = { + ITEM_HEIGHT: 24, + ITEM_GAP: 15, + LABEL_WIDTH: 120, +}; +var Widget = BI.inherit(BI.Pane, { + props: { + baseCls: 'demo-system-sms-config', + }, + + _store: function () { + return BI.Models.getModel(MODEL_TYPE); + }, + + watch: { + 'config.balance': function (value) { + this.balanceLabel.setText(config.balance + BI.i18nText('Dec-Basic_RMB')); + this.testButton.setEnable(value > 0); + }, + }, + + beforeRender: function (callback) { + var self = this; + self.loading(); + this.store.requestGetConfig(function () { + callback(); + self.loaded(); + }); + }, + + render: function () { + var self = this; + var config = self.model.config; + + return { + type: 'bi.vertical', + bgap: LAYOUT.ITEM_GAP, + items: [ + // 账号绑定 + { + type: 'bi.vertical_adapt', + height: LAYOUT.ITEM_HEIGHT, + items: [ + { + type: 'bi.label', + cls: 'dec-font-weight-bold', + width: LAYOUT.LABEL_WIDTH, + text: BI.i18nText('Dec-System_SMS_Account_Bind'), + textAlign: 'left', + title: BI.i18nText('Dec-System_SMS_Account_Bind'), + }, + { + type: 'bi.label', + text: config.username, + textAlign: 'left', + }, + ], + }, + // 账号余额 + { + type: 'bi.vertical_adapt', + height: LAYOUT.ITEM_HEIGHT, + items: [ + { + type: 'bi.label', + cls: 'dec-font-weight-bold', + width: LAYOUT.LABEL_WIDTH, + text: BI.i18nText('Dec-System_SMS_Account_Balance'), + textAlign: 'left', + title: BI.i18nText('Dec-System_SMS_Account_Balance'), + }, + { + type: 'bi.label', + ref: function (_ref) { + self.balanceLabel = _ref; + }, + text: config.balance + BI.i18nText('Dec-Basic_RMB'), + textAlign: 'left', + }, + ], + }, + // 短信签名 + { + type: 'bi.vertical_adapt', + height: LAYOUT.ITEM_HEIGHT, + items: [ + { + type: 'bi.label', + cls: 'dec-font-weight-bold', + width: LAYOUT.LABEL_WIDTH, + text: BI.i18nText('Dec-System_SMS_Signatures'), + textAlign: 'left', + title: BI.i18nText('Dec-System_SMS_Signatures'), + }, + { + type: 'bi.label', + text: config.sign, + textAlign: 'left', + }, + ], + }, + // 信息测试 + { + type: 'bi.vertical_adapt', + height: LAYOUT.ITEM_HEIGHT, + items: [ + { + type: 'bi.label', + cls: 'dec-font-weight-bold', + width: LAYOUT.LABEL_WIDTH, + text: BI.i18nText('Dec-System_SMS_Test'), + textAlign: 'left', + title: BI.i18nText('Dec-System_SMS_Test'), + }, + { + type: 'bi.button', + ref: function (_ref) { + self.testButton = _ref; + }, + text: BI.i18nText('Dec-System_Send_Test_SMS'), + textAlign: 'left', + clear: true, + disabled: config.balance <= 0, + handler: function () { + self._sendTestMessage(); + }, + }, + ], + }, + ], + }; + }, + + /** + * 发送测试短信 + */ + _sendTestMessage: function () { + var self = this; + var popoverName = BI.UUID(); + BI.Popovers.create(popoverName, { + type: 'bi.popover', + width: 450, + height: 220, + header: BI.i18nText('Dec-System_Send_Test_Sms'), + body: { + type: 'dec.send.test.msg.dialog', + listeners: [ + { + eventName: BI.Popover.EVENT_CONFIRM, + action: function (phone) { + self.store.requsetSendTestMessage(phone); + }, + }, + { + eventName: BI.Popover.EVENT_CLOSE, + action: function () { + BI.Popovers.remove(popoverName); + }, + }, + ], + }, + }); + BI.Popovers.show(popoverName); + }, +}); + +// 3.定义模型 +var Model = BI.inherit(Fix.Model, { + state: function () { + return { + config: { + isSmsAvailable: true, + accountType: 1, + username: '', + balance: 0, + sign: '', + publicModel: [], + privateModel: [], + }, + }; + }, + + actions: { + /** + * 获取邮箱配置 + * @param {Function} callback beforeRender的回调 + */ + requestGetConfig: function (callback) { + var self = this; + // 发送请求,获取配置 + Dec.reqGetHandle('/v10/third/sms', '', function (data) { + self.model.config = data; + BI.isFunction(callback) && callback(); + }); + }, + + /** + * 发送测试邮件 + * @param {string} phone 收件人号码 + */ + requsetSendTestMessage: function (phone) { + var self = this; + Dec.reqPost( + '/v10/config/sms/test', + { + mobile: phone, + }, + function (result) { + if (result && result.data && result.data.code === 'success') { + BI.Msg.toast(BI.i18nText('Dec-Send_Success'), { level: 'success' }); + } else { + BI.Msg.toast(BI.i18nText('Dec-System_SMS_Send_Fail'), { + level: 'error', + }); + } + self.requestGetConfig(); + } + ); + }, + }, +}); + +// 4.注册组件 +BI.shortcut(WIDGET_TYPE, Widget); // 注册组件 +BI.model(MODEL_TYPE, Model); // 注册模型 +BI.config('dec.provider.system', function (provider) { + provider.registerSmsConfigWidget(WIDGET_TYPE, PRIORITY); // 注册邮箱配置组件 +}); diff --git a/src/main/resources/com/fr/plugin/decision/third/sms/xml/sms_template.xml b/src/main/resources/com/fr/plugin/decision/third/sms/xml/sms_template.xml new file mode 100644 index 0000000..4816b1b --- /dev/null +++ b/src/main/resources/com/fr/plugin/decision/third/sms/xml/sms_template.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/decision/third/sms/xml/sms_template_mapping.xml b/src/main/resources/com/fr/plugin/decision/third/sms/xml/sms_template_mapping.xml new file mode 100644 index 0000000..dbf944c --- /dev/null +++ b/src/main/resources/com/fr/plugin/decision/third/sms/xml/sms_template_mapping.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file