diff --git a/README.md b/README.md
index 30165b8..1a93767 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
# open-JSD-8016
-JSD-8016 开源任务材料
\ No newline at end of file
+JSD-8016 开源任务代码\
+免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
+仅作为开发者学习参考使用!禁止用于任何商业用途!\
+为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。
\ No newline at end of file
diff --git a/doc/钉钉扫码多公司版本配置说明.docx b/doc/钉钉扫码多公司版本配置说明.docx
new file mode 100644
index 0000000..d00e10f
Binary files /dev/null and b/doc/钉钉扫码多公司版本配置说明.docx differ
diff --git a/lib/fr-plugin-dingtalk-10.4.983.jar b/lib/fr-plugin-dingtalk-10.4.983.jar
new file mode 100644
index 0000000..a4f0202
Binary files /dev/null and b/lib/fr-plugin-dingtalk-10.4.983.jar differ
diff --git a/lib/hutool-all-4.3.2.jar b/lib/hutool-all-4.3.2.jar
new file mode 100644
index 0000000..e651efb
Binary files /dev/null and b/lib/hutool-all-4.3.2.jar differ
diff --git a/lib/taobao-sdk-java-auto_1479188381469-20200420.jar b/lib/taobao-sdk-java-auto_1479188381469-20200420.jar
new file mode 100644
index 0000000..0366c65
Binary files /dev/null and b/lib/taobao-sdk-java-auto_1479188381469-20200420.jar differ
diff --git a/plugin.xml b/plugin.xml
new file mode 100644
index 0000000..9dec2a4
--- /dev/null
+++ b/plugin.xml
@@ -0,0 +1,39 @@
+
+
+ com.fr.plugin.sln5470
+
+ yes
+ 1.1.5
+ 10.0
+ 2021-01-01
+ fr.open
+
+
+
+ [2020-04-22]项目启动
+ [2020-11-19]修复路径404bug
+ [2020-11-19]只开启扫码功能
+ [2021-02-02]插件对于新版本钉钉插件依赖关系,必须要安装钉钉插件后才能使用。
+ [2021-05-26]适配新版本登录界面按钮。
+ ]]>
+
+ com.fr.plugin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/fr/plugin/AllScanBeans.java b/src/main/java/com/fr/plugin/AllScanBeans.java
new file mode 100644
index 0000000..f797756
--- /dev/null
+++ b/src/main/java/com/fr/plugin/AllScanBeans.java
@@ -0,0 +1,59 @@
+package com.fr.plugin;
+
+import com.fr.decision.fun.impl.BaseHttpHandler;
+import com.fr.decision.webservice.Response;
+import com.fr.plugin.beans.ScanConfigBean;
+import com.fr.plugin.context.PluginContexts;
+import com.fr.third.fasterxml.jackson.core.JsonGenerationException;
+import com.fr.third.fasterxml.jackson.databind.JsonMappingException;
+import com.fr.third.fasterxml.jackson.databind.ObjectMapper;
+import com.fr.third.springframework.web.bind.annotation.RequestMethod;
+import com.fr.web.utils.WebUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.List;
+
+public class AllScanBeans extends BaseHttpHandler {
+ @Override
+ public RequestMethod getMethod() {
+ return RequestMethod.GET;
+ }
+
+ @Override
+ public String getPath() {
+ return "/getConfigBean";
+ }
+
+ @Override
+ public boolean isPublic() {
+ return true;
+ }
+
+ @Override
+ public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
+ List beanList = SCDBAccessProvider.like(null);
+ for (ScanConfigBean scanConfigBean : beanList) {
+ scanConfigBean.setAppSecret("");
+ scanConfigBean.setAppIdSecret("");
+ scanConfigBean.setAppKey("");
+ }
+ Response ok = Response.ok(beanList);
+ WebUtils.printAsString(httpServletResponse,serialize(ok));
+ }
+
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+
+ public static String serialize(Object object) {
+ Writer write = new StringWriter();
+ try {
+ objectMapper.writeValue(write, object);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return write.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/ConfigComponent.java b/src/main/java/com/fr/plugin/ConfigComponent.java
new file mode 100644
index 0000000..52fa698
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ConfigComponent.java
@@ -0,0 +1,51 @@
+package com.fr.plugin;
+
+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.FileType;
+import com.fr.web.struct.category.ScriptPath;
+import com.fr.web.struct.category.StylePath;
+
+public class ConfigComponent extends Component {
+ public static final ConfigComponent KEY = new ConfigComponent();
+
+ /**
+ * 返回需要引入的JS脚本路径
+ *
+ * @param client 请求客户端描述
+ * @return JS脚本路径
+ */
+ @Override
+ public ScriptPath script(RequestClient client) {
+ return ScriptPath.build("com/fr/plugin/web/dds/dds.js");
+ }
+
+ /**
+ * 返回需要引入的CSS样式路径
+ *
+ * @param client 请求客户端描述
+ * @return CSS样式路径
+ */
+ @Override
+ public StylePath style(RequestClient client) {
+ //如果不需要就直接返回 StylePath.EMPTY;
+ return StylePath.EMPTY;
+ }
+
+ /**
+ * 通过给定的资源过滤器控制是否加载这个资源
+ *
+ * @return 资源过滤器
+ */
+ @Override
+ public Filter filter() {
+ return new Filter() {
+ @Override
+ public boolean accept() {
+ //任何情况下我们都在平台组件加载时加载我们的组件
+ return true;
+ }
+ };
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ConfigJSHander.java b/src/main/java/com/fr/plugin/ConfigJSHander.java
new file mode 100644
index 0000000..7745183
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ConfigJSHander.java
@@ -0,0 +1,33 @@
+package com.fr.plugin;
+
+import com.fr.decision.fun.impl.AbstractWebResourceProvider;
+import com.fr.decision.web.MainComponent;
+import com.fr.web.struct.Atom;
+
+public class ConfigJSHander extends AbstractWebResourceProvider {
+
+ /**
+ * 需要附加到的主组件
+ *
+ * @return 主组件
+ */
+
+ @Override
+ public Atom attach() {
+ return MainComponent.KEY;
+ }
+
+ /**
+ * 客户端所需的组件
+ *
+ * @return 组件
+ */
+ @Override
+ public Atom client() {
+ return ConfigComponent.KEY;
+ }
+
+ public Atom[] clients() {
+ return new Atom[]{this.client()};
+ }
+}
diff --git a/src/main/java/com/fr/plugin/GetQRHandle.java b/src/main/java/com/fr/plugin/GetQRHandle.java
new file mode 100644
index 0000000..ed51c50
--- /dev/null
+++ b/src/main/java/com/fr/plugin/GetQRHandle.java
@@ -0,0 +1,42 @@
+package com.fr.plugin;
+
+import com.fr.decision.fun.impl.BaseHttpHandler;
+import com.fr.plugin.context.PluginContexts;
+import com.fr.third.springframework.web.bind.annotation.RequestMethod;
+import com.fr.web.utils.WebUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+
+public class GetQRHandle extends BaseHttpHandler {
+ @Override
+ public RequestMethod getMethod() {
+ return null;
+ }
+
+ @Override
+ public String getPath() {
+ return "/getQR";
+ }
+
+ @Override
+ public boolean isPublic() {
+ return true;
+ }
+
+ @Override
+ public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
+ ScanConfig instance = ScanConfig.getInstance();
+ HashMap params = new HashMap<>();
+ params.put("appId",instance.getAppId());
+ params.put("callback",httpServletRequest.getParameter("callback"));
+ if (PluginContexts.currentContext().isAvailable()) {
+ // 做认证通过的事情
+ WebUtils.writeOutTemplate("com/fr/new.html",httpServletResponse,params);
+ } else {
+ // 做认证未通过的事情
+ WebUtils.writeOutTemplate("com/fr/buynew.html",httpServletResponse,params);
+ }
+ }
+}
diff --git a/src/main/java/com/fr/plugin/HtmlUtils.java b/src/main/java/com/fr/plugin/HtmlUtils.java
new file mode 100644
index 0000000..dbd1925
--- /dev/null
+++ b/src/main/java/com/fr/plugin/HtmlUtils.java
@@ -0,0 +1,128 @@
+package com.fr.plugin;
+
+import com.dingtalk.api.DefaultDingTalkClient;
+import com.dingtalk.api.DingTalkClient;
+import com.dingtalk.api.request.OapiSnsGetuserinfoBycodeRequest;
+import com.dingtalk.api.request.OapiUserGetRequest;
+import com.dingtalk.api.request.OapiUserGetUseridByUnionidRequest;
+import com.dingtalk.api.response.OapiSnsGetuserinfoBycodeResponse;
+import com.dingtalk.api.response.OapiUserGetResponse;
+import com.dingtalk.api.response.OapiUserGetUseridByUnionidResponse;
+import com.fr.json.JSONObject;
+import com.fr.log.FineLoggerFactory;
+import com.fr.third.javax.annotation.Nullable;
+import com.taobao.api.ApiException;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class HtmlUtils {
+ public static String getUserUnid(String appId, String sercet, String code) {
+ DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/sns/getuserinfo_bycode");
+ OapiSnsGetuserinfoBycodeRequest req = new OapiSnsGetuserinfoBycodeRequest();
+ req.setTmpAuthCode(code);
+ try {
+ OapiSnsGetuserinfoBycodeResponse response = client.execute(req, appId, sercet);
+ FineLoggerFactory.getLogger().info("获取用户UNid详情:" + response.getBody());
+ String unionid = response.getUserInfo().getUnionid();
+ FineLoggerFactory.getLogger().info("获取用户unid:" + unionid);
+ return unionid;
+ } catch (ApiException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+
+ public static OapiUserGetResponse getUserMobByUnid(String unid, String appId, String appKey) throws Exception {
+
+ DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/getUseridByUnionid");
+ OapiUserGetUseridByUnionidRequest request = new OapiUserGetUseridByUnionidRequest();
+ request.setUnionid(unid);
+ request.setHttpMethod("GET");
+ String accessToken = getAccessToken(appId, appKey);
+ OapiUserGetUseridByUnionidResponse response = client.execute(request, accessToken);
+ FineLoggerFactory.getLogger().info("获取用户userId详情:" + response.getBody());
+ if (response.getErrcode() != 0) {
+ throw new Exception("访问接口报错:" + response.getErrmsg());
+ }
+ String userid = response.getUserid();
+ FineLoggerFactory.getLogger().info("获取用户UserId:" + userid);
+ OapiUserGetRequest userrequest = new OapiUserGetRequest();
+ client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/get");
+ userrequest.setUserid(userid);
+ userrequest.setHttpMethod("GET");
+ OapiUserGetResponse response1 = client.execute(userrequest, accessToken);
+ FineLoggerFactory.getLogger().info("获取用户mob详情:" + response1.getBody());
+ String mobile = response1.getMobile();
+ FineLoggerFactory.getLogger().info("获取用户手机号:" + mobile);
+ return response1;
+ }
+
+ private static String getAccessToken(String appid, String appkey) {
+ String url = String.format("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s", appid
+ , appkey);
+ JSONObject jsonObject = httpRequest(url, "GET", null);
+ if (jsonObject.getInt("errcode") == 0) {
+ return jsonObject.getString("access_token");
+ }
+ return "";
+ }
+
+ private static void closeStream(Closeable var0) {
+ if (var0 != null) {
+ try {
+ var0.close();
+ } catch (IOException var2) {
+ }
+
+ }
+ }
+
+ private static int CONNECTION_TIME_OUT = 120000;
+ private static int READ_TIME_OUT = 120000;
+
+ @Nullable
+ public static JSONObject httpRequest(String var0, String var1, String var2) {
+ JSONObject var3 = null;
+ StringBuilder var4 = new StringBuilder();
+ HttpURLConnection var5 = null;
+
+ try {
+ URL var6 = new URL(var0);
+ var5 = (HttpURLConnection) var6.openConnection();
+ var5.setUseCaches(false);
+ var5.setRequestMethod(var1);
+ var5.setConnectTimeout(CONNECTION_TIME_OUT);
+ var5.setReadTimeout(READ_TIME_OUT);
+ if (var2 != null) {
+ var5.setDoOutput(true);
+ var5.setRequestProperty("Content-Type", "application/json; charset=utf-8");
+ OutputStream var7 = var5.getOutputStream();
+ var7.write(var2.getBytes("UTF-8"));
+ closeStream(var7);
+ }
+
+ InputStream var16 = var5.getInputStream();
+ InputStreamReader var8 = new InputStreamReader(var16, "UTF-8");
+ BufferedReader var9 = new BufferedReader(var8);
+
+ String var10;
+ while ((var10 = var9.readLine()) != null) {
+ var4.append(var10);
+ }
+
+ closeStream(var9);
+ closeStream(var8);
+ closeStream(var16);
+ var3 = new JSONObject(var4.toString());
+ return var3;
+ } catch (Exception var14) {
+ } finally {
+ if (var5 != null) {
+ var5.disconnect();
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/LDAPLocalFinder.java b/src/main/java/com/fr/plugin/LDAPLocalFinder.java
new file mode 100644
index 0000000..aa55b05
--- /dev/null
+++ b/src/main/java/com/fr/plugin/LDAPLocalFinder.java
@@ -0,0 +1,10 @@
+package com.fr.plugin;
+
+import com.fr.stable.fun.impl.AbstractLocaleFinder;
+
+public class LDAPLocalFinder extends AbstractLocaleFinder {
+ @Override
+ public String find() {
+ return "/com/fr/plugin/i18n/lan";
+ }
+}
diff --git a/src/main/java/com/fr/plugin/PluginInitializeFilterBridge.java b/src/main/java/com/fr/plugin/PluginInitializeFilterBridge.java
new file mode 100644
index 0000000..a354535
--- /dev/null
+++ b/src/main/java/com/fr/plugin/PluginInitializeFilterBridge.java
@@ -0,0 +1,21 @@
+package com.fr.plugin;
+
+import com.fr.decision.fun.impl.AbstractEmbedRequestFilterProvider;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class PluginInitializeFilterBridge extends AbstractEmbedRequestFilterProvider {
+ @Override
+ public void init(FilterConfig filterConfig) {
+ ScanConfig.getInstance();
+ }
+
+ @Override
+ public void filter(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException {
+
+ }
+}
diff --git a/src/main/java/com/fr/plugin/SCDBAccessProvider.java b/src/main/java/com/fr/plugin/SCDBAccessProvider.java
new file mode 100644
index 0000000..58eb6a9
--- /dev/null
+++ b/src/main/java/com/fr/plugin/SCDBAccessProvider.java
@@ -0,0 +1,153 @@
+package com.fr.plugin;
+
+import com.fr.db.fun.impl.AbstractDBAccessProvider;
+import com.fr.decision.base.util.UUIDUtil;
+import com.fr.log.FineLoggerFactory;
+import com.fr.plugin.beans.ScanConfigBean;
+import com.fr.plugin.dao.ScanConfigDao;
+import com.fr.plugin.entitys.ScanConfigEntity;
+import com.fr.stable.StringUtils;
+import com.fr.stable.db.accessor.DBAccessor;
+import com.fr.stable.db.action.DBAction;
+import com.fr.stable.db.dao.DAOContext;
+import com.fr.stable.db.dao.DAOProvider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SCDBAccessProvider extends AbstractDBAccessProvider {
+
+ private static DBAccessor accessor;
+ @Override
+ public DAOProvider[] registerDAO() {
+ return new DAOProvider[]{
+ ScanConfigDao.DAO
+ };
+ }
+
+ public static DBAccessor getAccessor() {
+ return accessor;
+ }
+
+ public static void setAccessor(DBAccessor accessor) {
+ SCDBAccessProvider.accessor = accessor;
+ }
+
+ @Override
+ public void onDBAvailable(DBAccessor dbAccessor) {
+ SCDBAccessProvider.accessor = dbAccessor;
+ }
+
+ /**
+ * 业务对象——增
+ * @param bean
+ */
+ public static void add( final ScanConfigBean bean ){
+ try{
+ accessor.runDMLAction(new DBAction() {
+ @Override
+ public Boolean run(DAOContext context) throws Exception {
+ context.getDAO(ScanConfigDao.class).add( loadScanConfigEntity(bean,true) );
+ return true;
+ }
+ });
+ }catch(Throwable e){
+ FineLoggerFactory.getLogger().error(e,"Add ScanConfigBean Error:{}",e.getMessage());
+ }
+ }
+
+ /**
+ * 业务对象——删
+ * @param id
+ */
+ public static ScanConfigBean delete( final String id ){
+ try{
+ return accessor.runDMLAction(new DBAction() {
+ @Override
+ public ScanConfigBean run(DAOContext context) throws Exception {
+ ScanConfigEntity entity = context.getDAO(ScanConfigDao.class).getById(id);
+ if( null == entity ){
+ return null;
+ }
+ context.getDAO(ScanConfigDao.class).remove( id );
+ return toScanConfigBean(entity);
+ }
+ });
+ }catch(Throwable e){
+ FineLoggerFactory.getLogger().error(e,"Delete ScanConfigBean[{}] Error:{}",id,e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * 业务对象——改
+ * @param bean
+ */
+ public static void update( ScanConfigBean bean ){
+ try{
+ accessor.runDMLAction(new DBAction() {
+ @Override
+ public Boolean run(DAOContext context) throws Exception {
+ context.getDAO(ScanConfigDao.class).update( loadScanConfigEntity(bean,false) );
+ return true;
+ }
+ });
+ }catch(Throwable e){
+ FineLoggerFactory.getLogger().error(e,"Update ScanConfigBean Error:{}",e.getMessage());
+ }
+ }
+
+
+ private static ScanConfigEntity loadScanConfigEntity( ScanConfigBean bean, boolean isAdd ){
+ ScanConfigEntity entity = new ScanConfigEntity();
+ if(isAdd || StringUtils.isEmpty( bean.getId() ) ){
+ bean.setId(UUIDUtil.generate());
+ }
+ entity.setId( bean.getId() );
+ entity.setAppFlag( bean.getAppFlag() );
+ entity.setAppId( bean.getAppId() );
+ entity.setAppName( bean.getAppName() );
+ entity.setAppKey( bean.getAppKey() );
+ entity.setAppIdSecret( bean.getAppIdSecret() );
+ entity.setAppSecret( bean.getAppSecret() );
+ return entity;
+ }
+
+ private static ScanConfigBean toScanConfigBean( ScanConfigEntity entity ){
+ ScanConfigBean bean = new ScanConfigBean();
+ bean.setId( entity.getId() );
+ bean.setAppId( entity.getAppId() );
+ bean.setAppName( entity.getAppName() );
+ bean.setAppKey(entity.getAppKey());
+ bean.setAppIdSecret(entity.getAppIdSecret());
+ bean.setAppSecret(entity.getAppSecret());
+ bean.setAppFlag(entity.getAppFlag());
+ return bean;
+ }
+
+
+
+ /**
+ * 业务对象——查
+ * @param key
+ * @return
+ */
+ public static List like(String key ){
+ try{
+ return accessor.runQueryAction(new DBAction>() {
+ @Override
+ public List run(DAOContext context) throws Exception {
+ List result = new ArrayList();
+ List list = context.getDAO(ScanConfigDao.class).likeByKey(key);
+ for (ScanConfigEntity scanConfigEntity : list) {
+ result.add(toScanConfigBean(scanConfigEntity));
+ }
+ return result;
+ }
+ });
+ }catch(Throwable e){
+ FineLoggerFactory.getLogger().error(e,"Get ScanConfigBeans{} Error:{}",key,e.getMessage());
+ }
+ return new ArrayList();
+ }
+}
diff --git a/src/main/java/com/fr/plugin/SacnCycleMonitor.java b/src/main/java/com/fr/plugin/SacnCycleMonitor.java
new file mode 100644
index 0000000..b326e78
--- /dev/null
+++ b/src/main/java/com/fr/plugin/SacnCycleMonitor.java
@@ -0,0 +1,15 @@
+package com.fr.plugin;
+
+import com.fr.plugin.context.PluginContext;
+import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
+
+public class SacnCycleMonitor extends AbstractPluginLifecycleMonitor {
+ @Override
+ public void afterRun(PluginContext pluginContext) {
+ ScanConfig instance = ScanConfig.getInstance();
+ }
+
+ @Override
+ public void beforeStop(PluginContext pluginContext) {
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ScanCallBackHandle.java b/src/main/java/com/fr/plugin/ScanCallBackHandle.java
new file mode 100644
index 0000000..7bcf778
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ScanCallBackHandle.java
@@ -0,0 +1,292 @@
+package com.fr.plugin;
+
+import com.dingtalk.api.response.OapiUserGetResponse;
+import com.fr.base.TableData;
+import com.fr.base.TemplateUtils;
+import com.fr.data.NetworkHelper;
+import com.fr.decision.authority.AuthorityContext;
+import com.fr.decision.authority.data.User;
+import com.fr.decision.fun.impl.BaseHttpHandler;
+import com.fr.decision.mobile.terminal.TerminalHandler;
+import com.fr.decision.webservice.bean.authentication.OriginUrlResponseBean;
+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.file.DatasourceManager;
+import com.fr.general.ComparatorUtils;
+import com.fr.general.data.DataModel;
+import com.fr.log.FineLoggerFactory;
+import com.fr.plugin.beans.ScanConfigBean;
+import com.fr.plugin.dao.ScanConfigDao;
+import com.fr.plugin.dingtalk.server.config.DingTalkConfig;
+import com.fr.plugin.dingtalk.server.config.DingTalkMemberManagementConfig;
+import com.fr.plugin.dingtalk.server.helper.DingTalkDecUserHelper;
+import com.fr.plugin.dingtalk.server.helper.DingTalkUserHelper;
+import com.fr.plugin.dingtalk.server.log.DingTalkLoggerFactory;
+import com.fr.plugin.entitys.ScanConfigEntity;
+import com.fr.script.Calculator;
+import com.fr.security.JwtUtils;
+import com.fr.stable.StringUtils;
+import com.fr.stable.db.action.DBAction;
+import com.fr.stable.db.dao.DAOContext;
+import com.fr.stable.query.QueryFactory;
+import com.fr.stable.query.restriction.RestrictionFactory;
+import com.fr.stable.web.Device;
+import com.fr.third.springframework.web.bind.annotation.RequestMethod;
+import com.fr.web.utils.WebUtils;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class ScanCallBackHandle extends BaseHttpHandler {
+ @Override
+ public RequestMethod getMethod() {
+ return null;
+ }
+
+ @Override
+ public String getPath() {
+ return "/scanLogin";
+ }
+
+ @Override
+ public boolean isPublic() {
+ return true;
+ }
+
+ @Override
+ public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
+ String code = WebUtils.getHTTPRequestParameter(httpServletRequest, "code");
+ FineLoggerFactory.getLogger().info("鉴权成功!拿到的code为:" + code);
+ String state = WebUtils.getHTTPRequestParameter(httpServletRequest, "state");
+ if (StringUtils.isBlank(code)) {
+ WebUtils.printAsString(httpServletResponse, "本接口仅限钉钉调用");
+ return;
+ }
+ if (StringUtils.isNotBlank(state)) {
+ ScanConfigEntity entity = SCDBAccessProvider.getAccessor().runQueryAction(context -> {
+ List entities = context.getDAO(ScanConfigDao.class).find(QueryFactory.create().addRestriction(RestrictionFactory.eq("appId", state)));
+ return entities.get(0);
+ });
+ if (entity != null) {
+ String appId = entity.getAppId();
+ String secret = entity.getAppIdSecret();
+ String appKey = entity.getAppKey();
+ String appSecret = entity.getAppSecret();
+ String userUnid = HtmlUtils.getUserUnid(appId, secret, code);
+ OapiUserGetResponse userMob = HtmlUtils.getUserMobByUnid(userUnid,appKey,appSecret);
+ String userName = dingTalkUserToDecUser(userMob);
+ if (userName != null) {
+ if (isUserExist(userName)) {
+ String token = login(httpServletRequest, httpServletResponse, userName);
+ FineLoggerFactory.getLogger().debug("单点登录成功!生成token为:" + token);
+ String callBack = httpServletRequest.getParameter("redirectUrl");
+ Cookie[] cookies = httpServletRequest.getCookies();
+ for (Cookie cookie : cookies) {
+ if (StringUtils.equals(cookie.getName(), "myorgin")) {
+ String value = cookie.getValue();
+ try {
+ cookie.setMaxAge(0);//删除cookies
+ String originUrl = ((OriginUrlResponseBean) DecisionStatusService.originUrlStatusService().get(value)).getOriginUrl();
+ httpServletResponse.addCookie(cookie);
+ sendRedirect(httpServletResponse, originUrl);
+ return;
+ } catch (Exception e) {
+ }
+ }
+ }
+ if (StringUtils.isNotBlank(callBack)) {
+ sendRedirect(httpServletResponse, callBack);
+ } else {
+ sendRedirect(httpServletResponse, getHomeURI(httpServletRequest));
+ }
+ return;
+ } else {
+ FineLoggerFactory.getLogger().warn(String.format("平台用户中无%s用户!", userMob));
+ }
+ }
+ }
+ }
+
+ WebUtils.printAsString(httpServletResponse, "扫码获取用户信息失败");
+ return;
+ }
+
+
+ /**
+ * 通过钉钉认证之后的响应 来获取用户名
+ *
+ * @param userMob
+ * @return
+ * @throws Exception
+ */
+ public static String dingTalkUserToDecUser(OapiUserGetResponse userMob) throws Exception {
+ DingTalkMemberManagementConfig config = DingTalkConfig.getInstance().getMemberManagementConfig();
+ if (userMob != null && config != null) {
+ String jobNumber;
+ jobNumber = null;
+ String userid = userMob.getUserid();
+ label65:
+ switch (config.getMatchingFSWay()) {
+ case 0:
+ FineLoggerFactory.getLogger().debug("当前匹配方式为工号匹配");
+ jobNumber = userMob.getJobnumber();
+ break;
+ case 1:
+ FineLoggerFactory.getLogger().debug("当前匹配方式为手机号匹配");
+ String mobile = userMob.getMobile();
+ if (StringUtils.isEmpty(mobile)) {
+ FineLoggerFactory.getLogger().warn("未能获取到该钉钉用户%s的手机号,请于钉钉管理后台中核查!");
+ } else {
+ List var11 = AuthorityContext.getInstance().getUserController().find(QueryFactory.create().addRestriction(RestrictionFactory.eq("mobile", mobile)));
+ if (var11 != null && !var11.isEmpty()) {
+ Iterator var12 = var11.iterator();
+
+ while (true) {
+ if (!var12.hasNext()) {
+ break label65;
+ }
+
+ User var13 = (User) var12.next();
+ if (var13.isEnable()) {
+ jobNumber = var13.getUserName();
+ break label65;
+ }
+
+ FineLoggerFactory.getLogger().warn(String.format("当前平台用户%s被禁用,请在决策平台用户管理中设置!", var13.getUserName()));
+ }
+ } else {
+ FineLoggerFactory.getLogger().warn(String.format("没有在平台用户中找到手机号为%s的用户!", mobile));
+ }
+ }
+ break;
+ case 2:
+ FineLoggerFactory.getLogger().debug("当前匹配方式为手动匹配");
+ jobNumber = DingTalkUserHelper.getDecUserName(userid);
+ if (StringUtils.isEmpty(jobNumber)) {
+ FineLoggerFactory.getLogger().warn(String.format("请检查fine_dingtalk_user_relation表中是否存在dingTalkUser为%s的用户匹配关系", userid));
+ }
+ break;
+ case 3:
+ FineLoggerFactory.getLogger().debug("当前匹配方式为数据集匹配");
+ if (StringUtils.isNotEmpty(config.getDataSet())) {
+ TableData var5 = DatasourceManager.getInstance().getTableData(config.getDataSet());
+ DataModel var6 = var5.createDataModel(Calculator.createCalculator());
+
+ for (int var7 = 0; var7 < var6.getRowCount(); ++var7) {
+ int var8 = config.getDataSetDingTalkUserIdColumn();
+ if (ComparatorUtils.equals(var6.getValueAt(var7, var8).toString(), userid)) {
+ int var9 = config.getDataSetFsUserNameColumn();
+ jobNumber = var6.getValueAt(var7, var9).toString();
+ FineLoggerFactory.getLogger().debug(String.format("匹配第%s行第%s列的平台用户为:" + jobNumber, var7, var9));
+ User var10 = DingTalkDecUserHelper.getDecUserByName(jobNumber);
+ if (var10 != null) {
+ if (var10.isEnable()) {
+ break;
+ }
+
+ FineLoggerFactory.getLogger().warn(String.format("数据集中%s用户对应平台用户不可用", jobNumber));
+ } else {
+ FineLoggerFactory.getLogger().warn(String.format("数据集中%s用户不在平台用户中", jobNumber));
+ }
+ }
+ }
+ } else {
+ FineLoggerFactory.getLogger().warn("没有设置匹配数据集,请在钉钉管理中设置!");
+ }
+ }
+ if (StringUtils.isEmpty(jobNumber)) {
+ FineLoggerFactory.getLogger().warn("钉钉用户匹配平台用户失败!");
+ } else {
+ FineLoggerFactory.getLogger().debug("钉钉用户匹配平台用户结果为:" + jobNumber);
+ }
+
+ return jobNumber;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * 登录
+ *
+ * @param req
+ * @param res
+ * @param username
+ * @return
+ */
+ private String login(HttpServletRequest req, HttpServletResponse res, String username) {
+ try {
+ String oldToken = TokenResource.COOKIE.getToken(req);
+ if ((oldToken == null) || (!checkTokenValid(req, oldToken, username))) {
+ String token = LoginService.getInstance().login(req, res, username);
+ req.setAttribute("fine_auth_token", token);
+ FineLoggerFactory.getLogger().error("fr CookieFilter is over with username is ###" + username);
+ return token;
+ } else {
+ FineLoggerFactory.getLogger().error("no need login: {}", username);
+ }
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(), e);
+ }
+ return "";
+ }
+
+ /**
+ * 校验token是否有效
+ */
+ public static boolean checkTokenValid(HttpServletRequest req, String token, String currentUserName) {
+ try {
+ //当前登录用户和token对应的用户名不同,需要重新生成token
+ if (!ComparatorUtils.equals(currentUserName, JwtUtils.parseJWT(token).getSubject())) {
+ FineLoggerFactory.getLogger().info("username changed:" + currentUserName);
+ return false;
+ }
+ Device device = NetworkHelper.getDevice(req);
+ LoginService.getInstance().loginStatusValid(token, TerminalHandler.getTerminal(req, device));
+ return true;
+ } catch (Exception ignore) {
+ return false;
+ }
+ }
+
+ private User getUserByMob(String mob) throws Exception {
+ List mobile = AuthorityContext.getInstance().getUserController().find(QueryFactory.create().addRestriction(RestrictionFactory.eq("mobile", mob)));
+ if (!mobile.isEmpty()) {
+ return mobile.get(0);
+ }
+ return null;
+ }
+
+ public boolean isUserExist(String var0) {
+ if (StringUtils.isEmpty(var0)) {
+ return false;
+ } else {
+ try {
+ List var1 = AuthorityContext.getInstance().getUserController().find(QueryFactory.create().addRestriction(RestrictionFactory.eq("userName", var0)));
+ return var1 != null && !var1.isEmpty();
+ } catch (Exception var2) {
+ return false;
+ }
+ }
+ }
+
+ private void sendRedirect(HttpServletResponse res, String url) {
+ res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ res.setHeader("Location", url);
+ }
+
+ private String getHomeURI(HttpServletRequest request) {
+ String url = "/";
+ try {
+ url = TemplateUtils.render("${fineServletURL}");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return url;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ScanComponent.java b/src/main/java/com/fr/plugin/ScanComponent.java
new file mode 100644
index 0000000..3a45391
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ScanComponent.java
@@ -0,0 +1,51 @@
+package com.fr.plugin;
+
+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.FileType;
+import com.fr.web.struct.category.ScriptPath;
+import com.fr.web.struct.category.StylePath;
+
+public class ScanComponent extends Component {
+ public static final ScanComponent KEY = new ScanComponent();
+
+ /**
+ * 返回需要引入的JS脚本路径
+ *
+ * @param client 请求客户端描述
+ * @return JS脚本路径
+ */
+ @Override
+ public ScriptPath script(RequestClient client) {
+ return ScriptPath.build("com.fr.plugin.ScanJS&time=" + System.currentTimeMillis(), FileType.CLASS);
+ }
+
+ /**
+ * 返回需要引入的CSS样式路径
+ *
+ * @param client 请求客户端描述
+ * @return CSS样式路径
+ */
+ @Override
+ public StylePath style(RequestClient client) {
+ //如果不需要就直接返回 StylePath.EMPTY;
+ return StylePath.EMPTY;
+ }
+
+ /**
+ * 通过给定的资源过滤器控制是否加载这个资源
+ *
+ * @return 资源过滤器
+ */
+ @Override
+ public Filter filter() {
+ return new Filter() {
+ @Override
+ public boolean accept() {
+ //任何情况下我们都在平台组件加载时加载我们的组件
+ return true;
+ }
+ };
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ScanConfig.java b/src/main/java/com/fr/plugin/ScanConfig.java
new file mode 100644
index 0000000..1f20e85
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ScanConfig.java
@@ -0,0 +1,108 @@
+package com.fr.plugin;
+
+import com.fr.config.*;
+import com.fr.config.holder.Conf;
+import com.fr.config.holder.factory.Holders;
+
+@Visualization(category = "钉钉扫码配置")
+public class ScanConfig extends DefaultConfiguration {
+ private static volatile ScanConfig config = null;
+
+ public static ScanConfig getInstance() {
+ if (config == null) {
+ config = ConfigContext.getConfigInstance(ScanConfig.class);
+ }
+ return config;
+ }
+
+ @Identifier(value = "AppId", name = "扫码AppID", description = "", status = Status.SHOW)
+ private Conf appId = Holders.simple("");
+
+ @Identifier(value = "Secret", name = "扫码app_secret", description = "", status = Status.SHOW)
+ private Conf secret = Holders.simple("");
+
+// @Identifier(value = "loginKey", name = "登录AppKey", description = "", status = Status.SHOW)
+// private Conf loginKey = Holders.simple("");
+//
+// @Identifier(value = "LoginSecret", name = "登录app_secret", description = "", status = Status.SHOW)
+// private Conf loginSecret = Holders.simple("");
+
+ @Identifier(value = "openLogin", name = "登录界面启动开关", description = "", status = Status.SHOW)
+ private Conf openLogin = Holders.simple(true);
+ @Identifier(value = "defaultScan", name = "默认扫码登录", description = "", status = Status.SHOW)
+ private Conf defaultScan = Holders.simple(false);
+ @Identifier(value = "onlyScan", name = "只保留扫码登录", description = "", status = Status.SHOW)
+ private Conf onlyScan = Holders.simple(false);
+
+ public Boolean getDefaultScan() {
+ return defaultScan.get();
+ }
+
+ public void setDefaultScan( Boolean defaultScan) {
+ this.defaultScan .set(defaultScan);
+ }
+
+ public Boolean getOnlyScan() {
+ return onlyScan.get();
+ }
+
+ public void setOnlyScan( Boolean onlyScan) {
+ this.onlyScan .set(onlyScan);
+ }
+
+ public String getAppId() {
+ return appId.get();
+ }
+
+ public void setAppId(String appId) {
+ this.appId.set(appId);
+ }
+
+ public String getSecret() {
+ return secret.get();
+ }
+
+ public void setSecret(String secret) {
+ this.secret.set(secret);
+ }
+//
+// public String getLoginKey() {
+// return loginKey.get();
+// }
+//
+// public void setLoginKey(String loginKey) {
+// this.loginKey.set(loginKey);
+// }
+//
+// public String getLoginSecret() {
+// return loginSecret.get();
+// }
+//
+// public void setLoginSecret(String loginSecret) {
+// this.loginSecret.set(loginSecret);
+// }
+
+ public Boolean getOpenLogin() {
+ return openLogin.get();
+ }
+
+ public void setOpenLogin(Boolean openLogin) {
+ this.openLogin.set(openLogin);
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ ScanConfig cloned = (ScanConfig) super.clone();
+ cloned.appId = (Conf) appId.clone();
+ cloned.secret = (Conf) secret.clone();
+
+// cloned.loginKey = (Conf) loginKey.clone();
+// cloned.loginSecret = (Conf) loginSecret.clone();
+//
+ cloned.onlyScan = (Conf) onlyScan.clone();
+ cloned.defaultScan = (Conf) defaultScan.clone();
+ cloned.openLogin = (Conf) openLogin.clone();
+ return cloned;
+ }
+
+}
diff --git a/src/main/java/com/fr/plugin/ScanControllerBridge.java b/src/main/java/com/fr/plugin/ScanControllerBridge.java
new file mode 100644
index 0000000..f71b85a
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ScanControllerBridge.java
@@ -0,0 +1,11 @@
+package com.fr.plugin;
+
+import com.fr.decision.fun.impl.AbstractControllerRegisterProvider;
+import com.fr.plugin.web.controllers.ScanController;
+
+public class ScanControllerBridge extends AbstractControllerRegisterProvider {
+ @Override
+ public Class>[] getControllers() {
+ return new Class[]{ScanController.class};
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ScanFunction.java b/src/main/java/com/fr/plugin/ScanFunction.java
new file mode 100644
index 0000000..393e337
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ScanFunction.java
@@ -0,0 +1,12 @@
+package com.fr.plugin;
+
+import com.fr.plugin.transform.ExecuteFunctionRecord;
+import com.fr.plugin.transform.FunctionRecorder;
+
+@FunctionRecorder(localeKey = "scan")
+public class ScanFunction {
+ @ExecuteFunctionRecord
+ public String name() {
+ return "功能点检测";
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ScanHttpHander.java b/src/main/java/com/fr/plugin/ScanHttpHander.java
new file mode 100644
index 0000000..c6a7b1e
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ScanHttpHander.java
@@ -0,0 +1,19 @@
+package com.fr.plugin;
+
+import com.fr.decision.fun.HttpHandler;
+import com.fr.decision.fun.impl.AbstractHttpHandlerProvider;
+import com.fr.stable.fun.Authorize;
+
+
+public class ScanHttpHander extends AbstractHttpHandlerProvider {
+ HttpHandler[] actions = new HttpHandler[]{
+ new ScanCallBackHandle(),
+ new GetQRHandle(),
+ new AllScanBeans()
+ };
+
+ @Override
+ public HttpHandler[] registerHandlers() {
+ return actions;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ScanJS.java b/src/main/java/com/fr/plugin/ScanJS.java
new file mode 100644
index 0000000..38de80e
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ScanJS.java
@@ -0,0 +1,41 @@
+package com.fr.plugin;
+
+import com.fr.base.TemplateUtils;
+import com.fr.gen.TextGenerator;
+import com.fr.plugin.context.PluginContexts;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ScanJS implements TextGenerator {
+
+
+ public String text(HttpServletRequest req, HttpServletResponse res) throws Exception {
+ Map renderMap = new HashMap();
+ ScanConfig instance = ScanConfig.getInstance();
+ String appid = instance.getAppId();
+ renderMap.put("openScan", instance.getOpenLogin());
+ renderMap.put("defaultScan", instance.getDefaultScan());
+ renderMap.put("onlyScan", instance.getOnlyScan());
+ renderMap.put("appId", appid);
+ if (PluginContexts.currentContext().isAvailable()) {
+ // 做认证通过的事情
+ return TemplateUtils.renderTemplate(this.template(), renderMap);
+ } else {
+ // 做认证未通过的事情
+ return TemplateUtils.renderTemplate("/com/fr/plugin/scanBuy.tpl", renderMap);
+
+ }
+ }
+
+
+ public String mimeType() {
+ return "text/javascript";
+ }
+
+ public String template() {
+ return "/com/fr/plugin/scan.tpl";
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ScanJSHander.java b/src/main/java/com/fr/plugin/ScanJSHander.java
new file mode 100644
index 0000000..189d77f
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ScanJSHander.java
@@ -0,0 +1,32 @@
+package com.fr.plugin;
+
+import com.fr.decision.fun.impl.AbstractWebResourceProvider;
+import com.fr.decision.web.LoginComponent;
+import com.fr.web.struct.Atom;
+
+public class ScanJSHander extends AbstractWebResourceProvider {
+
+ /**
+ * 需要附加到的主组件
+ *
+ * @return 主组件
+ */
+
+ @Override
+ public Atom attach() {
+ return LoginComponent.KEY;
+ }
+
+ /**
+ * 客户端所需的组件
+ *
+ * @return 组件
+ */
+ @Override
+ public Atom client() {
+ return ScanComponent.KEY;
+ }
+ public Atom[] clients() {
+ return new Atom[]{this.client()};
+ }
+}
diff --git a/src/main/java/com/fr/plugin/beans/ScanAllConfigBean.java b/src/main/java/com/fr/plugin/beans/ScanAllConfigBean.java
new file mode 100644
index 0000000..febe37a
--- /dev/null
+++ b/src/main/java/com/fr/plugin/beans/ScanAllConfigBean.java
@@ -0,0 +1,31 @@
+package com.fr.plugin.beans;
+
+public class ScanAllConfigBean {
+ private Boolean openLogin = false;
+ private Boolean defaultScan = false;
+ private Boolean onlyScan = false;
+
+ public Boolean getOpenLogin() {
+ return openLogin;
+ }
+
+ public void setOpenLogin(Boolean openLogin) {
+ this.openLogin = openLogin;
+ }
+
+ public Boolean getDefaultScan() {
+ return defaultScan;
+ }
+
+ public void setDefaultScan(Boolean defaultScan) {
+ this.defaultScan = defaultScan;
+ }
+
+ public Boolean getOnlyScan() {
+ return onlyScan;
+ }
+
+ public void setOnlyScan(Boolean onlyScan) {
+ this.onlyScan = onlyScan;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/beans/ScanConfigBean.java b/src/main/java/com/fr/plugin/beans/ScanConfigBean.java
new file mode 100644
index 0000000..5cc5547
--- /dev/null
+++ b/src/main/java/com/fr/plugin/beans/ScanConfigBean.java
@@ -0,0 +1,71 @@
+package com.fr.plugin.beans;
+
+import com.fr.stable.db.entity.BaseEntity;
+
+public class ScanConfigBean extends BaseEntity {
+ private String id = "";
+ private String appId = "";
+ private String appIdSecret = "";
+ private String appKey = "";
+ private String appSecret = "";
+ private String appName = "";
+ private String appFlag = "";
+
+ public String getAppIdSecret() {
+ return appIdSecret;
+ }
+
+ public void setAppIdSecret(String appIdSecret) {
+ this.appIdSecret = appIdSecret;
+ }
+
+ public String getAppSecret() {
+ return appSecret;
+ }
+
+ public void setAppSecret(String appSecret) {
+ this.appSecret = appSecret;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getAppKey() {
+ return appKey;
+ }
+
+ public void setAppKey(String appKey) {
+ this.appKey = appKey;
+ }
+
+ public String getAppName() {
+ return appName;
+ }
+
+ public void setAppName(String appName) {
+ this.appName = appName;
+ }
+
+ public String getAppFlag() {
+ return appFlag;
+ }
+
+ public void setAppFlag(String appFlag) {
+ this.appFlag = appFlag;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/dao/ScanConfigDao.java b/src/main/java/com/fr/plugin/dao/ScanConfigDao.java
new file mode 100644
index 0000000..bb9898f
--- /dev/null
+++ b/src/main/java/com/fr/plugin/dao/ScanConfigDao.java
@@ -0,0 +1,61 @@
+package com.fr.plugin.dao;
+
+import com.fr.plugin.entitys.ScanConfigEntity;
+import com.fr.stable.StringUtils;
+import com.fr.stable.db.dao.BaseDAO;
+import com.fr.stable.db.dao.DAOProvider;
+import com.fr.stable.db.session.DAOSession;
+import com.fr.stable.query.QueryFactory;
+import com.fr.stable.query.condition.QueryCondition;
+import com.fr.stable.query.restriction.RestrictionFactory;
+
+import java.util.List;
+
+public class ScanConfigDao extends BaseDAO {
+ public ScanConfigDao(DAOSession daoSession) {
+ super(daoSession);
+ }
+
+ protected Class getEntityClass() {
+ return ScanConfigEntity.class;
+ }
+
+ public final static DAOProvider DAO = new DAOProvider() {
+ @Override
+ public Class getEntityClass() {
+ return ScanConfigEntity.class;
+ }
+
+ @Override
+ public Class extends BaseDAO> getDAOClass() {
+ return ScanConfigDao.class;
+ }
+ };
+
+ public void add(ScanConfigEntity entity) throws Exception {
+ getSession().persist(entity);
+ }
+
+ public void update(ScanConfigEntity entity) throws Exception {
+ getSession().merge(entity);
+ }
+
+ public ScanConfigEntity getById(String id) throws Exception {
+ return getSession().getById(id, ScanConfigEntity.class);
+ }
+
+ public void remove(String id) throws Exception {
+ getSession().remove(QueryFactory.create()
+ .addRestriction(RestrictionFactory.eq("id", id)),
+ this.getEntityClass());
+ }
+
+ public List likeByKey(String key) throws Exception {
+ QueryCondition condition = QueryFactory.create();
+ if (StringUtils.isNotBlank(key)) {
+ condition.addRestriction(RestrictionFactory.like("app_name", key));
+ }
+ return find(condition);
+ }
+
+}
diff --git a/src/main/java/com/fr/plugin/entitys/ScanConfigEntity.java b/src/main/java/com/fr/plugin/entitys/ScanConfigEntity.java
new file mode 100644
index 0000000..4eb24b9
--- /dev/null
+++ b/src/main/java/com/fr/plugin/entitys/ScanConfigEntity.java
@@ -0,0 +1,73 @@
+package com.fr.plugin.entitys;
+
+import com.fr.stable.db.entity.BaseEntity;
+import com.fr.third.javax.persistence.Column;
+import com.fr.third.javax.persistence.Entity;
+import com.fr.third.javax.persistence.Table;
+
+@Entity
+@Table(
+ name = "fine_dd_scan_login_config"
+)
+public class ScanConfigEntity extends BaseEntity {
+ @Column(name = "app_id")
+ private String appId = "";
+ @Column(name = "app_key")
+ private String appKey = "";
+ @Column(name = "app_id_secret")
+ private String appIdSecret = "";
+ @Column(name = "app_secret")
+ private String appSecret = "";
+ @Column(name = "app_name")
+ private String appName = "";
+ @Column(name = "app_flag")
+ private String appFlag = "";
+
+ public String getAppIdSecret() {
+ return appIdSecret;
+ }
+
+ public void setAppIdSecret(String appIdSecret) {
+ this.appIdSecret = appIdSecret;
+ }
+
+ public String getAppSecret() {
+ return appSecret;
+ }
+
+ public void setAppSecret(String appSecret) {
+ this.appSecret = appSecret;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getAppKey() {
+ return appKey;
+ }
+
+ public void setAppKey(String appKey) {
+ this.appKey = appKey;
+ }
+
+ public String getAppName() {
+ return appName;
+ }
+
+ public void setAppName(String appName) {
+ this.appName = appName;
+ }
+
+ public String getAppFlag() {
+ return appFlag;
+ }
+
+ public void setAppFlag(String appFlag) {
+ this.appFlag = appFlag;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/web/controllers/ScanController.java b/src/main/java/com/fr/plugin/web/controllers/ScanController.java
new file mode 100644
index 0000000..1ce9c84
--- /dev/null
+++ b/src/main/java/com/fr/plugin/web/controllers/ScanController.java
@@ -0,0 +1,69 @@
+package com.fr.plugin.web.controllers;
+
+import com.fr.decision.webservice.Response;
+import com.fr.decision.webservice.annotation.LoginStatusChecker;
+import com.fr.plugin.SCDBAccessProvider;
+import com.fr.plugin.ScanConfig;
+import com.fr.plugin.beans.ScanAllConfigBean;
+import com.fr.plugin.beans.ScanConfigBean;
+import com.fr.third.springframework.stereotype.Controller;
+import com.fr.third.springframework.web.bind.annotation.*;
+
+/**
+ * @author fr.open
+ * @version 10.0
+ * Created by fr.open on 2021-06-26
+ **/
+@Controller("ScanController")
+@LoginStatusChecker(required = true)
+@RequestMapping(value = "/ddScan/config")
+public class ScanController {
+
+ @RequestMapping(value = "/scan_entity", method = RequestMethod.POST)
+ @ResponseBody
+ public Response add(@RequestBody ScanConfigBean bean) throws Exception {
+ SCDBAccessProvider.add(bean);
+ return Response.ok(bean);
+ }
+
+ @RequestMapping(value = "/scan_entity/{entity}", method = RequestMethod.DELETE)
+ @ResponseBody
+ public Response delete(@PathVariable("entity") String entity) throws Exception {
+ return Response.ok(SCDBAccessProvider.delete(entity));
+ }
+
+ @RequestMapping(value = "/scan_entity", method = RequestMethod.PUT)
+ @ResponseBody
+ public Response update(@RequestBody ScanConfigBean bean) throws Exception {
+ SCDBAccessProvider.update(bean);
+ return Response.ok(bean);
+ }
+
+ @RequestMapping(value = "/scan_entity", method = RequestMethod.GET)
+ @ResponseBody
+ public Response like(@RequestParam(value = "key",required = false) String key) throws Exception {
+ return Response.ok(SCDBAccessProvider.like(key));
+ }
+
+ @RequestMapping(value = "/allDefConfig", method = RequestMethod.GET)
+ @ResponseBody
+ public Response allDefConfig() throws Exception {
+ ScanAllConfigBean bean = new ScanAllConfigBean();
+ ScanConfig scanConfig = ScanConfig.getInstance();
+ bean.setDefaultScan(scanConfig.getDefaultScan());
+ bean.setOpenLogin(scanConfig.getOpenLogin());
+ bean.setOnlyScan(scanConfig.getOnlyScan());
+ return Response.ok(bean);
+ }
+ @RequestMapping(value = "/changeConfig", method = RequestMethod.PUT)
+ @ResponseBody
+ public Response changeConfig(@RequestBody ScanAllConfigBean bean) throws Exception {
+ if (bean != null) {
+ ScanConfig scanConfig = ScanConfig.getInstance();
+ scanConfig.setDefaultScan(bean.getDefaultScan());
+ scanConfig.setOpenLogin(bean.getOpenLogin());
+ scanConfig.setOnlyScan(bean.getOnlyScan());
+ }
+ return Response.ok(bean);
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/com/fr/plugin/buynew.html b/src/main/resources/com/fr/plugin/buynew.html
new file mode 100644
index 0000000..71dd2cf
--- /dev/null
+++ b/src/main/resources/com/fr/plugin/buynew.html
@@ -0,0 +1,17 @@
+
+
+
+
+ 钉钉扫码
+
+
+
+
+
+ 请购买授权后使用
+
+
+
diff --git a/src/main/resources/com/fr/plugin/new.html b/src/main/resources/com/fr/plugin/new.html
new file mode 100644
index 0000000..d4e928b
--- /dev/null
+++ b/src/main/resources/com/fr/plugin/new.html
@@ -0,0 +1,69 @@
+
+
+
+
+ 钉钉扫码
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/fr/plugin/scan.tpl b/src/main/resources/com/fr/plugin/scan.tpl
new file mode 100644
index 0000000..31cf52d
--- /dev/null
+++ b/src/main/resources/com/fr/plugin/scan.tpl
@@ -0,0 +1,331 @@
+(function () {
+// 为平台增加一个footer
+ BI.Plugin.registerObject("dec.login.login", function (widget) {
+ var openScan = eval("${openScan}");
+ var defaultScan = eval("${defaultScan}");
+ var onlyScan = eval("${onlyScan}");
+ // if (openScan) {
+ // var target = $(widget.element).find(".bi-multi-select-item").parent();
+ // var item = $("")
+ // item.click(function () {
+ // window.zxltabs.setSelect(DecCst.Login.Tabs.QR_LOGIN)
+ // });
+ // item.insertAfter(target);
+ // }
+ if (openScan) {
+ var target = $(widget.element).find(".bi-multi-select-item").parent().parent();
+ var item = $("")
+ item.click(function () {
+ window.zxltabs.setSelect(DecCst.Login.Tabs.QR_LOGIN)
+ });
+ item.insertAfter(target);
+ }
+ });
+})();
+
+var onlyScan = eval("${onlyScan}");
+var defaultScan = eval("${defaultScan}");
+if(getQueryString("isAdmin") === "1"){
+ onlyScan=false;
+ defaultScan=false;
+}
+function setCookie(name, value) {
+ var Days = 1;
+ var exp = new Date();
+ exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);
+ document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString();
+}
+
+function getQueryString(name) {
+ var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
+ var r = window.location.search.substr(1).match(reg);
+ if (r != null) {
+ return decodeURIComponent(r[2]);
+ }
+ return null;
+}
+
+if (onlyScan) {
+ var tempScan = getQueryString("notScan");
+ if (tempScan) {
+ onlyScan = false;
+ defaultScan = false;
+ }
+}
+DecCst = DecCst || {};
+DecCst.Login.Tabs.QR_LOGIN = "qr_login";
+(function () {
+ var e = BI.inherit(BI.Widget, {
+ props: {
+ baseCls: "dec-login-index"
+ },
+ _store: function () {
+ return BI.Models.getModel("dec.model.login.index")
+ },
+ watch: {
+ selectedTab: function (e) {
+ this.tab.setSelect(e)
+ }
+ },
+ render: function () {
+ var t = this;
+ return {
+ type: "bi.tab",
+ cls: "bi-card",
+ single: !0,
+ cardCreator: BI.bind(this._createCard, this),
+ showIndex: this.model.selectedTab,
+ ref: function (e) {
+ t.tab = e
+ }
+ }
+ },
+ mounted: function () {
+ this.store.initData()
+ window.zxltabs = this.tab;
+ //如果有一个notScan参数就,不是只扫码
+ if (defaultScan) {
+ this.tab.setSelect(DecCst.Login.Tabs.QR_LOGIN)
+ }
+ },
+ _createCard: function (e) {
+ var t = this;
+
+ switch (e) {
+ case DecCst.Login.Tabs.LOGIN:
+
+ if (onlyScan) {
+ return {
+ type: "dec.login.QR"
+ };
+ } else {
+ return {
+ type: "dec.login.login",
+ listeners: [{
+ eventName: "EVENT_LOGIN",
+ action: function (e) {
+ t.store.login(e)
+ }
+ }]
+ };
+ }
+ case DecCst.Login.Tabs.FORGET_PASSWORD:
+ return {
+ type: "dec.login.forget"
+ };
+ case DecCst.Login.Tabs.AUTHENTICATION:
+ return {
+ type: "dec.login.authentication",
+ listeners: [{
+ eventName: "EVENT_LOGIN",
+ action: function (e) {
+ t.store.login(e)
+ }
+ }]
+ };
+ case DecCst.Login.Tabs.PASSWORD_TOKEN:
+ return {
+ type: "dec.login.password",
+ listeners: [{
+ eventName: "EVENT_SAVE",
+ action: function (e) {
+ t.store.toSuccess(e)
+ }
+ }]
+ };
+ case DecCst.Login.Tabs.QR_LOGIN:
+ return {
+ type: "dec.login.QR"
+ };
+ case DecCst.Login.Tabs.SUCCESS_PWD:
+ return {
+ type: "dec.login.password.success",
+ username: this.model.loginInfo.username,
+ pwd: this.model.userInfo.pwd,
+ loginValidity: this.model.loginInfo.validity,
+ listeners: [{
+ eventName: "EVENT_LOGIN",
+ action: function (e) {
+ t.store.login(e)
+ }
+ }]
+ };
+ case DecCst.Login.Tabs.SUCCESS_TOKEN:
+ return {
+ type: "dec.login.password.token",
+ listeners: [{
+ eventName: "EVENT_LOGIN",
+ action: function (e) {
+ t.store.login(e)
+ }
+ }]
+ };
+ case DecCst.Login.Tabs.PASSWORD_OLD:
+ return {
+ type: "dec.login.single",
+ username: this.model.loginInfo.username,
+ listeners: [{
+ eventName: "EVENT_BACK",
+ action: function () {
+ t.store.setTab(DecCst.Login.Tabs.LOGIN)
+ }
+ }, {
+ eventName: "EVENT_SURE",
+ action: function (e) {
+ t.store.toSuccess(e)
+ }
+ }]
+ };
+ case DecCst.Login.Tabs.VERIFY_BING:
+ return {
+ type: "dec.login.verify"
+ };
+ case DecCst.Login.Tabs.LOCKED:
+ return {
+ type: "dec.login.locked"
+ };
+ default:
+ return {
+ type: "bi.layout"
+ }
+ }
+ }
+ });
+ BI.shortcut("dec.login.index", e)
+}());
+function getPath(path, isPublic) {
+ if (!path || path[0] !== '/') {
+ path = '/' + path;
+ }
+ return isPublic === true
+ ? '/plugin/public/com.fr.plugin.sln5470' + path
+ : '/plugin/private/com.fr.plugin.sln5470' + path;
+}
+;(function () {
+ var e = BI.inherit(BI.Widget, {
+ props: {
+ baseCls: ""
+ },
+ _store: function () {
+ return BI.Models.getModel("dec.model.login.login")
+ },
+ beforeInit:function (callback){
+ //初始化的时候先获取有哪些钉钉服务器可以选择
+ var self = this;
+ Dec.reqGet(getPath("getConfigBean", true), {}, function (data) {
+ console.info(data)
+ self.datas = data.data;
+ callback();
+ })
+ },
+ mounted: function () {
+ if(this.firstId){
+ this.comb.setValue(this.firstId);
+ this.changeSelect(this.firstId);
+ }
+ },
+ changeSelect:function ( value){
+ var self=this;
+ var appId = value||self.comb.getValue()[0];
+ var host = window.location.protocol + "//" + window.location.host;//左良测试
+ var cal = host + "${fineServletURL}";
+ var target = encodeURIComponent(cal);
+ //拿到loginTmpCode后就可以在这里构造跳转链接进行跳转了
+ var orgin = getQueryString("origin")
+ if (orgin) {
+ setCookie("myorgin", orgin);
+ }
+ var callBack = encodeURIComponent(cal + "/plugin/public/com.fr.plugin.sln5470/scanLogin?redirectUrl=" + target);
+ var goto = encodeURIComponent('https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=' + appId + '&response_type=code&scope=snsapi_login&redirect_uri=' + callBack);
+ var url = "https://login.dingtalk.com/login/qrcode.htm?&state="+appId+"&goto=" + goto + "&style=" + encodeURIComponent('border:none;background-color:#FFFFFF;');
+ $(self.iframe.element).attr("src",url)
+ self.iframe.setVisible(true)
+ // self.comb.setVisible(false)
+ var handleMessage = function (event) {
+ var origin = event.origin;
+ var host = window.location.protocol + "//" + window.location.host;//左良测试
+ var callback = host + "${fineServletURL}";
+ console.log("origin", event.origin);
+ if (origin == "https://login.dingtalk.com") { //判断是否来自ddLogin扫码事件。
+ var loginTmpCode = event.data;
+ var url = "https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid="+appId+"&response_type=code&scope=snsapi_login&state="+appId+"&redirect_uri=" + callback + "&loginTmpCode=" + loginTmpCode;
+ window.location.href = url;
+ }
+ };
+ if (typeof window.addEventListener != 'undefined') {
+ window.addEventListener('message', handleMessage, false);
+ } else if (typeof window.attachEvent != 'undefined') {
+ window.attachEvent('onmessage', handleMessage);
+ }
+
+ },
+ render: function () {
+ var t = this;
+ var url="";
+ var items=BI.map(this.datas,function (i,v){
+ return {
+ text: v.appName,
+ value: v.appId
+ }
+ })
+ var vv=null;
+ if(items.length){
+ t.firstId=items[0].value;
+ }
+ return {
+ type: "bi.absolute",
+ items: [
+ {
+ el:{
+ css:{
+ zIndex:999
+ },
+ type: "bi.text_value_combo",
+ ref: function (e) {
+ t.comb=e;
+ },
+ value:vv,
+ text:"请选择登录的公司信息",
+ listeners: [{
+ eventName: "EVENT_CHANGE",
+ action: function () {
+ t.changeSelect();
+ }
+ }],
+ width: 201,
+ height:24,
+ items: items
+ },
+ bottom: 30,
+ left:35
+ },
+ {
+ el: {
+ type: "bi.default",
+ invisible:true,
+ ref:function (e){
+ t.iframe=e;
+ },
+ element: ""
+ },
+ top: 0,
+ height: "100%",
+ right: 0,
+ bottom: 0,
+ left: 0
+ }, {
+ el: {
+ type: "bi.icon_button",
+ cls: "toast-error-font",
+ handler: function () {
+ window.zxltabs.setSelect(DecCst.Login.Tabs.LOGIN)
+ }
+ },
+ top: 10,
+ right: 20
+ }]
+ }
+ }
+ });
+ BI.shortcut("dec.login.QR", e)
+})();
diff --git a/src/main/resources/com/fr/plugin/scanBuy.tpl b/src/main/resources/com/fr/plugin/scanBuy.tpl
new file mode 100644
index 0000000..71f758e
--- /dev/null
+++ b/src/main/resources/com/fr/plugin/scanBuy.tpl
@@ -0,0 +1,3 @@
+;(function () {
+ alert("钉钉扫码插件授权过期或未授权")
+})();
\ No newline at end of file
diff --git a/src/main/resources/com/fr/plugin/web/dds/dds.js b/src/main/resources/com/fr/plugin/web/dds/dds.js
new file mode 100644
index 0000000..32bc6b5
--- /dev/null
+++ b/src/main/resources/com/fr/plugin/web/dds/dds.js
@@ -0,0 +1,496 @@
+BI.config("dec.provider.management", function (provider) {
+ provider.inject({
+ modules: [
+ {
+ value: "dd.scan.config",
+ id: "decision-management-custom-manage",
+ text: "钉钉扫码配置",
+ cardType: "dd.scan.config",
+ cls: "setting-font",
+ dev: true
+ }
+ ]
+ });
+});
+
+function getPath(path, isPublic) {
+ if (!path || path[0] !== '/') {
+ path = '/' + path;
+ }
+ return isPublic === true
+ ? '//ddScan/config/' + path
+ : '/ddScan/config/' + path;
+}
+
+// 组件实现,效果为使用绝对布局组件放置了一个iframe
+var Wid = BI.inherit(BI.Widget, {
+
+ props: {
+ baseCls: ""
+ },
+
+ render: function () {
+ return {
+ type: "bi.vertical",
+ vgap: 30,
+ items: [
+ {
+ type: "dd.scan.top.row",
+ height: 300
+ },
+ {
+ tgap:30,
+ type: "dd.scan.bottom.config.all.area"
+ }
+ ]
+ };
+ }
+});
+BI.shortcut("dd.scan.config", Wid);
+// 组件实现,效果为使用绝对布局组件放置了一个iframe
+var allConfigWid = BI.inherit(BI.Widget, {
+
+ props: {
+ baseCls: "",
+ css: {
+ background: "#e3e3e3"
+ }
+ },
+ beforeInit: function (callback) {
+ var self = this;
+ Dec.reqGet(getPath("allDefConfig", false), {}, function (data) {
+ console.info(data)
+ self.data = data.data;
+ callback();
+ })
+ },
+ saveAction: function () {
+ var config = {
+ openLogin: this.openLogin.isSelected(),
+ onlyScan: this.onlyScan.isSelected(),
+ defaultScan: this.defaultScan.isSelected(),
+ }
+ Dec.reqPut(getPath("changeConfig", false), config, function (data) {
+ BI.Msg.toast("更新成功")
+ });
+ },
+ render: function () {
+ var self = this;
+ return {
+ type: "bi.vertical",
+ width:400,
+ hgap:40,
+ items: [
+ {
+ type: "bi.multi_select_item",
+ text: "默认开启扫码",
+ ref: function (e) {
+ self.defaultScan = e;
+ },
+ selected: self.data.defaultScan,
+ },
+ {
+ type: "bi.multi_select_item",
+ text: "仅开启扫码(不保留密码登陆)",
+ ref: function (e) {
+ self.onlyScan = e;
+ },
+ selected: self.data.onlyScan,
+ },
+ {
+ type: "bi.multi_select_item",
+ text: "打开扫码入口",
+ ref: function (e) {
+ self.openLogin = e;
+ },
+ selected: self.data.openLogin,
+ },
+ {
+ type: "bi.right",
+ items: [
+ {
+ type: "bi.button",
+ text: "保存",
+ level: "info",
+ height: 30,
+ handler: function () {
+ self.saveAction();
+ },
+ }
+ ]
+ }
+ ]
+ };
+ }
+});
+BI.shortcut("dd.scan.bottom.config.all.area", allConfigWid);
+// 组件实现,效果为使用绝对布局组件放置了一个iframe
+var toprow = BI.inherit(BI.Widget, {
+
+ props: {
+ baseCls: ""
+ },
+ beforeInit: function (callBack) {
+ var self = this;
+ Dec.reqGet(getPath("scan_entity", false), {}, function (data) {
+ console.info(data)
+ self.datas = data.data;
+ callBack();
+ })
+ },
+ reloadList:function (){
+ var self=this;
+ Dec.reqGet(getPath("scan_entity", false), {}, function (data) {
+ var da= data.data;
+ self.leftArea.populate(da);
+ })
+ },
+ saveAction: function () {
+ var self=this;
+ var value = this.rightArea.getValue();
+ if(value.id){
+ Dec.reqPut(getPath("scan_entity", false), value, function (data) {
+ console.info(data)
+ BI.Msg.toast("更新成功" + data.data.appName)
+ self.reloadList();
+ });
+ }else{
+ Dec.reqPost(getPath("scan_entity", false), value, function (data) {
+ console.info(data)
+ self.reloadList();
+ BI.Msg.toast("保存成功" + data.data.appName)
+ });
+ }
+ },
+ delAction: function (item) {
+ var self=this;
+ Dec.reqDelete(getPath("scan_entity/" + item.id, false), item, function (data) {
+ BI.Msg.toast("删除成功" + data.data.appName)
+ self.reloadList();
+ });
+ },
+ changeAction: function (item) {
+ this.rightArea.setValue(item);
+ },
+ createAction: function () {
+ this.rightArea.reset();
+ },
+ render: function () {
+ var self = this;
+ return {
+ type: "bi.horizontal",
+ vgap: 30,
+ items: [
+ {
+ type: "dd.scan.top.config.left.area",
+ height: 200,
+ lists: this.datas,
+ ref:function (e){
+ self.leftArea=e;
+ },
+ listeners: [{
+ eventName: "CREATENEW",
+ action: function () {
+ self.createAction();
+ }
+ }, {
+ eventName: "DELETED",
+ action: function (item) {
+ self.delAction(item);
+ }
+ }, {
+ eventName: "CLICKITEM",
+ action: function (item) {
+ self.changeAction(item);
+ }
+ },],
+ },
+ {
+ type: "dd.scan.top.config.right.area",
+ height: 400,
+ ref: function (e) {
+ self.rightArea = e;
+ },
+ listeners: [{
+ eventName: "SAVE",
+ action: function () {
+ self.saveAction();
+ }
+ }],
+ }
+ ]
+ };
+ }
+});
+BI.shortcut("dd.scan.top.row", toprow);
+
+// 这个组件需要编辑功能所以继承到BI.Single 这样可以继承到getValue和setValue
+var rightArea = BI.inherit(BI.Single, {
+
+ props: {
+ //这个item是父级传下来的,如果有这个item 就表示这次是编辑而不是新建
+ item: {}
+ },
+ getValue: function () {
+ return {
+ id: this.options.item.id,
+ appName: this.appName.getValue(),
+ appId: this.appId.getValue(),
+ appKey: this.appKey.getValue(),
+ appIdSecret: this.appIdSecret.getValue(),
+ appSecret: this.appSecret.getValue(),
+ }
+ },
+ setValue: function (item) {
+ this.options.item = item;
+ this.appName.setValue(item.appName);
+ this.appId.setValue(item.appId);
+ this.appSecret.setValue(item.appSecret);
+ this.appKey.setValue(item.appKey);
+ this.appIdSecret.setValue(item.appIdSecret);
+ },
+ render: function () {
+ var self = this;
+ var item = this.options.item;
+ return {
+ type: "bi.vertical",
+ hgap: 10,
+ vgap:10,
+ items: [
+ {
+ type: "bi.horizontal_adapt",
+ height: 30,
+ width:300,
+ columnSize: [120, "fill"],
+ items: [
+ {
+ type: "bi.label",
+ text: "公司名称"
+ },
+ {
+ type: "bi.editor", cls: "bi-border",
+ value: item.appName,
+ width: 200,
+ height: 24,
+ ref: function (e) {
+ self.appName = e;
+ }
+ }
+ ]
+ },
+ {
+ type: "bi.horizontal_adapt",
+ width:300,
+ columnSize: [120, "fill"],
+ height: 30,
+ items: [
+ {
+ type: "bi.label",
+ text: "appId"
+ },
+ {
+ type: "bi.editor", cls: "bi-border",
+ value: item.appId,
+ width: 200,
+ height: 24,
+ ref: function (e) {
+ self.appId = e;
+ }
+ }
+ ]
+ },{
+ type: "bi.horizontal_adapt",
+ width:300,
+ columnSize: [120, "fill"],
+ height: 30,
+ items: [
+ {
+ type: "bi.label",
+ text: "扫码的appSercet"
+ },
+ {
+ type: "bi.editor", cls: "bi-border",
+ value: item.appIdSecret,
+ width: 200,
+ height: 24,
+ ref: function (e) {
+ self.appIdSecret = e;
+ }
+ }
+ ]
+ }, {
+ type: "bi.horizontal_adapt",
+ width:300,
+ columnSize: [120, "fill"],
+ height: 30,
+ items: [
+ {
+ type: "bi.label",
+ text: "appKey"
+ },
+ {
+ type: "bi.editor", cls: "bi-border",
+ value: item.appKey,
+ width: 200,
+ height: 24,
+ ref: function (e) {
+ self.appKey = e;
+ }
+ }
+ ]
+ }, {
+ type: "bi.horizontal_adapt",
+ width:300,
+ columnSize: [120, "fill"],
+ height: 30,
+ items: [
+ {
+ type: "bi.label",
+ text: "应用的appSecret"
+ },
+ {
+ type: "bi.editor", cls: "bi-border",
+ width: 200,
+ height: 24,
+ value: item.appSecret,
+ ref: function (e) {
+ self.appSecret = e;
+ }
+ }
+ ]
+ },
+ {
+ type: "bi.right",
+ items: [
+ {
+ type: "bi.button",
+ text: "保存",
+ level: "info",
+ height: 30,
+ handler: function () {
+ //这里只发送一个事件出去,由父级组件调用getValue来实现
+ self.fireEvent("SAVE");
+ },
+ }
+ ]
+ }
+ ]
+ };
+ }
+});
+BI.shortcut("dd.scan.top.config.right.area", rightArea);
+
+// 组件实现,效果为使用绝对布局组件放置了一个iframe
+var topConfigWid = BI.inherit(BI.Widget, {
+
+ props: {
+ lists: []
+ },
+ renderEditorItem: function (datas) {
+ var self = this;
+ return BI.map(datas, function (i, v) {
+ return {
+ type: "dd.scan.config.item",
+ item: v,
+ listeners: [{
+ eventName: "DELETED",
+ action: function (item) {
+ self.fireEvent("DELETED", item);
+ },
+ }, {
+ eventName: "CLICKITEM",
+ action: function (item) {
+
+ self.fireEvent("CLICKITEM", item);
+ }
+ }]
+ }
+ });
+ },
+ populate:function (items){
+ this.list.populate(this.renderEditorItem(items))
+ },
+ render: function () {
+ var self = this;
+ return {
+ type: "bi.vertical",
+ vgap: 10,
+ items: [
+ {
+ type: "bi.label",
+ text: "钉钉扫码配置列表"
+ },
+ {
+ type: "bi.button_group",
+ chooseType: BI.Selection.Single,
+ value: 2,
+ ref:function (e){
+ self.list=e;
+ },
+ items: this.renderEditorItem(this.options.lists),
+ layouts: [{
+ vgap:10,
+ type: "bi.vertical",
+ }]
+ },
+ {
+ type: "bi.center_adapt",
+ items: [
+ {
+ type: "bi.button",
+ text: "新建",
+ level: "common",
+ height: 30,
+ width: 100,
+ handler: function () {
+ self.fireEvent("CREATENEW")
+ },
+
+ }
+ ]
+ }
+ ]
+ };
+ }
+});
+BI.shortcut("dd.scan.top.config.left.area", topConfigWid);
+
+
+// 组件实现,效果为使用绝对布局组件放置了一个iframe
+var cofigItem = BI.inherit(BI.Widget, {
+
+ props: {
+ item: {
+ appName: "",
+ id: ""
+ }
+ },
+
+ render: function () {
+ var self = this;
+ return {
+ type: "bi.horizontal_adapt",
+ width:300,
+ columnSize: [200, "fill"],
+ hgap: 30,
+ items: [
+ {
+ type: "bi.text_button",
+ text: this.options.item.appName,
+ handler: function () {
+ self.fireEvent("CLICKITEM", self.options.item)
+ }
+ },
+ {
+ type: "bi.button",
+ iconCls: "close-font",
+ height: 14,
+ handler: function () {
+ self.fireEvent("DELETED", self.options.item)
+ }
+ }
+ ]
+ };
+ }
+});
+BI.shortcut("dd.scan.config.item", cofigItem);