diff --git a/JSD-6952-配置使用文档.docx b/JSD-6952-配置使用文档.docx new file mode 100644 index 0000000..2e3f778 Binary files /dev/null and b/JSD-6952-配置使用文档.docx differ diff --git a/README.md b/README.md index 379c149..655253d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ # open-JSD-6952 -JSD-6952 开源任务代码 \ No newline at end of file +JSD-6952 开源任务代码\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。 \ No newline at end of file diff --git a/jsd-6952-需求确认书v1.docx b/jsd-6952-需求确认书v1.docx new file mode 100644 index 0000000..39b6fd4 Binary files /dev/null and b/jsd-6952-需求确认书v1.docx differ diff --git a/lib/finekit-10.0.jar b/lib/finekit-10.0.jar new file mode 100644 index 0000000..f4482fc Binary files /dev/null and b/lib/finekit-10.0.jar differ diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..86a32fc --- /dev/null +++ b/plugin.xml @@ -0,0 +1,28 @@ + + + com.fr.plugin.mqh.dingtalksyn.job + + yes + 1.0 + 10.0 + 2018-07-31 + mqh + + + 1.用户信息全量同步
+ 2.用户单点登陆功能
+ ]]>
+ com.fr.plugin.mqh.dingtalksyn + + com.fanruan.api + + + + + + + + + +
\ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/bean/DataResponse.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/bean/DataResponse.java new file mode 100644 index 0000000..6306735 --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/bean/DataResponse.java @@ -0,0 +1,158 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: DataResponse + * Author: Louis + * Date: 2021/3/19 11:46 + */ + package com.fr.plugin.mqh.dingtalksyn.bean; + + import com.fanruan.api.util.StringKit; + import com.fr.decision.webservice.Response; +import com.fr.third.fasterxml.jackson.annotation.JsonInclude; +import com.fr.third.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Map; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + @JsonInclude(JsonInclude.Include.NON_DEFAULT) + public class DataResponse extends Response { + private static final long serialVersionUID = -6470353731188369521L; + @JsonProperty("msg_signature") + private String msgSignature; + private String timeStamp; + private String nonce; + private String encrypt; + + private String code; + private String message; + + public DataResponse() { + } + + private static DataResponse create() { + return new DataResponse(); + } + + /** + * 相应success结果 + * + * @return + */ + public static DataResponse success(Map successMap) { + return create().msgSignature(successMap.get("msg_signature")) + .timeStamp(successMap.get("timeStamp")) + .nonce(successMap.get("nonce")) + .encrypt(successMap.get("encrypt")); + } + + /** + * 操作结果 + * + * @param data + * @return + */ + public static DataResponse operation(String data) { + return create().code("200").message("success").data(data); + } + + /** + * 报错结果 + * + * @param code + * @param message + * @return + */ + public static DataResponse error(String code, String message) { + return create().code(code).message(message).data(StringKit.EMPTY); + } + + public DataResponse msgSignature(String msgSignature) { + this.msgSignature = msgSignature; + return this; + } + + public DataResponse timeStamp(String timeStamp) { + this.timeStamp = timeStamp; + return this; + } + + public DataResponse nonce(String nonce) { + this.nonce = nonce; + return this; + } + + public DataResponse encrypt(String encrypt) { + this.encrypt = encrypt; + return this; + } + + public DataResponse code(String code) { + this.code = code; + return this; + } + + public DataResponse message(String message) { + this.message = message; + return this; + } + + public DataResponse data(Object data) { + this.setData(data); + return this; + } + + public String getMsgSignature() { + return msgSignature; + } + + public void setMsgSignature(String msgSignature) { + this.msgSignature = msgSignature; + } + + public String getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + public String getNonce() { + return nonce; + } + + public void setNonce(String nonce) { + this.nonce = nonce; + } + + public String getEncrypt() { + return encrypt; + } + + public void setEncrypt(String encrypt) { + this.encrypt = encrypt; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/bean/DingTalkJobConstructor.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/bean/DingTalkJobConstructor.java new file mode 100644 index 0000000..bbcd3b9 --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/bean/DingTalkJobConstructor.java @@ -0,0 +1,107 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: DingTalkJobConstructor + * Author: Louis + * Date: 2021/4/21 15:58 + */ + package com.fr.plugin.mqh.dingtalksyn.bean; + + import com.fr.scheduler.job.FineScheduleJob; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class DingTalkJobConstructor { + private String cron; + private String jobName; + private String jobGroup; + private String triggerName; + private String triggerGroup; + private Class jobClazz; + + public DingTalkJobConstructor() { + } + + public DingTalkJobConstructor cron(String var1) { + this.setCron(var1); + return this; + } + + public String getCron() { + return this.cron; + } + + public void setCron(String var1) { + this.cron = var1; + } + + public DingTalkJobConstructor jobName(String var1) { + this.setJobName(var1); + return this; + } + + public String getJobName() { + return this.jobName; + } + + public void setJobName(String var1) { + this.jobName = var1; + } + + public DingTalkJobConstructor jobGroup(String var1) { + this.setJobGroup(var1); + return this; + } + + public String getJobGroup() { + return this.jobGroup; + } + + public void setJobGroup(String var1) { + this.jobGroup = var1; + } + + public DingTalkJobConstructor triggerName(String var1) { + this.setTriggerName(var1); + return this; + } + + public String getTriggerName() { + return this.triggerName; + } + + public void setTriggerName(String var1) { + this.triggerName = var1; + } + + public DingTalkJobConstructor triggerGroup(String var1) { + this.setTriggerGroup(var1); + return this; + } + + public String getTriggerGroup() { + return this.triggerGroup; + } + + public void setTriggerGroup(String var1) { + this.triggerGroup = var1; + } + + public DingTalkJobConstructor jobClazz(Class var1) { + this.setJobClazz(var1); + return this; + } + + public Class getJobClazz() { + return this.jobClazz; + } + + public void setJobClazz(Class var1) { + this.jobClazz = var1; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/config/DingSynConfig.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/config/DingSynConfig.java new file mode 100644 index 0000000..565c752 --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/config/DingSynConfig.java @@ -0,0 +1,107 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: DingSynConfig + * Author: Louis + * Date: 2021/3/30 9:38 + */ + package com.fr.plugin.mqh.dingtalksyn.config; + + import com.fanruan.api.util.StringKit; +import com.fr.config.*; +import com.fr.config.holder.Conf; +import com.fr.config.holder.factory.Holders; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + @Visualization(category = "Plugin-dingtalksyn_Group") + public class DingSynConfig extends DefaultConfiguration { + + // 每天中午十二点触发 + public static final String CRON_CONDITION = "0 0 12 * * ?"; + public static final long ROOT_DEP_ID = 1; + private static volatile DingSynConfig config = null; + + public static DingSynConfig getInstance() { + if (config == null) { + config = ConfigContext.getConfigInstance(DingSynConfig.class); + } + return config; + } + + @Identifier(value = "cronCondition", name = "Plugin-dingtalksyn_Config_CronCondition", description = "Plugin-dingtalksyn_Config_CronCondition_Description", status = Status.SHOW) + private Conf cronCondition = Holders.simple(CRON_CONDITION); + @Identifier(value = "appKey", name = "Plugin-dingtalksyn_Config_appKey", description = "Plugin-dingtalksyn_Config_appKey_Description", status = Status.SHOW) + private Conf appKey = Holders.simple(StringKit.EMPTY); + @Identifier(value = "appSecret", name = "Plugin-dingtalksyn_Config_appSecret", description = "Plugin-dingtalksyn_Config_appSecret_Description", status = Status.SHOW) + private Conf appSecret = Holders.simple(StringKit.EMPTY); + @Identifier(value = "corpId", name = "Plugin-dingtalksyn_Config_corpId", description = "Plugin-dingtalksyn_Config_corpId_Description", status = Status.SHOW) + private Conf corpId = Holders.simple(StringKit.EMPTY); + @Identifier(value = "rootDepId", name = "Plugin-dingtalksyn_Config_rootDepId", description = "Plugin-dingtalksyn_Config_rootDepId_Description", status = Status.SHOW) + private Conf rootDepId = Holders.simple(ROOT_DEP_ID); +// @Identifier(value = "token", name = "Plugin-dingtalksyn_Config_Token", description = "Plugin-dingtalksyn_Config_Token_Description", status = Status.SHOW) +// private Conf token = Holders.simple(StringKit.EMPTY); +// @Identifier(value = "aesKey", name = "Plugin-dingtalksyn_Config_AesKey", description = "Plugin-dingtalksyn_Config_AesKey_Description", status = Status.SHOW) +// private Conf aesKey = Holders.simple(StringKit.EMPTY); + + public String getCronCondition() { + return cronCondition.get(); + } + + public void setCronCondition(String cronCondition) { + this.cronCondition.set(cronCondition); + } + + public String getAppKey() { + return appKey.get(); + } + + public void setAppKey(String appKey) { + this.appKey.set(appKey); + } + + public String getAppSecret() { + return appSecret.get(); + } + + public void setAppSecret(String appSecret) { + this.appSecret.set(appSecret); + } + + public String getCorpId() { + return corpId.get(); + } + + public void setCorpId(String corpId) { + this.corpId.set(corpId); + } + + public long getRootDepId() { + return rootDepId.get(); + } + + public void setRootDepId(long rootDepId) { + this.rootDepId.set(rootDepId); + } + +// public String getToken() { +// return token.get(); +// } +// +// public void setToken(String token) { +// this.token.set(token); +// } +// +// public String getAesKey() { +// return aesKey.get(); +// } +// +// public void setAesKey(String aesKey) { +// this.aesKey.set(aesKey); +// } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/helper/DingTalkScheduleHelper.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/helper/DingTalkScheduleHelper.java new file mode 100644 index 0000000..ad14e30 --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/helper/DingTalkScheduleHelper.java @@ -0,0 +1,77 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: DingTalkScheduleHelper + * Author: Louis + * Date: 2021/4/21 15:52 + */ + package com.fr.plugin.mqh.dingtalksyn.helper; + + import com.fr.plugin.mqh.dingtalksyn.bean.DingTalkJobConstructor; + import com.fr.plugin.mqh.dingtalksyn.job.DingTalkSyncMemberJob; + import com.fr.scheduler.ScheduleJobManager; + import com.fr.third.v2.org.quartz.CronScheduleBuilder; + import com.fr.third.v2.org.quartz.TriggerBuilder; + + import java.util.ArrayList; + import java.util.HashMap; + import java.util.TimeZone; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class DingTalkScheduleHelper { + public static final String DINGTALK_SCHEDULE_SYN_MEMBER_JOB_NAME = "MqhDingTalkSynDepMemberJob"; + public static final String DINGTALK_SCHEDULE_SYN_MEMBER_TRIGGER_NAME = "MqhDingTalkSynDepMemberTrigger"; + public static final String DINGTALK_SCHEDULE_SYN_MEMBER_GROUP = "MqhDingTalkSynDepMemberGroup"; + public static final String DINGTALK_SCHEDULE_SYN_MEMBER_TRIGGER_GROUP = "MqhDingTalkSynDepMemberTriggerGroup"; + + private DingTalkScheduleHelper() { + } + + public static DingTalkScheduleHelper getInstance() { + return DingTalkScheduleHelper.HOLDER.INSTANCE; + } + + public void startSynMemberSchedule(String cronCondition) throws Exception { + DingTalkJobConstructor jobConstructor = (new DingTalkJobConstructor()) + .cron(cronCondition).jobName(DINGTALK_SCHEDULE_SYN_MEMBER_JOB_NAME) + .jobGroup(DINGTALK_SCHEDULE_SYN_MEMBER_GROUP).triggerName(DINGTALK_SCHEDULE_SYN_MEMBER_TRIGGER_NAME) + .triggerGroup(DINGTALK_SCHEDULE_SYN_MEMBER_TRIGGER_GROUP).jobClazz(DingTalkSyncMemberJob.class); + this.startSchedule(jobConstructor); + } + + public void startSchedule(DingTalkJobConstructor var1) throws Exception { + if (var1 != null) { + String var2 = var1.getCron(); + String var3 = var1.getTriggerName(); + String var4 = var1.getTriggerGroup(); + String var5 = var1.getJobName(); + String var6 = var1.getJobGroup(); + Class var7 = var1.getJobClazz(); + TriggerBuilder var8 = TriggerBuilder.newTrigger(); + var8.withIdentity(var3, var4); + var8.withSchedule(CronScheduleBuilder.cronSchedule(var2).withMisfireHandlingInstructionFireAndProceed().inTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID()))).startNow(); + var8.forJob(var5, var6); + ArrayList var9 = new ArrayList(); + var9.add(var8.build()); + ScheduleJobManager.getInstance().removeJob(var5, var6); + ScheduleJobManager.getInstance().addJob(var5, var6, "jobDescription", var7, var9, new HashMap()); + } + } + + public void stopSchedule(String var1, String var2) { + ScheduleJobManager.getInstance().removeJob(var1, var2); + } + + public static class HOLDER { + private static final DingTalkScheduleHelper INSTANCE = new DingTalkScheduleHelper(); + + public HOLDER() { + } + } + } diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/job/DingTalkSyncMemberJob.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/job/DingTalkSyncMemberJob.java new file mode 100644 index 0000000..385b97b --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/job/DingTalkSyncMemberJob.java @@ -0,0 +1,34 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: DingTalkSyncMemberJob + * Author: Louis + * Date: 2021/4/21 16:02 + */ + package com.fr.plugin.mqh.dingtalksyn.job; + + import com.fanruan.api.log.LogKit; + import com.fr.cluster.core.ClusterNode; + import com.fr.plugin.mqh.dingtalksyn.user.DingTalkUserManager; + import com.fr.scheduler.job.FineScheduleJob; + import com.fr.third.v2.org.quartz.JobExecutionContext; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class DingTalkSyncMemberJob extends FineScheduleJob { + public DingTalkSyncMemberJob() { + } + + public void run(JobExecutionContext jobExecutionContext, ClusterNode clusterNode) { + try { + DingTalkUserManager.getInstance().synDingTalkUsers(); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/kit/CustomRoleServiceKit.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/kit/CustomRoleServiceKit.java new file mode 100644 index 0000000..782eca3 --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/kit/CustomRoleServiceKit.java @@ -0,0 +1,65 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: CustomRoleServiceKit + * Author: Louis + * Date: 2021/5/14 10:31 + */ + package com.fr.plugin.mqh.dingtalksyn.kit; + + import com.fr.decision.authority.AuthorityContext; + import com.fr.decision.authority.base.constant.SoftRoleType; + import com.fr.decision.authority.base.constant.type.operation.ManualOperationType; + import com.fr.decision.authority.data.CustomRole; + import com.fr.decision.record.OperateMessage; + import com.fr.decision.webservice.bean.user.RoleBean; + import com.fr.decision.webservice.exception.general.DuplicatedNameException; + import com.fr.decision.webservice.utils.ControllerFactory; + import com.fr.decision.webservice.v10.user.CustomRoleService; + import com.fr.intelli.record.MetricRegistry; + import com.fr.stable.query.QueryFactory; + import com.fr.stable.query.condition.QueryCondition; + import com.fr.stable.query.restriction.Restriction; + import com.fr.stable.query.restriction.RestrictionFactory; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class CustomRoleServiceKit extends CustomRoleService { + private static volatile CustomRoleServiceKit customRoleServiceKit = null; + + public CustomRoleServiceKit() { + } + + public static CustomRoleServiceKit getInstance() { + if (customRoleServiceKit == null) { + customRoleServiceKit = new CustomRoleServiceKit(); + } + return customRoleServiceKit; + } + + public void addCustomRole(String username, RoleBean roleBean) throws Exception { + this.checkDuplicatedCustomRole(roleBean.getText()); + CustomRole customRole = (new CustomRole()).id(roleBean.getId()).name(roleBean.getText()).description(roleBean.getDescription()).creationType(ManualOperationType.KEY).lastOperationType(ManualOperationType.KEY).enable(true); + ControllerFactory.getInstance().getCustomRoleController(username).addCustomRole(username, customRole); + this.deleteSoftData(customRole.getName()); + MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Role", roleBean.getText(), "Dec-Log_Add")); + } + + private void checkDuplicatedCustomRole(String roleName) throws Exception { + QueryCondition queryCondition = QueryFactory.create().addRestriction(RestrictionFactory.eq("name", roleName)); + CustomRole customRole = (CustomRole) AuthorityContext.getInstance().getCustomRoleController().findOne(queryCondition); + if (customRole != null) { + throw new DuplicatedNameException(); + } + } + + private void deleteSoftData(String roleName) throws Exception { + QueryCondition queryCondition = QueryFactory.create().addRestriction(RestrictionFactory.and(new Restriction[]{RestrictionFactory.eq("deletedName", roleName), RestrictionFactory.eq("type", SoftRoleType.CUSTOM)})); + AuthorityContext.getInstance().getSoftDataController().remove(queryCondition); + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/kit/DepartmentServiceKit.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/kit/DepartmentServiceKit.java new file mode 100644 index 0000000..d401c33 --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/kit/DepartmentServiceKit.java @@ -0,0 +1,95 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: DepartmentServiceKit + * Author: Louis + * Date: 2021/5/14 9:38 + */ + package com.fr.plugin.mqh.dingtalksyn.kit; + + import com.fanruan.api.i18n.I18nKit; + import com.fanruan.api.util.StringKit; + import com.fr.decision.authority.AuthorityContext; + import com.fr.decision.authority.base.constant.type.operation.ManualOperationType; + import com.fr.decision.authority.data.Department; + import com.fr.decision.record.OperateMessage; + import com.fr.decision.webservice.exception.general.DuplicatedNameException; + import com.fr.decision.webservice.v10.user.DepartmentService; + import com.fr.general.ComparatorUtils; + import com.fr.intelli.record.MetricRegistry; + import com.fr.stable.StableUtils; + import com.fr.stable.query.QueryFactory; + import com.fr.stable.query.condition.QueryCondition; + import com.fr.stable.query.restriction.Restriction; + import com.fr.stable.query.restriction.RestrictionFactory; + + import java.util.ArrayList; + import java.util.Collections; + import java.util.List; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class DepartmentServiceKit extends DepartmentService { + public static final String DECISION_DEP_ROOT = "decision-dep-root"; + private static volatile DepartmentServiceKit departmentServiceKit = null; + + public DepartmentServiceKit() { + } + + public static DepartmentServiceKit getInstance() { + if (departmentServiceKit == null) { + departmentServiceKit = new DepartmentServiceKit(); + } + return departmentServiceKit; + } + + public void addDepartment(String id, String pId, String depName) throws Exception { + if (StringKit.equals(pId, DECISION_DEP_ROOT)) { + pId = null; + } + this.checkDuplicatedDepartmentName(pId, depName); + Department department = (new Department()).id(id).name(depName).parentId(pId).creationType(ManualOperationType.KEY).lastOperationType(ManualOperationType.KEY).enable(true); + AuthorityContext.getInstance().getDepartmentController().add(department); + MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Department", this.getDepartmentFullPath(pId, depName, "/"), "Dec-Log_Add")); + } + + private void checkDuplicatedDepartmentName(String parentId, String depName) throws Exception { + QueryCondition condition = QueryFactory.create().addRestriction(RestrictionFactory.and(new Restriction[]{RestrictionFactory.eq("name", depName), RestrictionFactory.eq("parentId", parentId)})); + Department sameNameDep = AuthorityContext.getInstance().getDepartmentController().findOne(condition); + if (sameNameDep != null) { + throw new DuplicatedNameException(); + } + } + + private String getDepartmentFullPath(String pId, String depName, String splitter) throws Exception { + List paths = new ArrayList<>(); + paths.add(depName); + while (!ComparatorUtils.equals(pId, DECISION_DEP_ROOT) && pId != null) { + Department parentDepartment = AuthorityContext.getInstance().getDepartmentController().getById(pId); + paths.add(parentDepartment.getName()); + pId = parentDepartment.getParentId(); + } + Collections.reverse(paths); + return StableUtils.join(paths.toArray(new String[0]), splitter); + } + + public void editDepartment(String departmentId, String depName, String pId) throws Exception { + if (StringKit.equals(pId, DECISION_DEP_ROOT)) { + pId = null; + } + Department department = AuthorityContext.getInstance().getDepartmentController().getById(departmentId); + String departmentFullPath = DepartmentService.getInstance().getDepartmentFullPath(departmentId); + if (!ComparatorUtils.equals(department.getName(), depName)) { + this.checkDuplicatedDepartmentName(department.getParentId(), depName); + department.setName(depName); + department.setParentId(pId); + AuthorityContext.getInstance().getDepartmentController().update(department); + } + MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Department", DepartmentService.getInstance().getDepartmentFullPath(departmentId), "Dec-Log_Update", I18nKit.getLocText("Fine-Dec_Department") + ":" + departmentFullPath)); + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/kit/UserServiceKit.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/kit/UserServiceKit.java new file mode 100644 index 0000000..7e9f096 --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/kit/UserServiceKit.java @@ -0,0 +1,186 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: UserServiceKit + * Author: Louis + * Date: 2021/5/14 8:28 + */ + package com.fr.plugin.mqh.dingtalksyn.kit; + + import com.dingtalk.api.response.OapiV2UserGetResponse; +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.StringKit; +import com.fr.decision.authority.AuthorityContext; +import com.fr.decision.authority.data.Post; +import com.fr.decision.authority.data.User; +import com.fr.decision.authority.data.personnel.DepRole; +import com.fr.decision.privilege.TransmissionTool; +import com.fr.decision.webservice.bean.user.DepartmentPostBean; +import com.fr.decision.webservice.bean.user.UserBean; +import com.fr.decision.webservice.utils.UserSourceFactory; +import com.fr.decision.webservice.utils.WebServiceUtils; +import com.fr.decision.webservice.v10.user.PositionService; +import com.fr.decision.webservice.v10.user.UserService; +import com.fr.stable.StringUtils; +import com.fr.stable.collections.CollectionUtils; +import com.fr.stable.query.QueryFactory; +import com.fr.stable.query.restriction.RestrictionFactory; + +import java.util.ArrayList; +import java.util.List; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class UserServiceKit extends UserService { + private static volatile UserServiceKit userServiceKit = null; + + public UserServiceKit() { + } + + public static UserServiceKit getInstance() { + if (userServiceKit == null) { + userServiceKit = new UserServiceKit(); + } + return userServiceKit; + } + + public UserBean createUserBean(OapiV2UserGetResponse.UserGetResponse userGetResponse) throws Exception { + UserBean userBean = new UserBean(); + userBean.setUsername(userGetResponse.getUserid()); + userBean.setRealName(userGetResponse.getName()); + userBean.setEmail(userGetResponse.getEmail()); + userBean.setMobile(userGetResponse.getMobile()); + userBean.setPassword(TransmissionTool.defaultEncrypt(userGetResponse.getUserid() + "123456")); + if (!CollectionUtils.isEmpty(userGetResponse.getRoleList())) { + userBean.setRoleIds(oapiUserRoles2Ids(userGetResponse.getRoleList())); + } + if (!CollectionUtils.isEmpty(userGetResponse.getDeptIdList())) { + List departmentPostIds = createDepartmentPostIds(userGetResponse.getDeptIdList(), userGetResponse.getTitle()); + userBean.setDepartmentPostIds(departmentPostIds); + } + return userBean; + } + + /** + * 钉钉部门list转为部门职务组合list + * + * @param deptIdList + * @param title + * @return + * @throws Exception + */ + private List createDepartmentPostIds(List deptIdList, String title) throws Exception { + List departmentPostIds = new ArrayList<>(); + String departmentPostId; + for (long currentDepId : deptIdList) { + departmentPostId = String.valueOf(currentDepId); + if (StringKit.isBlank(departmentPostId) || StringKit.equals(departmentPostId, "null")) { + continue; + } + // 职务处理 + String positionId = positionSynOperation(title, departmentPostId); + if (StringKit.isNotBlank(positionId)) { + departmentPostId = departmentPostId + "@@@" + positionId; + } + departmentPostIds.add(departmentPostId); + } + return departmentPostIds; + } + + /** + * 职务同步操作 + * + * @param title + * @return + * @throws Exception + */ + private String positionSynOperation(String title, String departmentId) throws Exception { + String position = StringKit.isNotBlank(title) ? title : "职员"; + Post post = AuthorityContext.getInstance().getPostController().findOne(QueryFactory.create().addRestriction(RestrictionFactory.eq("name", position))); + String positionId; + if (post == null) { + positionId = PositionService.getInstance().addPosition(position, position); + } else { + positionId = post.getId(); + } + List departmentPostBeanList = PositionService.getInstance().getPositionsUnderParentDepartment(getAdminUserId(), departmentId, position); + if (departmentPostBeanList == null || departmentPostBeanList.isEmpty()) { + try { + AuthorityContext.getInstance().getPostController().addPostToDepartment(positionId, departmentId); + } catch (Exception e) { + LogKit.info("dingtalksyn-UserServiceKit-positionSynOperation-addPostToDepartmentFailed-position:{}, departmentId:{}", positionId + position, departmentId); + LogKit.error(e.getMessage(), e); + } + } + return positionId; + } + + /** + * 获取管理员id + * + * @return + * @throws Exception + */ + public String getAdminUserId() throws Exception { + List adminUserIdList = UserService.getInstance().getAdminUserIdList(); + if (adminUserIdList.isEmpty()) { + return "admin"; + } + return StringKit.isNotBlank(adminUserIdList.get(0)) ? adminUserIdList.get(0) : "admin"; + } + + public UserBean updateUserBean(OapiV2UserGetResponse.UserGetResponse userGetResponse) throws Exception { + User user = UserService.getInstance().getUserByUserName(userGetResponse.getUserid()); + if (user == null) { + return null; + } + UserBean userBean = new UserBean(); + userBean.setId(user.getId()); + userBean.setUsername(user.getUserName()); + userBean.setRealName(userGetResponse.getName()); + userBean.setEmail(userGetResponse.getEmail()); + userBean.setMobile(userGetResponse.getMobile()); + if (!CollectionUtils.isEmpty(userGetResponse.getRoleList())) { + userBean.setRoleIds(oapiUserRoles2Ids(userGetResponse.getRoleList())); + } + if (!CollectionUtils.isEmpty(userGetResponse.getDeptIdList())) { + List departmentPostIds = createDepartmentPostIds(userGetResponse.getDeptIdList(), userGetResponse.getTitle()); + userBean.setDepartmentPostIds(departmentPostIds); + } + return userBean; + } + + /** + * 增加用户部门关联 + * + * @param userBean + * @throws Exception + */ + public void addUserDepartment(UserBean userBean) throws Exception { + if (CollectionUtils.isEmpty(userBean.getDepartmentPostIds())) { + return; + } + for (String departmentPostId : userBean.getDepartmentPostIds()) { + if (StringUtils.isEmpty(departmentPostId)) { + continue; + } + User user = UserService.getInstance().getUserByUserName(userBean.getUsername()); + DepRole depRole = WebServiceUtils.parseUniqueDepartmentPostId(departmentPostId); + UserSourceFactory.getInstance().checkSource(user, AuthorityContext.getInstance().getDepartmentController().getById(depRole.getDepartmentId())); + AuthorityContext.getInstance().getUserController().addUserToDepartmentAndPost(user.getId(), depRole.getDepartmentId(), depRole.getPostId()); + } + } + + private String[] oapiUserRoles2Ids(List oapiUserRoleList) { + String[] roleIds = new String[oapiUserRoleList.size()]; + for (int i = 0; i < oapiUserRoleList.size(); i++) { + roleIds[i] = String.valueOf(oapiUserRoleList.get(i).getId()); + } + return roleIds; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/provider/LifeCycleMonitorImpl.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/provider/LifeCycleMonitorImpl.java new file mode 100644 index 0000000..3b318aa --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/provider/LifeCycleMonitorImpl.java @@ -0,0 +1,49 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: LifeCycleMonitorImpl + * Author: Louis + * Date: 2021/3/30 15:10 + */ + package com.fr.plugin.mqh.dingtalksyn.provider; + + import com.fanruan.api.log.LogKit; + import com.fr.plugin.context.PluginContext; + import com.fr.plugin.mqh.dingtalksyn.helper.DingTalkScheduleHelper; + import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; + import com.fr.plugin.mqh.dingtalksyn.config.DingSynConfig; + + import static com.fr.plugin.mqh.dingtalksyn.helper.DingTalkScheduleHelper.DINGTALK_SCHEDULE_SYN_MEMBER_GROUP; + import static com.fr.plugin.mqh.dingtalksyn.helper.DingTalkScheduleHelper.DINGTALK_SCHEDULE_SYN_MEMBER_JOB_NAME; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class LifeCycleMonitorImpl extends AbstractPluginLifecycleMonitor { + public LifeCycleMonitorImpl() { + } + + @Override + public void afterRun(PluginContext pluginContext) { + DingSynConfig.getInstance(); + this.reStartSchedule(); + } + + @Override + public void beforeStop(PluginContext pluginContext) { + DingTalkScheduleHelper.getInstance().stopSchedule(DINGTALK_SCHEDULE_SYN_MEMBER_JOB_NAME, DINGTALK_SCHEDULE_SYN_MEMBER_GROUP); + } + + private void reStartSchedule() { + try { + String cronCondition = DingSynConfig.getInstance().getCronCondition(); + DingTalkScheduleHelper.getInstance().startSynMemberSchedule(cronCondition); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/provider/LocaleFinder.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/provider/LocaleFinder.java new file mode 100644 index 0000000..f7a9816 --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/provider/LocaleFinder.java @@ -0,0 +1,36 @@ + /* + * Copyright (C), 2018-2020 + * Project: starter + * FileName: LocaleFinder + * Author: Louis + * Date: 2020/8/31 22:19 + */ + package com.fr.plugin.mqh.dingtalksyn.provider; + + import com.fr.intelli.record.Focus; +import com.fr.intelli.record.Original; +import com.fr.record.analyzer.EnableMetrics; +import com.fr.stable.fun.impl.AbstractLocaleFinder; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + @EnableMetrics + public class LocaleFinder extends AbstractLocaleFinder { + public static final String PLUGIN_ID = "com.fr.plugin.mqh.dingtalksyn.job"; + + @Override + @Focus(id = PLUGIN_ID, text = "Plugin-dingtalksyn", source = Original.PLUGIN) + public String find() { + return "com/fr/plugin/mqh/dingtalksyn/locale/lang"; + } + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/request/GlobalRequestFilterBridge.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/request/GlobalRequestFilterBridge.java new file mode 100644 index 0000000..839dc8f --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/request/GlobalRequestFilterBridge.java @@ -0,0 +1,198 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: GlobalRequestFilterBridge + * Author: Louis + * Date: 2021/3/30 22:09 + */ + package com.fr.plugin.mqh.dingtalksyn.request; + + import com.fanruan.api.decision.login.LoginKit; +import com.fanruan.api.log.LogKit; +import com.fanruan.api.net.NetworkKit; +import com.fanruan.api.net.http.HttpKit; +import com.fanruan.api.util.IOKit; +import com.fanruan.api.util.StringKit; +import com.fr.base.TemplateUtils; +import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; +import com.fr.decision.webservice.utils.DecisionServiceConstants; +import com.fr.json.JSONObject; +import com.fr.plugin.mqh.dingtalksyn.config.DingSynConfig; +import com.fr.web.utils.WebUtils; + +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap; +import java.util.Map; + +import static com.fr.plugin.mqh.dingtalksyn.utils.DingAPI.GETTOKEN; +import static com.fr.plugin.mqh.dingtalksyn.utils.DingAPI.GET_USER_INFO; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class GlobalRequestFilterBridge extends AbstractGlobalRequestFilterProvider { + public static final String TPL_PATH = "/com/fr/plugin/mqh/dingtalksyn/web/codePage.html"; + public static final String DINGTALK_OPEN_JS = "/com/fr/plugin/mqh/dingtalksyn/web/dingtalk.open.js"; + public static final String CODE = "code"; + public static final String DING_TALK_LOGIN = "dt"; + + private DingSynConfig config; + + /** + * 过滤器名称 + * + * @return + */ + @Override + public String filterName() { + return "DingTalkSynFilter"; + } + + /** + * 过滤规则 + * + * @return + */ + @Override + public String[] urlPatterns() { + return new String[]{"/decision/*"}; + } + + /** + * 过滤器初始化 + * + * @param filterConfig + */ + @Override + public void init(FilterConfig filterConfig) { + this.config = DingSynConfig.getInstance(); + super.init(filterConfig); + } + + /** + * 过滤器处理 + * + * @param request + * @param response + * @param filterChain + */ + @Override + public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) { + try { + if (operation(request, response)) { + filterChain.doFilter(request, response); + } + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + + /** + * 用户验证登陆操作 + * + * @param req + * @param res + * @throws Exception + */ + private boolean operation(HttpServletRequest req, HttpServletResponse res) throws Exception { + String pathInfo = (req.getPathInfo() != null) ? req.getPathInfo() : StringKit.EMPTY; + if (StringKit.equals(DINGTALK_OPEN_JS, pathInfo)) { + WebUtils.printAsString(res, IOKit.readResourceAsString(DINGTALK_OPEN_JS)); + return false; + } + //DingTalk登陆参数 + String dt = NetworkKit.getHTTPRequestParameter(req, DING_TALK_LOGIN); + if (StringKit.isBlank(dt)) { + return true; + } + String code = NetworkKit.getHTTPRequestParameter(req, CODE); + LogKit.info("dingtalksyn-GlobalRequestFilterBridge-operation-code:{}", code); + if (StringKit.isEmpty(code)) { + loginPage(req, res); + return false; + } + String accessToken = getAccessToken(code); + String username = getUsername(code, accessToken); + LogKit.info("dingtalksyn-GlobalRequestFilterBridge-operation-username:{}", username); + if (StringKit.isEmpty(username)) { + return true; + } + String tokenFR = LoginKit.login(req, res, username); + req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, tokenFR); + return true; + } + + /** + * 钉钉获取code页面 + * + * @param req + * @param res + * @return + * @throws Exception + */ + private void loginPage(HttpServletRequest req, HttpServletResponse res) throws Exception { + Map parameterMap = new HashMap<>(); + parameterMap.put("corpId", this.config.getCorpId()); + parameterMap.put("openJs", WebUtils.createServletURL(req) + DINGTALK_OPEN_JS); + parameterMap.put("remoteServletURL", getRemoteServletURL(WebUtils.getOriginalURL(req))); + String codePage = TemplateUtils.renderTemplate(TPL_PATH, parameterMap); + WebUtils.printAsString(res, codePage); + } + + /** + * 处理请求url加入code参数 + * + * @param url + * @return + */ + private String getRemoteServletURL(String url) { + if (url.contains("?")) { + return url + "&" + CODE + "="; + } + return url + "?" + CODE + "="; + } + + /** + * 获取access_token + * + * @param code + * @return + * @throws Exception + */ + private String getAccessToken(String code) throws Exception { + Map tokenParams = new HashMap<>(); + tokenParams.put("appkey", this.config.getAppKey()); + tokenParams.put("appsecret", this.config.getAppSecret()); + tokenParams.put("code", code); + LogKit.info("dingtalksyn-GlobalRequestFilterBridge-getAccessToken-params:{}", tokenParams); + String res = HttpKit.get(GETTOKEN, tokenParams); + LogKit.info("dingtalksyn-GlobalRequestFilterBridge-getAccessToken-res:{}", res); + if (StringKit.isEmpty(res)) { + return StringKit.EMPTY; + } + return new JSONObject(res).getString("access_token"); + } + + /** + * 通过凭证获得username + * + * @param code + * @param accessToken + * @return + */ + private String getUsername(String code, String accessToken) throws Exception { + Map userInfoParams = new HashMap<>(); + userInfoParams.put("access_token", accessToken); + userInfoParams.put("code", code); + String userRes = HttpKit.get(GET_USER_INFO, userInfoParams); + LogKit.info("dingtalksyn-GlobalRequestFilterBridge-getUsername-userRes:{}", userRes); + return new JSONObject(userRes).getString("userid"); + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/user/DingTalkUserManager.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/user/DingTalkUserManager.java new file mode 100644 index 0000000..b0d7cef --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/user/DingTalkUserManager.java @@ -0,0 +1,179 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: DingTalkUserManager + * Author: Louis + * Date: 2021/4/21 16:18 + */ + package com.fr.plugin.mqh.dingtalksyn.user; + + import com.dingtalk.api.response.OapiRoleListResponse; +import com.dingtalk.api.response.OapiV2DepartmentListsubResponse; +import com.dingtalk.api.response.OapiV2UserGetResponse; +import com.fanruan.api.decision.user.UserKit; +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.StringKit; +import com.fr.decision.authority.AuthorityContext; +import com.fr.decision.authority.base.constant.type.operation.ManualOperationType; +import com.fr.decision.authority.data.Department; +import com.fr.decision.webservice.bean.user.RoleBean; +import com.fr.decision.webservice.bean.user.UserBean; +import com.fr.decision.webservice.v10.user.CustomRoleService; +import com.fr.decision.webservice.v10.user.UserService; +import com.fr.plugin.mqh.dingtalksyn.config.DingSynConfig; +import com.fr.plugin.mqh.dingtalksyn.kit.CustomRoleServiceKit; +import com.fr.plugin.mqh.dingtalksyn.kit.DepartmentServiceKit; +import com.fr.plugin.mqh.dingtalksyn.kit.UserServiceKit; +import com.taobao.api.ApiException; + +import java.util.List; + +import static com.fr.plugin.mqh.dingtalksyn.kit.DepartmentServiceKit.DECISION_DEP_ROOT; +import static com.fr.plugin.mqh.dingtalksyn.utils.DingAPI.*; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public final class DingTalkUserManager { + private DingSynConfig config; + + public DingTalkUserManager() { + this.config = DingSynConfig.getInstance(); + } + + private static class HOLDER { + private static final DingTalkUserManager INSTANCE = new DingTalkUserManager(); + } + public static DingTalkUserManager getInstance() { + return HOLDER.INSTANCE; + } + + /** + * 同步更新的字段包括:用户、邮箱、手机、部门、职位、角色。 + * 用户唯一字段用户名,更新时也是基于用户名。 + * + * @throws Exception + */ + public synchronized void synDingTalkUsers() throws Exception { + LogKit.info("dingtalksyn-DingTalkUserManager-synDingTalkUsers-start"); + // 同步用户角色 + List oapiRoleGroupList = getOapiRoleList(); + for (OapiRoleListResponse.OpenRoleGroup openRoleGroup : oapiRoleGroupList) { + List openRoleList = openRoleGroup.getRoles(); + for (OapiRoleListResponse.OpenRole openRole : openRoleList) { + roleSynOperation(openRoleGroup.getName(), openRole); + } + } + // 同步部门和用户信息 + departmentSynLoop(this.config.getRootDepId()); + LogKit.info("dingtalksyn-DingTalkUserManager-synDingTalkUsers-end"); + } + + /** + * 按部门遍历子部门并同步人员信息 + * + * @param deptId + * @throws Exception + */ + private void departmentSynLoop(long deptId) throws ApiException { + List departmentList = getDepartmentList(deptId); + if (departmentList == null || departmentList.isEmpty()) { + return; + } + // 同步部门信息 + for (OapiV2DepartmentListsubResponse.DeptBaseResponse oapiDepartment : departmentList) { + try { + departmentSynOperation(oapiDepartment); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + // 同步当前部门的用户信息 + List deptMemberList = getDeptMember(oapiDepartment.getDeptId()); + for (String userId : deptMemberList) { + try { + OapiV2UserGetResponse.UserGetResponse userGetResponse = getUserResponse(userId); + if (userGetResponse == null) { + continue; + } + userSynOperation(userGetResponse); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + // 操作子部门遍历 + departmentSynLoop(oapiDepartment.getDeptId()); + } + } + + /** + * 角色的新增更新操作 + * + * @param openRole + * @throws Exception + */ + private void roleSynOperation(String groupName, OapiRoleListResponse.OpenRole openRole) throws Exception { + if (openRole == null) { + return; + } + RoleBean roleBean = CustomRoleService.getInstance().getCustomRole(String.valueOf(openRole.getId())); + String roleName = StringKit.isBlank(groupName) ? openRole.getName() : groupName + "-" + openRole.getName(); + if (roleBean == null) { + roleBean = new RoleBean(roleName, String.valueOf(openRole.getId()), roleName, ManualOperationType.KEY.toInteger()); + CustomRoleServiceKit.getInstance().addCustomRole(UserServiceKit.getInstance().getAdminUserId(), roleBean); + } else if(!StringKit.equals(roleBean.getText(), roleName)) { + roleBean.setText(roleName); + roleBean.setDescription(roleName); + CustomRoleService.getInstance().editCustomRole(roleBean.getId(), roleBean); + } + } + + /** + * 部门组织的新增更新操作 + * + * @param oapiDepartment + * @throws Exception + */ + private void departmentSynOperation(OapiV2DepartmentListsubResponse.DeptBaseResponse oapiDepartment) throws Exception { + String departmentId = String.valueOf(oapiDepartment.getDeptId()); + String parentId = String.valueOf(oapiDepartment.getParentId()); + if (StringKit.equals(parentId, String.valueOf(this.config.getRootDepId()))) { parentId = DECISION_DEP_ROOT; } + String depName = oapiDepartment.getName(); + Department department = AuthorityContext.getInstance().getDepartmentController().getById(departmentId); + if (department == null) { + DepartmentServiceKit.getInstance().addDepartment(departmentId, parentId, depName); + } else { + DepartmentServiceKit.getInstance().editDepartment(department.getId(), depName, parentId); + } + } + + /** + * 用户新增更新操作 + * + * @param userGetResponse + * @throws Exception + */ + private void userSynOperation(OapiV2UserGetResponse.UserGetResponse userGetResponse) throws Exception { + UserBean userBean; + if (UserKit.existUsername(userGetResponse.getUserid())) { + userBean = UserServiceKit.getInstance().updateUserBean(userGetResponse); + if (userBean == null) { + return; + } + UserService.getInstance().editUser(userBean); + UserServiceKit.getInstance().addUserDepartment(userBean); + } else { + userBean = UserServiceKit.getInstance().createUserBean(userGetResponse); + try { + UserService.getInstance().addUser(userBean); + } catch (Exception e) { + LogKit.error("dingtalksyn-DingTalkUserManager-userSynOperation-Username:{}, RealName:{}, Mobile:{}, Email:{}", + userBean.getUsername(), userBean.getRealName(), userBean.getMobile(), userBean.getEmail()); + LogKit.error(e.getMessage(), e); + } + } + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/utils/DingAPI.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/utils/DingAPI.java new file mode 100644 index 0000000..b3051b2 --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/utils/DingAPI.java @@ -0,0 +1,150 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: DingAPI + * Author: Louis + * Date: 2021/5/13 16:16 + */ + package com.fr.plugin.mqh.dingtalksyn.utils; + + import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.*; +import com.dingtalk.api.response.*; +import com.fr.plugin.mqh.dingtalksyn.config.DingSynConfig; +import com.taobao.api.ApiException; + +import java.util.List; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class DingAPI { + public static final int TOKEN_EXPIRE_TIME = 3600000; + /** + * 获取企业内部应用的access_token + */ + public static final String GETTOKEN = "https://oapi.dingtalk.com/gettoken"; + /** + * 通过免登码获取用户信息 + */ + public static final String GET_USER_INFO = "https://oapi.dingtalk.com/user/getuserinfo"; + public static final String USER_GET = "https://oapi.dingtalk.com/topapi/v2/user/get"; + public static final String DEPARTMENT_LIST = "https://oapi.dingtalk.com/topapi/v2/department/listsub"; + public static final String GET_DEPT_MEMBER = "https://oapi.dingtalk.com/topapi/user/listid"; + public static final String GET_DEPT = "https://oapi.dingtalk.com/topapi/v2/department/get"; + public static final String ROLE_LIST = "https://oapi.dingtalk.com/topapi/role/list"; + public static final String GETROLE = "https://oapi.dingtalk.com/topapi/role/getrole"; + + /** + * 根据deptId获取用户详情 + * + * @param deptId + * @return + * @throws ApiException + */ + public static OapiV2DepartmentGetResponse.DeptGetResponse getDeptResponse(long deptId) throws ApiException { + DingTalkClient client = new DefaultDingTalkClient(GET_DEPT); + OapiV2DepartmentGetRequest req = new OapiV2DepartmentGetRequest(); + req.setDeptId(deptId); + req.setLanguage("zh_CN"); + OapiV2DepartmentGetResponse rsp = client.execute(req, DingTokenUtils.getAccessToken()); + return rsp.getResult(); + } + + /** + * 获取部门用户userid列表 + * + * @param deptId + * @return + * @throws ApiException + */ + public static List getDeptMember(long deptId) throws ApiException { + DingTalkClient client = new DefaultDingTalkClient(GET_DEPT_MEMBER); + OapiUserListidRequest req = new OapiUserListidRequest(); + req.setDeptId(deptId); + OapiUserListidResponse rsp = client.execute(req, DingTokenUtils.getAccessToken()); + return rsp.getResult().getUseridList(); + } + + /** + * 获取部门列表 + * + * @return + * @throws ApiException + */ + public static List getDepartmentList(long deptId) throws ApiException { + DingTalkClient client = new DefaultDingTalkClient(DEPARTMENT_LIST); + OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest(); + req.setDeptId(deptId); + req.setLanguage("zh_CN"); + OapiV2DepartmentListsubResponse rsp = client.execute(req, DingTokenUtils.getAccessToken()); + return rsp.getResult(); + } + + /** + * 根据roleId获取角色详情 + * + * @param roleId + * @return + * @throws ApiException + */ + public static OapiRoleGetroleResponse.OpenRole getRoleResponse(long roleId) throws ApiException { + DingTalkClient client = new DefaultDingTalkClient(GETROLE); + OapiRoleGetroleRequest req = new OapiRoleGetroleRequest(); + req.setRoleId(roleId); + OapiRoleGetroleResponse rsp = client.execute(req, DingTokenUtils.getAccessToken()); + return rsp.getRole(); + } + + /** + * 获取角色列表 + * + * @return + * @throws ApiException + */ + public static List getOapiRoleList() throws ApiException { + DingTalkClient client = new DefaultDingTalkClient(ROLE_LIST); + OapiRoleListRequest req = new OapiRoleListRequest(); + req.setSize(200L); + req.setOffset(0L); + OapiRoleListResponse rsp = client.execute(req, DingTokenUtils.getAccessToken()); + return rsp.getResult().getList(); + } + + /** + * 根据userid获取用户详情 + * + * @param userId + * @return + * @throws ApiException + */ + public static OapiV2UserGetResponse.UserGetResponse getUserResponse(String userId) throws ApiException { + DingTalkClient client = new DefaultDingTalkClient(USER_GET); + OapiV2UserGetRequest req = new OapiV2UserGetRequest(); + req.setUserid(userId); + req.setLanguage("zh_CN"); + OapiV2UserGetResponse rsp = client.execute(req, DingTokenUtils.getAccessToken()); + return rsp.getResult(); + } + + /** + * 获取企业内部应用的access_token + * + * @return + * @throws ApiException + */ + public static String getAccessToken() throws ApiException { + DingTalkClient client = new DefaultDingTalkClient(GETTOKEN); + OapiGettokenRequest request = new OapiGettokenRequest(); + request.setAppkey(DingSynConfig.getInstance().getAppKey()); + request.setAppsecret(DingSynConfig.getInstance().getAppSecret()); + request.setHttpMethod("GET"); + OapiGettokenResponse response = client.execute(request); + return response.getAccessToken(); + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/mqh/dingtalksyn/utils/DingTokenUtils.java b/src/main/java/com/fr/plugin/mqh/dingtalksyn/utils/DingTokenUtils.java new file mode 100644 index 0000000..e4b165d --- /dev/null +++ b/src/main/java/com/fr/plugin/mqh/dingtalksyn/utils/DingTokenUtils.java @@ -0,0 +1,67 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: DingTokenUtils + * Author: Louis + * Date: 2021/5/14 14:23 + */ + package com.fr.plugin.mqh.dingtalksyn.utils; + + import com.fanruan.api.log.LogKit; + import com.fanruan.api.util.StringKit; + import com.fr.plugin.mqh.dingtalksyn.config.DingSynConfig; + import com.fr.store.StateHubManager; + import com.fr.store.StateHubService; + + import static com.fr.plugin.mqh.dingtalksyn.utils.DingAPI.TOKEN_EXPIRE_TIME; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class DingTokenUtils { + + public static final String DINGTALKSYN_ACCESS_TOKEN = "dingtalksyn_access_token"; + public static final String DINGTALKSYN_SUITE_TICKET = "dingtalksyn_suite_ticket"; + + private static final StateHubService tokenService = StateHubManager.applyForService(DINGTALKSYN_ACCESS_TOKEN); + private static final StateHubService ticketService = StateHubManager.applyForService(DINGTALKSYN_SUITE_TICKET); + + public DingTokenUtils() { + } + + /** + * 缓存钉钉端AccessToken + * + * @return + */ + public static String getAccessToken() { + String appKey = DingSynConfig.getInstance().getAppKey(); + try { + if (StringKit.isBlank(tokenService.get(appKey))) { + tokenService.put(appKey, DingAPI.getAccessToken(), TOKEN_EXPIRE_TIME); + } + return tokenService.get(appKey); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + return StringKit.EMPTY; + } + } + + /** + * 缓存钉钉端SuiteTicket + * + * @return + */ + public static void setSuiteTicket(String suiteTicket) { + String appKey = DingSynConfig.getInstance().getAppKey(); + try { + ticketService.put(appKey, suiteTicket, TOKEN_EXPIRE_TIME); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + } \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/mqh/dingtalksyn/locale/lang.properties b/src/main/resources/com/fr/plugin/mqh/dingtalksyn/locale/lang.properties new file mode 100644 index 0000000..4b80ff4 --- /dev/null +++ b/src/main/resources/com/fr/plugin/mqh/dingtalksyn/locale/lang.properties @@ -0,0 +1,18 @@ +Plugin-dingtalksyn=DingTalk syn Plugin +Plugin-dingtalksyn_Group=DingTalk syn Plugin +Plugin-dingtalksyn_Config_CronCondition=Cron Condition +Plugin-dingtalksyn_Config_CronCondition_Description=Cron Condition +Plugin-dingtalksyn_Config_appKey=APPKEY +Plugin-dingtalksyn_Config_appKey_Description=APPKEY +Plugin-dingtalksyn_Config_appSecret=appSecret +Plugin-dingtalksyn_Config_appSecret_Description=appSecret +Plugin-dingtalksyn_Config_corpId=Corp Id +Plugin-dingtalksyn_Config_corpId_Description=Corp Id +Plugin-dingtalksyn_Config_rootDepId=Root Department ID +Plugin-dingtalksyn_Config_rootDepId_Description=Root Department ID +Plugin-dingtalksyn_Config_Token=Token +Plugin-dingtalksyn_Config_Token_Description=Token +Plugin-dingtalksyn_Config_AesKey=AesKey +Plugin-dingtalksyn_Config_AesKey_Description=AesKey +Plugin-dingtalksyn_Error_500=error +Plugin-dingtalksyn_Error_501=DingTalkSyn Plugin License Expired! \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/mqh/dingtalksyn/locale/lang_zh_CN.properties b/src/main/resources/com/fr/plugin/mqh/dingtalksyn/locale/lang_zh_CN.properties new file mode 100644 index 0000000..b91492b --- /dev/null +++ b/src/main/resources/com/fr/plugin/mqh/dingtalksyn/locale/lang_zh_CN.properties @@ -0,0 +1,18 @@ +Plugin-dingtalksyn=\u9489\u9489\u6570\u636E\u540C\u6B65\u63D2\u4EF6 +Plugin-dingtalksyn_Group=\u9489\u9489\u6570\u636E\u540C\u6B65\u63D2\u4EF6 +Plugin-dingtalksyn_Config_CronCondition=Cron\u8868\u8FBE\u5F0F +Plugin-dingtalksyn_Config_CronCondition_Description=Cron\u8868\u8FBE\u5F0F +Plugin-dingtalksyn_Config_appKey=\u5E94\u7528\u7CFB\u7EDF\u7684APPKEY +Plugin-dingtalksyn_Config_appKey_Description=\u5E94\u7528\u7CFB\u7EDF\u7684APPKEY +Plugin-dingtalksyn_Config_appSecret=\u5E94\u7528\u7CFB\u7EDF\u7684appSecret +Plugin-dingtalksyn_Config_appSecret_Description=\u5E94\u7528\u7CFB\u7EDF\u7684appSecret +Plugin-dingtalksyn_Config_corpId=Corp Id +Plugin-dingtalksyn_Config_corpId_Description=Corp Id +Plugin-dingtalksyn_Config_rootDepId=\u6839\u90E8\u95E8ID +Plugin-dingtalksyn_Config_rootDepId_Description=\u6839\u90E8\u95E8ID +Plugin-dingtalksyn_Config_Token=\u7B7E\u540DToken +Plugin-dingtalksyn_Config_Token_Description=\u7B7E\u540DToken +Plugin-dingtalksyn_Config_AesKey=\u52A0\u5BC6aes_key +Plugin-dingtalksyn_Config_AesKey_Description=\u52A0\u5BC6aes_key +Plugin-dingtalksyn_Error_500=error +Plugin-dingtalksyn_Error_501=DingTalkSyn\u63D2\u4EF6\u8BB8\u53EF\u5931\u6548! \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/mqh/dingtalksyn/web/codePage.html b/src/main/resources/com/fr/plugin/mqh/dingtalksyn/web/codePage.html new file mode 100644 index 0000000..064ed88 --- /dev/null +++ b/src/main/resources/com/fr/plugin/mqh/dingtalksyn/web/codePage.html @@ -0,0 +1,24 @@ + + + + + + + DingTalk + + + + + + \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/mqh/dingtalksyn/web/dingtalk.open.js b/src/main/resources/com/fr/plugin/mqh/dingtalksyn/web/dingtalk.open.js new file mode 100644 index 0000000..3d1ed4d --- /dev/null +++ b/src/main/resources/com/fr/plugin/mqh/dingtalksyn/web/dingtalk.open.js @@ -0,0 +1 @@ +(function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.dd=t():e.dd=t()})(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=707)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),o=n(180),i=n(2);t.ENV_ENUM=i.ENV_ENUM,t.ENV_ENUM_SUB=i.ENV_ENUM_SUB;var a=n(3);n(186),t.ddSdk=new a.Sdk(r.getENV(),o.log)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.addWatchParamsDeal=function(e){var t=Object.assign({},e);return t.watch=!0,t},t.addDefaultCorpIdParamsDeal=function(e){var t=Object.assign({},e);return t.corpId="corpId",t},t.genDefaultParamsDealFn=function(e){var t=Object.assign({},e);return function(e){return Object.assign({},t,e)}},t.forceChangeParamsDealFn=function(e){var t=Object.assign({},e);return function(e){return Object.assign(e,t)}},t.genBoolResultDealFn=function(e){return function(t){var n=Object.assign({},t);return e.forEach(function(e){void 0!==n[e]&&(n[e]=!!n[e])}),n}},t.genBizStoreParamsDealFn=function(e){var t=Object.assign({},e);return"string"!=typeof t.params?(t.params=JSON.stringify(t),t):t}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(3),o=n(3);t.ENV_ENUM=o.ENV_ENUM,t.APP_TYPE=o.APP_TYPE,t.ENV_ENUM_SUB=o.ENV_ENUM_SUB;var i,a=n(183);(function(e){e.singlePage="singlePage",e.miniApp="miniApp",e.miniWidget="miniWidget"})(i||(i={})),t.getUA=function(){var e="";try{"undefined"!=typeof navigator&&(e=navigator&&(navigator.userAgent||navigator.swuserAgent)||"")}catch(t){e=""}return e},t.getENV=function(){var e=t.getUA(),n=/iPhone|iPad|iPod|iOS/i.test(e),o=/Android/i.test(e),s=/Nebula/i.test(e),d=/DingTalk/i.test(e),u=/dd-web/i.test(e),c="object"==typeof nuva,l="object"==typeof dd&&"function"==typeof dd.dtBridge,f=l&&n||c&&n,v=d||a.default.isDingTalk,p=n&&v||a.default.isWeexiOS||f,_=o&&v||a.default.isWeexAndroid,E=s&&v||l,N=u,P=r.APP_TYPE.WEB;if(N)P=r.APP_TYPE.WEBVIEW_IN_MINIAPP;else if(E)P=r.APP_TYPE.MINI_APP;else if(a.default.isWeexiOS||a.default.isWeexAndroid)try{var M=weex.config.ddWeexEnv;P=M===i.miniWidget?r.APP_TYPE.WEEX_WIDGET:r.APP_TYPE.WEEX}catch(e){P=r.APP_TYPE.WEEX}var h,m="*",k=e.match(/AliApp\(\w+\/([a-zA-Z0-9.-]+)\)/);null===k&&(k=e.match(/DingTalk\/([a-zA-Z0-9.-]+)/));var b;k&&k[1]&&(b=k[1]);var g="";if("undefined"!=typeof name&&(g=name),g)try{var I=JSON.parse(g);I.hostVersion&&(b=I.hostVersion),m=I.language||navigator.language||"*",h=I.containerId}catch(e){}var y=!!h;y&&!b&&(k=e.match(/DingTalk\(([a-zA-Z0-9\.-]+)\)/))&&k[1]&&(b=k[1]);var A,S=r.ENV_ENUM_SUB.noSub;if(p)A=r.ENV_ENUM.ios;else if(_)A=r.ENV_ENUM.android;else if(y){var V=e.indexOf("Macintosh; Intel Mac OS")>-1;S=V?r.ENV_ENUM_SUB.mac:r.ENV_ENUM_SUB.win,A=r.ENV_ENUM.pc}else A=r.ENV_ENUM.notInDingTalk;return{platform:A,platformSub:S,version:b,appType:P,language:m}}},function(e,t,n){"use strict";function r(e,t){var n=e&&e.vs;return"object"==typeof n&&(n=n[t.platformSub]),n}Object.defineProperty(t,"__esModule",{value:!0});var o=n(189);t.APP_TYPE=o.APP_TYPE,t.LogLevel=o.LogLevel,t.isFunction=o.isFunction,t.compareVersion=o.compareVersion,t.ENV_ENUM=o.ENV_ENUM,t.ENV_ENUM_SUB=o.ENV_ENUM_SUB;var i=function(){function e(e,t){var n=this;this.configJsApiList=[],this.hadConfig=!1,this.p={},this.config$=new Promise(function(e,t){n.p.reject=t,n.p.resolve=e}),this.logQueue=[],this.devConfig={debug:!1},this.platformConfigMap={},this.invokeAPIConfigMapByMethod={},this.isBridgeDrity=!0,this.getExportSdk=function(){return n.exportSdk},this.setAPI=function(e,t){n.invokeAPIConfigMapByMethod[e]=t},this.setPlatform=function(e){n.isBridgeDrity=!0,n.platformConfigMap[e.platform]=e,e.platform===n.env.platform&&e.bridgeInit().catch(function(e){n.customLog(o.LogLevel.WARNING,["auto bridgeInit error",e||""])})},this.getPlatformConfigMap=function(){return n.platformConfigMap},this.deleteApiConfig=function(e,t){var r=n.invokeAPIConfigMapByMethod[e];r&&delete r[t]},this.invokeAPI=function(e,t,i){void 0===t&&(t={}),void 0===i&&(i=!0),n.customLog(o.LogLevel.INFO,['==> "'+e+'" params: ',t]);var a=+new Date,s=a+"_"+Math.floor(1e3*Math.random());if(n.devConfig.onBeforeInvokeAPI)try{n.devConfig.onBeforeInvokeAPI({invokeId:s,method:e,params:t,startTime:a})}catch(e){n.customLog(o.LogLevel.ERROR,["call Hook:onBeforeInvokeAPI failed, reason:",e])}return!1===n.devConfig.isAuthApi&&(i=!1),n.bridgeInitFn().then(function(d){var u=n.invokeAPIConfigMapByMethod[e],c=n.devConfig.forceEnableDealApiFnMap&&n.devConfig.forceEnableDealApiFnMap[e]&&!0===n.devConfig.forceEnableDealApiFnMap[e](t),l=!c&&(!0===n.devConfig.isDisableDeal||n.devConfig.disbaleDealApiWhiteList&&-1!==n.devConfig.disbaleDealApiWhiteList.indexOf(e));if(u||!i){var f;if(u&&(f=u[n.env.platform]),f||!i){var v={};v=!l&&f&&f.paramsDeal&&o.isFunction(f.paramsDeal)?f.paramsDeal(t):Object.assign({},t);var p=function(e){return!l&&f&&f.resultDeal&&o.isFunction(f.resultDeal)?f.resultDeal(e):e};if(o.isFunction(v.onSuccess)){var _=v.onSuccess;v.onSuccess=function(e){_(p(e))}}return d(e,v).then(p,function(t){var a=n.hadConfig&&void 0===n.isReady&&-1!==n.configJsApiList.indexOf(e),s="object"==typeof t&&"string"==typeof t.errorCode&&t.errorCode===o.ERROR_CODE.no_permission,u="object"==typeof t&&"string"==typeof t.errorCode&&t.errorCode===o.ERROR_CODE.cancel,c=r(f,n.env),l=c&&n.env.version&&o.compareVersion(n.env.version,c),_=(n.env.platform===o.ENV_ENUM.ios||n.env.platform===o.ENV_ENUM.android)&&a&&s,E=n.env.platform===o.ENV_ENUM.pc&&a&&(l&&!u&&i||s);return _||E?n.config$.then(function(){return d(e,v).then(p)}):Promise.reject(t)}).then(function(r){if(n.devConfig.onAfterInvokeAPI)try{n.devConfig.onAfterInvokeAPI({invokeId:s,method:e,params:t,payload:r,isSuccess:!0,startTime:a,duration:+new Date-a})}catch(e){n.customLog(o.LogLevel.ERROR,["call Hook:onAfterInvokeAPI failed, reason:",e])}return n.customLog(o.LogLevel.INFO,['<== "'+e+'" success result: ',r]),r},function(r){if(n.devConfig.onAfterInvokeAPI)try{n.devConfig.onAfterInvokeAPI({invokeId:s,method:e,params:t,payload:r,startTime:a,duration:+new Date-a,isSuccess:!1})}catch(r){n.customLog(o.LogLevel.ERROR,["call Hook:onAfterInvokeAPI failed, reason:",r])}return n.customLog(o.LogLevel.WARNING,['<== "'+e+'" fail result: ',r]),Promise.reject(r)})}var E='"'+e+'" do not support the current platform ('+n.env.platform+")";return n.customLog(o.LogLevel.ERROR,[E]),Promise.reject({errorCode:o.ERROR_CODE.jsapi_internal_error,errorMessage:E})}var E="This API method is not configured for the platform ("+n.env.platform+")";return n.customLog(o.LogLevel.ERROR,[E]),Promise.reject({errorCode:o.ERROR_CODE.jsapi_internal_error,errorMessage:E})})},this.customLog=function(e,t){var r={level:e,text:t,time:new Date};if(!0===n.devConfig.debug)n.customLogInstance(r);else{n.logQueue.push(r);n.logQueue.length>10&&(n.logQueue=n.logQueue.slice(n.logQueue.length-10))}},this.clearLogQueue=function(){n.logQueue.forEach(function(e){n.customLogInstance(e)}),n.logQueue=[]},this.customLogInstance=t,this.env=e,this.bridgeInitFn=function(){if(n.bridgeInitFnPromise&&!n.isBridgeDrity)return n.bridgeInitFnPromise;n.isBridgeDrity=!1;var t=n.platformConfigMap[e.platform];if(t)n.bridgeInitFnPromise=t.bridgeInit().catch(function(e){return n.customLog(o.LogLevel.ERROR,["\b\b\b\b\bJsBridge initialization fails, jsapi will not work"]),Promise.reject(e)});else{var r="Do not support the current environment:"+e.platform;n.customLog(o.LogLevel.WARNING,[r]),n.bridgeInitFnPromise=Promise.reject(new Error(r))}return n.bridgeInitFnPromise};var i=function(e){void 0===e&&(e={}),n.devConfig=Object.assign(n.devConfig,e),!0===e.debug&&n.clearLogQueue(),e.extraPlatform&&n.setPlatform(e.extraPlatform)};this.exportSdk={config:function(t){void 0===t&&(t={});var r=!0;Object.keys(t).forEach(function(e){-1===["debug","usePromise"].indexOf(e)&&(r=!1)}),r?(n.customLog(o.LogLevel.WARNING,["This is a deprecated feature, recommend use dd.devConfig"]),i(t)):n.hadConfig?n.customLog(o.LogLevel.WARNING,["Config has been executed"]):(t.jsApiList&&(n.configJsApiList=t.jsApiList),n.hadConfig=!0,n.bridgeInitFn().then(function(r){var o=n.platformConfigMap[e.platform],i=t;o.authParamsDeal&&(i=o.authParamsDeal(i)),r(o.authMethod,i).then(function(e){n.isReady=!0,n.p.resolve(e)}).catch(function(e){n.isReady=!1,n.p.reject(e)})},function(){n.customLog(o.LogLevel.ERROR,['\b\b\b\b\bJsBridge initialization failed and "dd.config" failed to call'])}))},devConfig:i,ready:function(e){!1===n.hadConfig?(n.customLog(o.LogLevel.WARNING,["You don 't use a dd.config, so you don't need to wrap dd.ready, recommend remove dd.ready"]),n.bridgeInitFn().then(function(){e()})):n.config$.then(function(t){e()})},error:function(e){n.config$.catch(function(t){e(t)})},on:function(t,r){n.bridgeInitFn().then(function(){n.platformConfigMap[e.platform].event.on(t,r)})},off:function(t,r){n.bridgeInitFn().then(function(){n.platformConfigMap[e.platform].event.off(t,r)})},env:e,checkJsApi:function(t){void 0===t&&(t={});var i={};return t.jsApiList&&t.jsApiList.forEach(function(t){var a=n.invokeAPIConfigMapByMethod[t];if(a){var s=a[e.platform],d=r(s,e);d&&e.version&&o.compareVersion(e.version,d)&&(i[t]=!0)}i[t]||(i[t]=!1)}),Promise.resolve(i)},_invoke:function(e,t){return void 0===t&&(t={}),n.invokeAPI(e,t,!1)}}}return e}();t.Sdk=i},function(e,t,n){(function(t,n){e.exports=n()})(0,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=579)}({179:function(e,t,n){"use strict";var r=n(181);e.exports=r},181:function(e,t,n){"use strict";var r=n(183),o=n(184),i=n(182),a=n(185),s=new i,d=!1,u="",c=null,l={},f=/{.*}/;try{var v=window.name.match(f);if(v&&v[0])var l=JSON.parse(v[0])}catch(e){l={}}l.hostOrigin&&".dingtalk.com"===l.hostOrigin.split(":")[1].slice(0-".dingtalk.com".length)&&l.containerId&&(d=!0,u=l.hostOrigin,c=l.containerId);var p={},_=new Promise(function(e,t){p._resolve=e,p._reject=t}),E={},N=null;window.top!==window&&(N=window.top,p._resolve()),E[a.SYS_INIT]=function(e){N=e.frameWindow,p._resolve(),e.respond({})},window.addEventListener("message",function(e){var t=e.data,n=e.origin;if(n===u)if("response"===t.type&&t.msgId){var r=t.msgId,i=s.getMsyById(r);i&&i.receiveResponse(t.body,!t.success)}else if("event"===t.type&&t.msgId){var r=t.msgId,i=s.getMsyById(r);i&&i.receiveEvent(t.eventName,t.body)}else if("request"===t.type&&t.msgId){var i=new o(e.source,n,t);E[i.methodName]&&E[i.methodName](i)}}),t.invokeAPI=function(e,t){var n=new r(c,e,t);return d&&_.then(function(){N&&N.postMessage(n.getPayload(),u),s.addPending(n)}),n};var P=null;t.addEventListener=function(e,n){P||(P=t.invokeAPI(a.SYS_EVENT,{})),P.addEventListener(e,n)},t.removeEventListener=function(e,t){P&&P.removeEventListener(e,t)}},182:function(e,t,n){"use strict";var r=function(){this.pendingMsgs={}};r.prototype.addPending=function(e){this.pendingMsgs[e.id]=e;var t=function(){delete this.pendingMsgs[e.id],e.removeEventListener("_finish",t)}.bind(this);e.addEventListener("_finish",t)},r.prototype.getMsyById=function(e){return this.pendingMsgs[e]},e.exports=r},183:function(e,t,n){"use strict";var r=n(574),o=n(573),i=0,a=Math.floor(1e3*Math.random()),s=function(){return 1e3*(1e3*a+Math.floor(1e3*Math.random()))+ ++i%1e3},d={code:408,reason:"timeout"},u={TIMEOUT:"_timeout",FINISH:"_finish"},c={timeout:-1},l=function(e,t,n,r){this.id=s(),this.methodName=t,this.containerId=e,this.option=o({},c,r);var n=n||{};this._p={},this.result=new Promise(function(e,t){this._p._resolve=e,this._p._reject=t}.bind(this)),this.callbacks={},this.plainMsg=this._handleMsg(n),this._eventsHandle={},this._timeoutTimer=null,this._initTimeout(),this.isFinish=!1};l.prototype._initTimeout=function(){this._clearTimeout(),this.option.timeout>0&&(this._timeoutTimer=setTimeout(function(){this.receiveEvent(u.TIMEOUT),this.receiveResponse(d,!0)}.bind(this),this.option.timeout))},l.prototype._clearTimeout=function(){clearTimeout(this._timeoutTimer)},l.prototype._handleMsg=function(e){var t={};return Object.keys(e).forEach(function(n){var o=e[n];"function"==typeof o&&"on"===n.slice(0,2)?this.callbacks[n]=o:t[n]=r(o)}.bind(this)),t},l.prototype.getPayload=function(){return{msgId:this.id,containerId:this.containerId,methodName:this.methodName,body:this.plainMsg,type:"request"}},l.prototype.receiveEvent=function(e,t){if(this.isFinish&&e!==u.FINISH)return!1;e!==u.FINISH&&e!==u.TIMEOUT&&this._initTimeout(),Array.isArray(this._eventsHandle[e])&&this._eventsHandle[e].forEach(function(e){try{e(t)}catch(e){console.error(t)}});var n="on"+e.charAt(0).toUpperCase()+e.slice(1);return this.callbacks[n]&&this.callbacks[n](t),!0},l.prototype.addEventListener=function(e,t){if(!e||"function"!=typeof t)throw"eventName is null or handle is not a function, addEventListener fail";Array.isArray(this._eventsHandle[e])||(this._eventsHandle[e]=[]),this._eventsHandle[e].push(t)},l.prototype.removeEventListener=function(e,t){if(!e||!t)throw"eventName is null or handle is null, invoke removeEventListener fail";if(Array.isArray(this._eventsHandle[e])){var n=this._eventsHandle[e].indexOf(t);-1!==n&&this._eventsHandle[e].splice(n,1)}},l.prototype.receiveResponse=function(e,t){if(!0===this.isFinish)return!1;this._clearTimeout();var t=!!t;return t?this._p._reject(e):this._p._resolve(e),setTimeout(function(){this.receiveEvent(u.FINISH)}.bind(this),0),this.isFinish=!0,!0},e.exports=l},184:function(e,t,n){"use strict";var r=function(e,t,n){if(this._msgId=n.msgId,this.frameWindow=e,this.methodName=n.methodName,this.clientOrigin=t,this.containerId=n.containerId,this.params=n.body,!this._msgId)throw"msgId not exist";if(!this.frameWindow)throw"frameWindow not exist";if(!this.methodName)throw"methodName not exits";if(!this.clientOrigin)throw"clientOrigin not exist";this.hasResponded=!1};r.prototype.respond=function(e,t){var t=!!t;if(!0!==this.hasResponded){var n={type:"response",success:!t,body:e,msgId:this._msgId};this.frameWindow.postMessage(n,this.clientOrigin),this.hasResponded=!0}},r.prototype.emit=function(e,t){var n={type:"event",eventName:e,body:t,msgId:this._msgId};this.frameWindow.postMessage(n,this.clientOrigin)},e.exports=r},185:function(e,t,n){"use strict";e.exports={SYS_EVENT:"SYS_openAPIContainerInitEvent",SYS_INIT:"SYS_openAPIContainerInit"}},4:function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},572:function(e,t,n){(function(e,n){function r(e,t){return e.set(t[0],t[1]),e}function o(e,t){return e.add(t),e}function i(e,t){for(var n=-1,r=e.length;++n-1}function g(e,t){var n=this.__data__,r=W(n,e);return r<0?n.push([e,t]):n[r][1]=t,this}function I(e){var t=-1,n=e?e.length:0;for(this.clear();++t-1&&e%1==0&&e-1&&e%1==0&&e<=Ve}function ke(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function be(e){return!!e&&"object"==typeof e}function ge(e){return!!ke(e)&&(he(e)||c(e)?Pt:tt).test(_e(e))}function Ie(e){return"string"==typeof e||!Lt(e)&&be(e)&&Nt.call(e)==xe}function ye(e){var t=pe(e);if(!t&&!Pe(e))return z(e);var n=le(e),r=!!n,o=n||[],i=o.length;for(var a in e)!B(e,a)||r&&("length"==a||fe(a,i))||t&&"constructor"==a||o.push(a);return o}var Ae=200,Se="__lodash_hash_undefined__",Ve=9007199254740991,Ue="[object Arguments]",Oe="[object Boolean]",je="[object Date]",$e="[object Function]",we="[object GeneratorFunction]",De="[object Map]",Ce="[object Number]",Te="[object Object]",We="[object RegExp]",Re="[object Set]",xe="[object String]",Fe="[object Symbol]",Le="[object ArrayBuffer]",Be="[object DataView]",ze="[object Float32Array]",qe="[object Float64Array]",Ye="[object Int8Array]",Je="[object Int16Array]",Ge="[object Int32Array]",He="[object Uint8Array]",Xe="[object Uint8ClampedArray]",Ke="[object Uint16Array]",Qe="[object Uint32Array]",Ze=/[\\^$.*+?()[\]{}|]/g,et=/\w*$/,tt=/^\[object .+?Constructor\]$/,nt=/^(?:0|[1-9]\d*)$/,rt={};rt[Ue]=rt["[object Array]"]=rt[Le]=rt[Be]=rt[Oe]=rt[je]=rt[ze]=rt[qe]=rt[Ye]=rt[Je]=rt[Ge]=rt[De]=rt[Ce]=rt[Te]=rt[We]=rt[Re]=rt[xe]=rt[Fe]=rt[He]=rt[Xe]=rt[Ke]=rt[Qe]=!0,rt["[object Error]"]=rt[$e]=rt["[object WeakMap]"]=!1;var ot={function:!0,object:!0},it=ot[typeof t]&&t&&!t.nodeType?t:void 0,at=ot[typeof e]&&e&&!e.nodeType?e:void 0,st=at&&at.exports===it?it:void 0,dt=u(it&&at&&"object"==typeof n&&n),ut=u(ot[typeof self]&&self),ct=u(ot[typeof window]&&window),lt=u(ot[typeof this]&&this),ft=dt||ct!==(lt&<.window)&&ct||ut||lt||Function("return this")(),vt=Array.prototype,pt=Object.prototype,_t=Function.prototype.toString,Et=pt.hasOwnProperty,Nt=pt.toString,Pt=RegExp("^"+_t.call(Et).replace(Ze,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Mt=st?ft.Buffer:void 0,ht=ft.Symbol,mt=ft.Uint8Array,kt=Object.getOwnPropertySymbols,bt=Object.create,gt=pt.propertyIsEnumerable,It=vt.splice,yt=Object.getPrototypeOf,At=Object.keys,St=oe(ft,"DataView"),Vt=oe(ft,"Map"),Ut=oe(ft,"Promise"),Ot=oe(ft,"Set"),jt=oe(ft,"WeakMap"),$t=oe(Object,"create"),wt=_e(St),Dt=_e(Vt),Ct=_e(Ut),Tt=_e(Ot),Wt=_e(jt),Rt=ht?ht.prototype:void 0,xt=Rt?Rt.valueOf:void 0;v.prototype.clear=p,v.prototype.delete=_,v.prototype.get=E,v.prototype.has=N,v.prototype.set=P,M.prototype.clear=h,M.prototype.delete=m,M.prototype.get=k,M.prototype.has=b,M.prototype.set=g,I.prototype.clear=y,I.prototype.delete=A,I.prototype.get=S,I.prototype.has=V,I.prototype.set=U,O.prototype.clear=j,O.prototype.delete=$,O.prototype.get=w,O.prototype.has=D,O.prototype.set=C;var Ft=function(e){return function(e){return null==e?void 0:e.length}}();kt||(ae=function(){return[]}),(St&&se(new St(new ArrayBuffer(1)))!=Be||Vt&&se(new Vt)!=De||Ut&&"[object Promise]"!=se(Ut.resolve())||Ot&&se(new Ot)!=Re||jt&&"[object WeakMap]"!=se(new jt))&&(se=function(e){var t=Nt.call(e),n=t==Te?e.constructor:void 0,r=n?_e(n):void 0;if(r)switch(r){case wt:return Be;case Dt:return De;case Ct:return"[object Promise]";case Tt:return Re;case Wt:return"[object WeakMap]"}return t});var Lt=Array.isArray,Bt=Mt?function(e){return e instanceof Mt}:function(e){return function(){return!1}}();e.exports=x}).call(t,n(577)(e),n(4))},573:function(e,t,n){function r(e,t,n){var r=e[t];h.call(e,t)&&d(r,n)&&(void 0!==n||t in e)||(e[t]=n)}function o(e,t,n,o){n||(n={});for(var i=-1,a=t.length;++i-1&&e%1==0&&e-1&&e%1==0&&e<=_}function f(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var v=n(575),p=n(576),_=9007199254740991,E="[object Function]",N="[object GeneratorFunction]",P=/^(?:0|[1-9]\d*)$/,M=Object.prototype,h=M.hasOwnProperty,m=M.toString,k=M.propertyIsEnumerable,b=!k.call({valueOf:1},"valueOf"),g=function(e){return function(e){return null==e?void 0:e.length}}(),I=function(e){return p(function(t,n){var r=-1,o=n.length,i=o>1?n[o-1]:void 0,s=o>2?n[2]:void 0;for(i=e.length>3&&"function"==typeof i?(o--,i):void 0,s&&a(n[0],n[1],s)&&(i=o<3?void 0:i,o=1),t=Object(t);++r-1&&e%1==0&&e-1&&e%1==0&&e<=_}function f(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function v(e){return!!e&&"object"==typeof e}function p(e){return d(e)?r(e):o(e)}var _=9007199254740991,E="[object Arguments]",N="[object Function]",P="[object GeneratorFunction]",M=/^(?:0|[1-9]\d*)$/,h=Object.prototype,m=h.hasOwnProperty,k=h.toString,b=h.propertyIsEnumerable,g=function(e,t){return function(n){return e(t(n))}}(Object.keys,Object),I=Array.isArray;e.exports=p},576:function(e,t){function n(e,t,n){switch(n.length){case 0:return e.call(t);case 1:return e.call(t,n[0]);case 2:return e.call(t,n[0],n[1]);case 3:return e.call(t,n[0],n[1],n[2])}return e.apply(t,n)}function r(e,t){return t=b(void 0===t?e.length-1:t,0),function(){for(var r=arguments,o=-1,i=b(r.length-t,0),a=Array(i);++o0;)o=a.shift(),i=s.shift();return n?(i||0)>=(o||0):(i||0)>(o||0)},t.language=o.language,t.version=o.version},function(e,t,n){"use strict";function r(e,t,n){var r="Web"===n.platform,i="iOS"===n.platform,a="android"===n.platform,s=a||i,d=function(){return r?window.navigator.userAgent.toLowerCase():""}(),u=function(){var e={};if(r){var t=window.name;try{var n=JSON.parse(t);e.containerId=n.containerId,e.version=n.hostVersion,e.language=n.language||"*"}catch(e){}}return e}(),c=function(){return s?"DingTalk"===n.appName||"com.alibaba.android.rimet"===n.appName:d.indexOf("dingtalk")>-1||!!u.containerId}(),l=function(){if(r){if(u.version)return u.version;var e=d.match(/aliapp\(\w+\/([a-zA-Z0-9.-]+)\)/);null===e&&(e=d.match(/dingtalk\/([a-zA-Z0-9.-]+)/));return e&&e[1]||"Unknown"}return n.appVersion}(),f=!!u.containerId,v=/iphone|ipod|ios/.test(d),p=/ipad/.test(d),_=d.indexOf("android")>-1,E=d.indexOf("mac")>-1&&f,N=d.indexOf("win")>-1&&f,P=!E&&!N&&f,M=f,h="";return h=c?v||i?o.PLATFORM.IOS:_||a?o.PLATFORM.ANDROID:p?o.PLATFORM.IPAD:E?o.PLATFORM.MAC:N?o.PLATFORM.WINDOWS:P?o.PLATFORM.BROWSER:o.PLATFORM.UNKNOWN:o.PLATFORM.UNKNOWN,{isDingTalk:c,isWebiOS:v,isWebAndroid:_,isWeexiOS:i,isWeexAndroid:a,isDingTalkPCMac:E,isDingTalkPCWeb:P,isDingTalkPCWindows:N,isDingTalkPC:M,runtime:e,framework:t,platform:h,version:l,isWeex:s}}Object.defineProperty(t,"__esModule",{value:!0});var o=n(11);t.default=r},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(184),o=n(182),i=n(11),a=r.default().split("."),s=a[0],d=a[1],u=function(){var e={};switch(d){case i.FRAMEWORK.VUE:var t=weex.config,n=t.env;e.platform=n.platform,i.RUNTIME.WEEX===s&&(e.appVersion=n.appVersion,e.appName=n.appName);break;case i.FRAMEWORK.RAX:i.RUNTIME.WEEX===s&&(e.platform=navigator.platform,e.appName=navigator.appName,e.appVersion=navigator.appVersion);break;case i.FRAMEWORK.UNKNOWN:i.RUNTIME.WEB===s&&(e.platform=i.RUNTIME.WEB),i.RUNTIME.UNKNOWN===s&&(e.platform=i.RUNTIME.UNKNOWN)}return e}(),c=o.default(s,d,u);t.default=c},function(e,t,n){"use strict";function r(e,t){for(var n=e.length,r=0,o=!0;ro[i])return!0}return!0}Object.defineProperty(t,"__esModule",{value:!0}),t.isFunction=r,t.compareVersion=o;(function(e){e.cancel="-1",e.not_exist="1",e.no_permission="7",e.jsapi_internal_error="22"})(t.ERROR_CODE||(t.ERROR_CODE={}));(function(e){e.pc="pc",e.android="android",e.ios="ios",e.notInDingTalk="notInDingTalk"})(t.ENV_ENUM||(t.ENV_ENUM={}));(function(e){e.mac="mac",e.win="win",e.noSub="noSub"})(t.ENV_ENUM_SUB||(t.ENV_ENUM_SUB={}));(function(e){e.WEB="WEB",e.MINI_APP="MINI_APP",e.WEEX="WEEX",e.WEBVIEW_IN_MINIAPP="WEBVIEW_IN_MINIAPP",e.WEEX_WIDGET="WEEX_WIDGET"})(t.APP_TYPE||(t.APP_TYPE={}));(function(e){e[e.INFO=1]="INFO",e[e.WARNING=2]="WARNING",e[e.ERROR=3]="ERROR"})(t.LogLevel||(t.LogLevel={}))},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(0),o=n(2),i=n(3),a=n(5),s=n(9),d=n(176),u=n(6),c=n(8),l=n(10);r.ddSdk.setPlatform({platform:o.ENV_ENUM.android,bridgeInit:function(){var e=o.getENV();return e.appType===i.APP_TYPE.MINI_APP?Promise.resolve(a.default):e.appType===i.APP_TYPE.WEBVIEW_IN_MINIAPP?Promise.resolve(s.default):e.appType===i.APP_TYPE.WEEX?u.androidWeexBridge():d.h5AndroidbridgeInit().then(function(){return d.default})},authMethod:"runtime.permission.requestJsApis",event:{on:function(e,t){var n=o.getENV();switch(n.appType){case i.APP_TYPE.WEB:case i.APP_TYPE.WEBVIEW_IN_MINIAPP:c.on(e,t);break;case i.APP_TYPE.WEEX:l.on(e,t);break;default:throw new Error("Not support global event in the platfrom: "+n.appType)}},off:function(e,t){var n=o.getENV();switch(n.appType){case i.APP_TYPE.WEB:case i.APP_TYPE.WEBVIEW_IN_MINIAPP:c.off(e,t);break;case i.APP_TYPE.WEEX:l.off(e,t);break;default:throw new Error("Not support global event in the platfrom: "+n.appType)}}}})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(193),n(190),n(192)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(0),o=n(2),i=n(3),a=n(5),s=n(9),d=n(177),u=n(6),c=n(8),l=n(10);r.ddSdk.setPlatform({platform:o.ENV_ENUM.ios,bridgeInit:function(){var e=o.getENV();return e.appType===i.APP_TYPE.MINI_APP?Promise.resolve(a.default):e.appType===i.APP_TYPE.WEBVIEW_IN_MINIAPP?Promise.resolve(s.default):e.appType===i.APP_TYPE.WEEX?u.iosWeexBridge():d.h5IosBridgeInit().then(function(){return d.default})},authMethod:"runtime.permission.requestJsApis",event:{on:function(e,t){var n=o.getENV();switch(n.appType){case i.APP_TYPE.WEB:case i.APP_TYPE.WEBVIEW_IN_MINIAPP:c.on(e,t);break;case i.APP_TYPE.WEEX:l.on(e,t);break;default:throw new Error("Not support global event in the platfrom: "+n.appType)}},off:function(e,t){var n=o.getENV();switch(n.appType){case i.APP_TYPE.WEB:case i.APP_TYPE.WEBVIEW_IN_MINIAPP:c.off(e,t);break;case i.APP_TYPE.WEEX:l.off(e,t);break;default:throw new Error("Not support global event in the platfrom: "+n.appType)}}}})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(0),o=n(2),i=n(178),a=n(5),s=n(3),d=n(179);r.ddSdk.setPlatform({platform:o.ENV_ENUM.pc,bridgeInit:function(){switch(o.getENV().appType){case s.APP_TYPE.MINI_APP:return Promise.resolve(a.default);default:return i.h5PcBridgeInit().then(function(){return i.default})}},authMethod:"config",authParamsDeal:function(e){var t=Object.assign({},e);return t.url=window.location.href.split("#")[0],t},event:{on:function(e,t){if(o.getENV().appType===s.APP_TYPE.WEB)return d.on(e,t)},off:function(e,t){if(o.getENV().appType===s.APP_TYPE.WEB)return d.off(e,t)}}})},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function o(e){if(c===setTimeout)return setTimeout(e,0);if((c===n||!c)&&setTimeout)return c=setTimeout,setTimeout(e,0);try{return c(e,0)}catch(t){try{return c.call(null,e,0)}catch(t){return c.call(this,e,0)}}}function i(e){if(l===clearTimeout)return clearTimeout(e);if((l===r||!l)&&clearTimeout)return l=clearTimeout,clearTimeout(e);try{return l(e)}catch(t){try{return l.call(null,e)}catch(t){return l.call(this,e)}}}function a(){_&&v&&(_=!1,v.length?p=v.concat(p):E=-1,p.length&&s())}function s(){if(!_){var e=o(a);_=!0;for(var t=p.length;t;){for(v=p,p=[];++E1)for(var n=1;n=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n(196),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(t,n(7))},,function(e,t,n){"use strict";var r=n(175),o=n(665),i=Object.assign(r,o.apiObj);e.exports=i},,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(12),o=n(13),i=n(14),a=n(15),s=n(16),d=n(17),u=n(18),c=n(19),l=n(20),f=n(21),v=n(22),p=n(23),_=n(24),E=n(25),N=n(26),P=n(27),M=n(28),h=n(29),m=n(30),k=n(31),b=n(32),g=n(33),I=n(34),y=n(35),A=n(36),S=n(37),V=n(38),U=n(39),O=n(40),j=n(41),$=n(42),w=n(43),D=n(44),C=n(45),T=n(46),W=n(47),R=n(48),x=n(49),F=n(50),L=n(51),B=n(52),z=n(53),q=n(54),Y=n(55),J=n(56),G=n(57),H=n(58),X=n(59),K=n(60),Q=n(61),Z=n(62),ee=n(63),te=n(64),ne=n(65),re=n(66),oe=n(67),ie=n(68),ae=n(69),se=n(70),de=n(71),ue=n(72),ce=n(73),le=n(74),fe=n(75),ve=n(76),pe=n(77),_e=n(78),Ee=n(79),Ne=n(80),Pe=n(81),Me=n(82),he=n(83),me=n(84),ke=n(85),be=n(86),ge=n(87),Ie=n(88),ye=n(89),Ae=n(90),Se=n(91),Ve=n(92),Ue=n(93),Oe=n(94),je=n(95),$e=n(96),we=n(97),De=n(98),Ce=n(99),Te=n(100),We=n(101),Re=n(102),xe=n(103),Fe=n(104),Le=n(105),Be=n(106),ze=n(107),qe=n(108),Ye=n(109),Je=n(110),Ge=n(111),He=n(112),Xe=n(113),Ke=n(114),Qe=n(115),Ze=n(116),et=n(117),tt=n(118),nt=n(119),rt=n(120),ot=n(121),it=n(122),at=n(123),st=n(124),dt=n(125),ut=n(126),ct=n(127),lt=n(128),ft=n(129),vt=n(130),pt=n(131),_t=n(132),Et=n(133),Nt=n(134),Pt=n(135),Mt=n(136),ht=n(137),mt=n(138),kt=n(139),bt=n(140),gt=n(141),It=n(142),yt=n(143),At=n(144),St=n(145),Vt=n(146),Ut=n(147),Ot=n(148),jt=n(149),$t=n(150),wt=n(151),Dt=n(152),Ct=n(153),Tt=n(154),Wt=n(155),Rt=n(156),xt=n(157),Ft=n(158),Lt=n(159),Bt=n(160),zt=n(161),qt=n(162),Yt=n(163),Jt=n(164),Gt=n(165),Ht=n(166),Xt=n(167),Kt=n(168),Qt=n(169),Zt=n(170),en=n(171),tn=n(172),nn=n(173);t.apiObj={biz:{ATMBle:{beaconPicker:r.beaconPicker$,faceManager:o.faceManager$,punchModePicker:i.punchModePicker$},alipay:{pay:a.pay$},calendar:{chooseDateTime:s.chooseDateTime$,chooseHalfDay:d.chooseHalfDay$,chooseInterval:u.chooseInterval$,chooseOneDay:c.chooseOneDay$},chat:{chooseConversationByCorpId:l.chooseConversationByCorpId$,collectSticker:f.collectSticker$,createSceneGroup:v.createSceneGroup$,getRealmCid:p.getRealmCid$,locationChatMessage:_.locationChatMessage$,openSingleChat:E.openSingleChat$,pickConversation:N.pickConversation$,sendEmotion:P.sendEmotion$,toConversation:M.toConversation$},clipboardData:{setData:h.setData$},conference:{videoConfCall:m.videoConfCall$},contact:{choose:k.choose$,chooseMobileContacts:b.chooseMobileContacts$,complexPicker:g.complexPicker$,createGroup:I.createGroup$,departmentsPicker:y.departmentsPicker$,externalComplexPicker:A.externalComplexPicker$,externalEditForm:S.externalEditForm$,setRule:V.setRule$},cspace:{chooseSpaceDir:U.chooseSpaceDir$,delete:O.delete$,preview:j.preview$,saveFile:$.saveFile$},customContact:{choose:w.choose$,multipleChoose:D.multipleChoose$},ding:{create:C.create$,post:T.post$},event:{notifyWeex:W.notifyWeex$},intent:{fetchData:R.fetchData$},iot:{bind:x.bind$,bindMeetingRoom:F.bindMeetingRoom$,getDeviceProperties:L.getDeviceProperties$,invokeThingService:B.invokeThingService$,queryMeetingRoomList:z.queryMeetingRoomList$,setDeviceProperties:q.setDeviceProperties$,unbind:Y.unbind$},map:{locate:J.locate$,search:G.search$,view:H.view$},media:{compressVideo:X.compressVideo$},microApp:{openApp:K.openApp$},navigation:{close:Q.close$,goBack:Z.goBack$,hideBar:ee.hideBar$,quit:te.quit$,replace:ne.replace$,setIcon:re.setIcon$,setLeft:oe.setLeft$,setMenu:ie.setMenu$,setRight:ae.setRight$,setTitle:se.setTitle$},realm:{subscribe:de.subscribe$,unsubscribe:ue.unsubscribe$},shortCut:{addShortCut:ce.addShortCut$},store:{closeUnpayOrder:le.closeUnpayOrder$,createOrder:fe.createOrder$,getPayUrl:ve.getPayUrl$,inquiry:pe.inquiry$},telephone:{call:_e.call$,checkBizCall:Ee.checkBizCall$,quickCallList:Ne.quickCallList$,showCallMenu:Pe.showCallMenu$},user:{checkPassword:Me.checkPassword$,get:he.get$},util:{chosen:me.chosen$,datepicker:ke.datepicker$,datetimepicker:be.datetimepicker$,decrypt:ge.decrypt$,downloadFile:Ie.downloadFile$,encrypt:ye.encrypt$,isLocalFileExist:Ae.isLocalFileExist$,multiSelect:Se.multiSelect$,open:Ve.open$,openLink:Ue.openLink$,openLocalFile:Oe.openLocalFile$,openModal:je.openModal$,openSlidePanel:$e.openSlidePanel$,presentWindow:we.presentWindow$,previewImage:De.previewImage$,previewVideo:Ce.previewVideo$,scan:Te.scan$,scanCard:We.scanCard$,setScreenBrightnessAndKeepOn:Re.setScreenBrightnessAndKeepOn$,share:xe.share$,startDocSign:Fe.startDocSign$,systemShare:Le.systemShare$,timepicker:Be.timepicker$,uploadAttachment:ze.uploadAttachment$,uploadImage:qe.uploadImage$,uploadImageFromCamera:Ye.uploadImageFromCamera$,ut:Je.ut$},verify:{openBindIDCard:Ge.openBindIDCard$,startAuth:He.startAuth$}},channel:{permission:{requestAuthCode:Xe.requestAuthCode$}},device:{accelerometer:{clearShake:Ke.clearShake$,watchShake:Qe.watchShake$},audio:{download:Ze.download$,onPlayEnd:et.onPlayEnd$,onRecordEnd:tt.onRecordEnd$,pause:nt.pause$,play:rt.play$,resume:ot.resume$,startRecord:it.startRecord$,stop:at.stop$,stopRecord:st.stopRecord$,translateVoice:dt.translateVoice$},base:{getInterface:ut.getInterface$,getPhoneInfo:ct.getPhoneInfo$,getUUID:lt.getUUID$,getWifiStatus:ft.getWifiStatus$},connection:{getNetworkType:vt.getNetworkType$},geolocation:{checkPermission:pt.checkPermission$,get:_t.get$,start:Et.start$,status:Nt.status$,stop:Pt.stop$},launcher:{checkInstalledApps:Mt.checkInstalledApps$,launchApp:ht.launchApp$},nfc:{nfcRead:mt.nfcRead$,nfcStop:kt.nfcStop$,nfcWrite:bt.nfcWrite$},notification:{actionSheet:gt.actionSheet$,alert:It.alert$,confirm:yt.confirm$,extendModal:At.extendModal$,hidePreloader:St.hidePreloader$,modal:Vt.modal$,prompt:Ut.prompt$,showPreloader:Ot.showPreloader$,toast:jt.toast$,vibrate:$t.vibrate$},screen:{insetAdjust:wt.insetAdjust$,resetView:Dt.resetView$,rotateView:Ct.rotateView$}},net:{bjGovApn:{loginGovNet:Tt.loginGovNet$}},runtime:{message:{fetch:Wt.fetch$,post:Rt.post$},permission:{requestAuthCode:xt.requestAuthCode$,requestOperateAuthCode:Ft.requestOperateAuthCode$}},ui:{input:{plain:Lt.plain$},nav:{close:Bt.close$,getCurrentId:zt.getCurrentId$,go:qt.go$,preload:Yt.preload$,recycle:Jt.recycle$},progressBar:{setColors:Gt.setColors$},pullToRefresh:{disable:Ht.disable$,enable:Xt.enable$,stop:Kt.stop$},webViewBounce:{disable:Qt.disable$,enable:Zt.enable$}},util:{domainStorage:{getItem:en.getItem$,removeItem:tn.removeItem$,setItem:nn.setItem$}}}},,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,function(e,t,n){e.exports=n(199)}])}); \ No newline at end of file