| package com.doumee.core.dingTalk; | 
|   | 
| import com.alibaba.fastjson.JSONObject; | 
| import com.aliyun.dingtalkoauth2_1_0.Client; | 
| import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest; | 
| import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse; | 
| import com.aliyun.dingtalktodo_1_0.models.*; | 
| import com.aliyun.tea.TeaException; | 
| import com.aliyun.teautil.models.RuntimeOptions; | 
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | 
| import com.dingtalk.api.DefaultDingTalkClient; | 
| import com.dingtalk.api.DingTalkClient; | 
| import com.dingtalk.api.request.*; | 
| import com.dingtalk.api.response.*; | 
| import com.doumee.biz.system.SystemDictDataBiz; | 
| import com.doumee.core.constants.ResponseStatus; | 
| import com.doumee.core.exception.BusinessException; | 
| import com.doumee.core.utils.Constants; | 
| import com.doumee.core.utils.DateUtil; | 
| import com.doumee.dao.business.dao.CompanyMapper; | 
| import com.doumee.dao.business.model.CarUseBook; | 
| import com.doumee.dao.business.model.Company; | 
| import com.doumee.dao.business.model.HiddenDanger; | 
| import com.doumee.dao.business.model.Visits; | 
| import com.doumee.dao.system.model.SystemDictData; | 
| import com.doumee.service.business.CompanyService; | 
| import com.github.xiaoymin.knife4j.core.util.CollectionUtils; | 
| import com.taobao.api.ApiException; | 
| import lombok.extern.slf4j.Slf4j; | 
| import org.apache.commons.lang.StringUtils; | 
| import org.springframework.beans.factory.annotation.Autowired; | 
| import org.springframework.stereotype.Service; | 
|   | 
| import java.text.DateFormat; | 
| import java.util.*; | 
| import java.util.stream.Collectors; | 
|   | 
| /** | 
|  * Created by IntelliJ IDEA. | 
|  * | 
|  * @Author : Rk | 
|  * @create 2025/9/24 16:25 | 
|  */ | 
| @Slf4j | 
| @Service | 
| public class DingTalk { | 
|   | 
|     @Autowired | 
|     private SystemDictDataBiz systemDictDataBiz; | 
|   | 
|     @Autowired | 
|     private CompanyMapper companyMapper; | 
|   | 
|     /** | 
|      * 使用 Token 初始化账号Client 数据同步类 | 
|      * @return Client com.aliyun.dingtalkoauth2_1_0. | 
|      * @throws Exception | 
|      */ | 
|     public static Client createClient() throws Exception { | 
|         com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config(); | 
|         config.protocol = "https"; | 
|         config.regionId = "central"; | 
|         return new Client(config); | 
|     } | 
|   | 
|     /** | 
|      * 待办通知类 链接池 | 
|      * @return | 
|      * @throws Exception | 
|      */ | 
|     public static com.aliyun.dingtalktodo_1_0.Client createV1Client() throws Exception { | 
|         com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config(); | 
|         config.protocol = "https"; | 
|         config.regionId = "central"; | 
|         return new com.aliyun.dingtalktodo_1_0.Client(config); | 
|     } | 
|   | 
|     public void updTokenInfo() throws Exception { | 
|         String appKey  =  systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.APP_KEY).getCode(); | 
|         String appSecret  = systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.APP_SECRET).getCode(); | 
|         Client client = DingTalk.createClient(); | 
|         GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest() | 
|                 .setAppKey(appKey) | 
|                 .setAppSecret(appSecret); | 
|         try { | 
|             GetAccessTokenResponse getAccessTokenResponse = client.getAccessToken(getAccessTokenRequest); | 
|             //返参描述 例:{"body":{"accessToken":"76a248ea72ba3f359b39c9e70073d642","expireIn":7200},"headers":{"access-control-allow-origin":"*","date":"Wed, 24 Sep 2025 08:39:36 GMT","server":"DingTalk/1.0.0","transfer-encoding":"chunked","x-acs-request-id":"9E8AF053-04DD-7031-9766-14DFFB087A79","access-control-allow-headers":"X-Requested-With, X-Sequence, _aop_secret, _aop_signature, x-acs-dingtalk-access-token","connection":"keep-alive","content-type":"application/json;charset=utf-8","access-control-expose-headers":"*","x-acs-trace-id":"96e7cf1f3c0e059779a6d581d4b5fca7"},"statusCode":200} | 
|             if(Constants.equalsInteger(getAccessTokenResponse.statusCode,Constants.DD_STATUS_SUCCESS_CODE)){ | 
|                 //解析token信息 存储 | 
|                 String accessToken = getAccessTokenResponse.getBody().getAccessToken(); | 
|                 //更新token信息存储 | 
|                 SystemDictData systemDictData = systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.ACCESS_TOKEN); | 
|                 systemDictData.setCode(accessToken); | 
|                 systemDictData.setUpdateTime(new Date()); | 
|                 systemDictDataBiz.updateByIdNew(systemDictData); | 
|             } | 
|   | 
|             //更新Token信息 | 
|             System.out.println(JSONObject.toJSONString(getAccessTokenResponse)); | 
|   | 
|         } catch (TeaException err) { | 
|             if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { | 
|                 // err 中含有 code 和 message 属性,可帮助开发定位问题 | 
|                 log.error("更新钉钉Token失败:{}" + err.message); | 
|             } | 
|   | 
|         } catch (Exception _err) { | 
|             TeaException err = new TeaException(_err.getMessage(), _err); | 
|             if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { | 
|                 // err 中含有 code 和 message 属性,可帮助开发定位问题 | 
|                 log.error("更新钉钉Token失败:{}" + err.message); | 
|             } | 
|         } | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 获取钉钉Token | 
|      * @return | 
|      */ | 
|     public String getToken(){ | 
|         String accessToken  =  systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.ACCESS_TOKEN).getCode(); | 
|         return accessToken; | 
|     } | 
|   | 
|   | 
|     public OapiV2UserGetuserinfoResponse.UserGetByCodeResponse  getDDUserByCode(String code) throws ApiException { | 
|         DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo"); | 
|         OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest(); | 
|         req.setCode(code); | 
|         OapiV2UserGetuserinfoResponse rsp = client.execute(req, getToken()); | 
|         if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ | 
|            return  rsp.getResult(); | 
|         }else{ | 
|             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); | 
|         } | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 全量同步 部门信息 | 
|      * 接口文档地址 https://open.dingtalk.com/document/orgapp/obtain-the-department-list-v2 | 
|      * 本接口只支持获取当前部门的下一级部门基础信息,不支持获取当前部门下所有层级子部门 | 
|      * @throws ApiException | 
|      */ | 
|     public List<OapiV2DepartmentGetResponse.DeptGetResponse>  syncAllDDDepartmentList() throws ApiException { | 
|         DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub"); | 
|         List<Long> headList = new ArrayList<>(); | 
|         headList.add(1L); | 
|         List<OapiV2DepartmentListsubResponse.DeptBaseResponse> deptBaseResponseList = new ArrayList<>(); | 
|         List<OapiV2DepartmentListsubResponse.DeptBaseResponse> thisLevelList = getDepartmentList(client,headList); | 
|         deptBaseResponseList.addAll(thisLevelList); | 
|         while (CollectionUtils.isNotEmpty(thisLevelList)){ | 
|             headList = thisLevelList.stream().map(i->i.getDeptId()).collect(Collectors.toList()); | 
|             thisLevelList = getDepartmentList(client,headList); | 
|             if(CollectionUtils.isNotEmpty(thisLevelList)){ | 
|                 deptBaseResponseList.addAll(thisLevelList); | 
|             } | 
|         } | 
|         List<OapiV2DepartmentGetResponse.DeptGetResponse> getResponseList = new ArrayList<>(); | 
|         if(CollectionUtils.isNotEmpty(deptBaseResponseList)){ | 
|             for (OapiV2DepartmentListsubResponse.DeptBaseResponse deptBaseResponse:deptBaseResponseList) { | 
|                 OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse = syncDepartmentInfo(deptBaseResponse.getDeptId()); | 
|                 getResponseList.add(deptGetResponse); | 
|             } | 
|         } | 
|         return getResponseList; | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 获取部门下级数据 | 
|      * @param client | 
|      * @param deptIdList | 
|      * @return | 
|      * @throws ApiException | 
|      */ | 
|     public List<OapiV2DepartmentListsubResponse.DeptBaseResponse> getDepartmentList | 
|             (DingTalkClient client, List<Long> deptIdList) throws ApiException{ | 
|         List<OapiV2DepartmentListsubResponse.DeptBaseResponse> thisLevelList = new ArrayList<>(); | 
|         for (Long deptId:deptIdList) { | 
|             OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest(); | 
|             req.setDeptId(deptId); | 
|             req.setLanguage("zh_CN"); | 
|             OapiV2DepartmentListsubResponse rsp = client.execute(req, this.getToken()); | 
|             if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ | 
|                 if(CollectionUtils.isNotEmpty(rsp.getResult())){ | 
|                     thisLevelList.addAll(rsp.getResult()); | 
|                 } | 
|             }else{ | 
|                 throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); | 
|             } | 
|         } | 
|         return thisLevelList; | 
|     } | 
|   | 
|     /** | 
|      * 创建组织部门 暂不使用 | 
|      * 接口文档地址:https://open.dingtalk.com/document/orgapp/create-a-department-v2 | 
|      * @param ddParentId 钉钉上级部门主键 如果没有则入null | 
|      * @param name 部门名称 | 
|      * @param sn 序号 | 
|      * @param id 系统部门主键 | 
|      * @throws ApiException | 
|      */ | 
|     public void pushCreatDepartment(Integer ddParentId,String name,Long sn,Integer id) throws ApiException { | 
|         DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/create"); | 
|         OapiV2DepartmentCreateRequest req = new OapiV2DepartmentCreateRequest(); | 
|         //必入参数 | 
|         //如果无父级 则默认跟组织 1L | 
|         req.setParentId(Objects.isNull(ddParentId)?1L:ddParentId); | 
|         req.setName(name); | 
|         req.setOrder(sn); | 
|         //外部部门字段 | 
|         req.setSourceIdentifier(id.toString()); | 
|   | 
|         //默认参数 | 
|         req.setHideDept(false); | 
|         req.setOuterDept(false); | 
|         req.setCreateDeptGroup(false); | 
|   | 
|         OapiV2DepartmentCreateResponse rsp = client.execute(req, getToken()); | 
|         if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ | 
|   | 
|         }else{ | 
|             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); | 
|         } | 
|   | 
|         System.out.println(rsp.getBody()); | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 更新组织部门 暂不使用 | 
|      * 接口文档地址:https://open.dingtalk.com/document/orgapp/update-a-department-v2 | 
|      * @param deptId 钉钉部门主键 | 
|      * @param name 部门名称 | 
|      * @param parentId 父级钉钉部门主键 | 
|      * @param sn 序号 | 
|      * @throws ApiException | 
|      */ | 
|     public void pushUpdDepartment(Integer deptId,String name,Integer parentId,Long sn) throws ApiException { | 
|         DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/update"); | 
|         OapiV2DepartmentUpdateRequest req = new OapiV2DepartmentUpdateRequest(); | 
|         req.setDeptId(deptId.longValue()); | 
|         //如果无父级 则默认跟组织 1L | 
|         req.setParentId(Objects.isNull(parentId)?1L:parentId.longValue()); | 
|         req.setOrder(sn); | 
|         req.setName(name); | 
|         OapiV2DepartmentUpdateResponse rsp = client.execute(req, getToken()); | 
|         if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ | 
|   | 
|         }else{ | 
|             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); | 
|         } | 
|     } | 
|   | 
|   | 
|   | 
|     /** | 
|      * 删除组织部门 暂不使用 | 
|      * 接口文档地址:https://open.dingtalk.com/document/orgapp/delete-a-department-v2 | 
|      * @param deptId 钉钉部门主键 | 
|      * @throws ApiException | 
|      */ | 
|     public void pushDelDepartment(Integer deptId) throws ApiException { | 
|         DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/delete"); | 
|         OapiV2DepartmentDeleteRequest req = new OapiV2DepartmentDeleteRequest(); | 
|         req.setDeptId(deptId.longValue()); | 
|         OapiV2DepartmentDeleteResponse rsp = client.execute(req, getToken()); | 
|         System.out.println(rsp.getBody()); | 
|         if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ | 
|   | 
|         }else{ | 
|             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); | 
|         } | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 获取钉钉部门详情 | 
|      * @param deptId | 
|      * @return | 
|      * @throws ApiException | 
|      */ | 
|     public OapiV2DepartmentGetResponse.DeptGetResponse syncDepartmentInfo(Long deptId) throws ApiException { | 
|         DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/get"); | 
|         OapiV2DepartmentGetRequest req = new OapiV2DepartmentGetRequest(); | 
|         req.setDeptId(deptId); | 
|         req.setLanguage("zh_CN"); | 
|         OapiV2DepartmentGetResponse rsp = client.execute(req, getToken()); | 
|         System.out.println(rsp.getBody()); | 
|         if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ | 
|             return rsp.getResult(); | 
|         }else{ | 
|             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); | 
|         } | 
|     } | 
|   | 
|   | 
|   | 
|   | 
|     public List<OapiV2UserGetResponse.UserGetResponse>  syncAllUserInfo() throws ApiException { | 
|         List<Company> deptList = companyMapper.selectList(new QueryWrapper<Company>().lambda() | 
|                 .eq(Company::getIsdeleted,Constants.ZERO) | 
|                 .eq(Company::getType,Constants.ONE) | 
|                 .isNotNull(Company::getErpId) | 
|         ); | 
|         if(CollectionUtils.isEmpty(deptList)){ | 
|             return null; | 
|         } | 
|         List<String> allUserIdList = new ArrayList<>(); | 
|         DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/listid"); | 
|         OapiUserListidRequest req = new OapiUserListidRequest(); | 
|         for (Company company:deptList) { | 
|             req.setDeptId(Long.valueOf(company.getErpId())); | 
|             OapiUserListidResponse rsp = client.execute(req, getToken()); | 
|             if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ | 
|                 if(CollectionUtils.isNotEmpty(rsp.getResult().getUseridList())){ | 
|                     allUserIdList.addAll(rsp.getResult().getUseridList()); | 
|                 } | 
|             }else{ | 
|                 throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); | 
|             } | 
|         } | 
|         if(CollectionUtils.isEmpty(allUserIdList)){ | 
|             return null; | 
|         } | 
|         Set<String> setUserIdList = new HashSet<>(allUserIdList); | 
|         return syncUserInfoList(setUserIdList); | 
|     } | 
|   | 
|   | 
|     public List<OapiV2UserGetResponse.UserGetResponse>  syncUserInfoList(Set<String> setUserIdList) throws ApiException { | 
|         List<OapiV2UserGetResponse.UserGetResponse> userList = new ArrayList<>(); | 
|         DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get"); | 
|         OapiV2UserGetRequest req = new OapiV2UserGetRequest(); | 
|         for (String userId:setUserIdList) { | 
|             req.setUserid(userId); | 
|             req.setLanguage("zh_CN"); | 
|             OapiV2UserGetResponse rsp = client.execute(req, getToken()); | 
|             if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ | 
|                 OapiV2UserGetResponse.UserGetResponse userGetResponse = rsp.getResult(); | 
|                 userList.add(userGetResponse); | 
|             }else{ | 
|                 throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); | 
|             } | 
|         } | 
|         return userList; | 
|     } | 
|   | 
|   | 
|     public OapiV2UserGetResponse.UserGetResponse syncUserInfo(String userId)throws ApiException { | 
|         DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get"); | 
|         OapiV2UserGetRequest req = new OapiV2UserGetRequest(); | 
|         req.setUserid(userId); | 
|         req.setLanguage("zh_CN"); | 
|         OapiV2UserGetResponse rsp = client.execute(req, getToken()); | 
|         if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ | 
|             OapiV2UserGetResponse.UserGetResponse userGetResponse = rsp.getResult(); | 
|             return userGetResponse; | 
|         }else{ | 
|             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); | 
|         } | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 发送 工作通知 | 
|      * @param agentId | 
|      * @param userIds | 
|      * @param msg | 
|      * api 地址 https://open.dingtalk.com/document/orgapp/asynchronous-sending-of-enterprise-session-messages | 
|      * @throws ApiException | 
|      */ | 
|     public Boolean workInfoOANotice(Long agentId,String userIds,OapiMessageCorpconversationAsyncsendV2Request.Msg msg){ | 
|         try{ | 
|             if(CollectionUtils.isEmpty(msg)){ | 
|                 return null; | 
|             } | 
|             DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"); | 
|             OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request(); | 
|             request.setAgentId(agentId); | 
|             request.setUseridList(userIds); | 
|             request.setToAllUser(false); | 
|   | 
|             request.setMsg(msg); | 
|             OapiMessageCorpconversationAsyncsendV2Response rsp = client.execute(request, getToken()); | 
|             if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ | 
|                 return true; | 
|             }else{ | 
|                 throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); | 
|             } | 
|         }catch (ApiException apiException){ | 
|   | 
|         } | 
|         return false; | 
|   | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 访客申请/报备 OA 工作通知 内容 | 
|      * @param visits | 
|      * @param title | 
|      * @return | 
|      */ | 
|     public OapiMessageCorpconversationAsyncsendV2Request.Msg getVisitNoticeMsg(Visits visits,String title){ | 
|         OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); | 
|         msg.setMsgtype("oa"); | 
|         OapiMessageCorpconversationAsyncsendV2Request.OA oa = new OapiMessageCorpconversationAsyncsendV2Request.OA(); | 
|         oa.setMessageUrl(""); | 
|         OapiMessageCorpconversationAsyncsendV2Request.Head head = new OapiMessageCorpconversationAsyncsendV2Request.Head(); | 
|         head.setText(title); | 
|         head.setBgcolor("#279BAA"); | 
|         oa.setHead(head); | 
|   | 
|         OapiMessageCorpconversationAsyncsendV2Request.Body body = new OapiMessageCorpconversationAsyncsendV2Request.Body(); | 
|         body.setTitle(!Constants.equalsInteger(visits.getType(),Constants.TWO)?visits.getName()+"的访客申请":"的访客报备"); | 
|         List<OapiMessageCorpconversationAsyncsendV2Request.Form> formList = new ArrayList<>(); | 
|   | 
|         OapiMessageCorpconversationAsyncsendV2Request.Form visitUser = new OapiMessageCorpconversationAsyncsendV2Request.Form(); | 
|         visitUser.setKey("来访人:"); | 
|         visitUser.setValue(visits.getName()); | 
|         formList.add(visitUser); | 
|   | 
|         OapiMessageCorpconversationAsyncsendV2Request.Form inDate = new OapiMessageCorpconversationAsyncsendV2Request.Form(); | 
|         inDate.setKey("入园时间:"); | 
|         inDate.setValue(DateUtil.formatDate(visits.getStarttime(),"MM-dd HH:mm")); | 
|         formList.add(inDate); | 
|   | 
|         OapiMessageCorpconversationAsyncsendV2Request.Form outDate = new OapiMessageCorpconversationAsyncsendV2Request.Form(); | 
|         outDate.setKey("离园时间:"); | 
|         outDate.setValue(DateUtil.formatDate(visits.getEndtime(),"MM-dd HH:mm")); | 
|         formList.add(outDate); | 
|   | 
|         OapiMessageCorpconversationAsyncsendV2Request.Form inReason = new OapiMessageCorpconversationAsyncsendV2Request.Form(); | 
|         inReason.setKey("来访事由:"); | 
|         inReason.setValue(visits.getReason()); | 
|         formList.add(inReason); | 
|   | 
|         if(StringUtils.isNotBlank(visits.getCarNos())){ | 
|             OapiMessageCorpconversationAsyncsendV2Request.Form carNos = new OapiMessageCorpconversationAsyncsendV2Request.Form(); | 
|             carNos.setKey("随访车辆:"); | 
|             carNos.setValue(visits.getCarNos()); | 
|             formList.add(visitUser); | 
|         } | 
|   | 
|         body.setForm(formList); | 
|         oa.setBody(body); | 
|         msg.setOa(oa); | 
|         return msg; | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 用车信息 钉钉通知数据组合 | 
|      * @param carUseBook | 
|      * @param title | 
|      * @return | 
|      */ | 
|     public OapiMessageCorpconversationAsyncsendV2Request.Msg getCarUseNoticeMsg(CarUseBook carUseBook,String title){ | 
|         OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); | 
|         msg.setMsgtype("oa"); | 
|         OapiMessageCorpconversationAsyncsendV2Request.OA oa = new OapiMessageCorpconversationAsyncsendV2Request.OA(); | 
|         oa.setMessageUrl(""); | 
|         OapiMessageCorpconversationAsyncsendV2Request.Head head = new OapiMessageCorpconversationAsyncsendV2Request.Head(); | 
|         head.setText(title); | 
|         head.setBgcolor("#279BAA"); | 
|         oa.setHead(head); | 
|   | 
|         OapiMessageCorpconversationAsyncsendV2Request.Body body = new OapiMessageCorpconversationAsyncsendV2Request.Body(); | 
|         body.setTitle("公务用车"); | 
|         List<OapiMessageCorpconversationAsyncsendV2Request.Form> formList = new ArrayList<>(); | 
|   | 
|   | 
|         OapiMessageCorpconversationAsyncsendV2Request.Form startDate = new OapiMessageCorpconversationAsyncsendV2Request.Form(); | 
|         startDate.setKey("开始时间:"); | 
|         startDate.setValue(DateUtil.formatDate(carUseBook.getStartTime(),"MM-dd HH:mm")); | 
|         formList.add(startDate); | 
|   | 
|         OapiMessageCorpconversationAsyncsendV2Request.Form endDate = new OapiMessageCorpconversationAsyncsendV2Request.Form(); | 
|         endDate.setKey("结束时间:"); | 
|         endDate.setValue(DateUtil.formatDate(carUseBook.getEndTime(),"MM-dd HH:mm")); | 
|         formList.add(endDate); | 
|   | 
|         OapiMessageCorpconversationAsyncsendV2Request.Form userNum = new OapiMessageCorpconversationAsyncsendV2Request.Form(); | 
|         userNum.setKey("乘车人数:"); | 
|         userNum.setValue(StringUtils.isBlank(carUseBook.getMemberNames())?"0人": (carUseBook.getMemberNames().split(",").length+"人")); | 
|         formList.add(userNum); | 
|   | 
|         OapiMessageCorpconversationAsyncsendV2Request.Form inReason = new OapiMessageCorpconversationAsyncsendV2Request.Form(); | 
|         inReason.setKey("用车地点:"); | 
|         inReason.setValue(Constants.equalsInteger(carUseBook.getType(),Constants.ZERO)?"市内":"市外"); | 
|         formList.add(inReason); | 
|   | 
|         body.setForm(formList); | 
|         oa.setBody(body); | 
|         msg.setOa(oa); | 
|         return msg; | 
|     } | 
|   | 
|     /** | 
|      * 天气 markdown | 
|      * @param title | 
|      * @param text | 
|      * @return | 
|      */ | 
|     public OapiMessageCorpconversationAsyncsendV2Request.Msg getWeatherNoticeMsg(String title,String text){ | 
|         OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); | 
|         msg.setMsgtype("markdown"); | 
|         OapiMessageCorpconversationAsyncsendV2Request.Markdown markdown = new OapiMessageCorpconversationAsyncsendV2Request.Markdown(); | 
|         markdown.setTitle(title); | 
|         markdown.setText(text); | 
|         msg.setMarkdown(markdown); | 
|         return msg; | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 安防/消防 markdown | 
|      * @param hiddenDanger | 
|      * @return | 
|      */ | 
|     public OapiMessageCorpconversationAsyncsendV2Request.Msg getAlarmNoticeMsg(String areaName,String submitTime,String infoType){ | 
|         OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); | 
|         msg.setMsgtype("markdown"); | 
|         OapiMessageCorpconversationAsyncsendV2Request.Markdown markdown = new OapiMessageCorpconversationAsyncsendV2Request.Markdown(); | 
|         markdown.setTitle("园区存在安防/消防隐患"); | 
|         markdown.setText(areaName+"在"+submitTime+"发生"+infoType+",请及时前往安防中心/消防中心进行处理"); | 
|         msg.setMarkdown(markdown); | 
|         return msg; | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 钉钉待办事件 | 
|      * api地址 https://open.dingtalk.com/document/orgapp/add-dingtalk-to-do-task | 
|      * unionId 通知所属用户 | 
|      * title 标题 | 
|      * unionIdList 待办通知人员集合 | 
|      * @throws Exception | 
|      */ | 
|     public String toDoNotice(String title,List<String> unionIdList,List<CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList> fieldList,String url) { | 
|         try{ | 
|             if(CollectionUtils.isEmpty(fieldList)){ | 
|                 return null; | 
|             } | 
|             com.aliyun.dingtalktodo_1_0.Client client = DingTalk.createV1Client(); | 
|             CreateTodoTaskHeaders createTodoTaskHeaders = new CreateTodoTaskHeaders(); | 
|             createTodoTaskHeaders.xAcsDingtalkAccessToken = getToken(); | 
|             //待办截止前的提醒 | 
|             CreateTodoTaskRequest.CreateTodoTaskRequestRemindNotifyConfigs remindNotifyConfigs = new CreateTodoTaskRequest.CreateTodoTaskRequestRemindNotifyConfigs() | 
|                     .setDingNotify("1") | 
|                     .setSendTodoApn("true"); | 
|             //待办通知配置 | 
|             CreateTodoTaskRequest.CreateTodoTaskRequestNotifyConfigs notifyConfigs = new CreateTodoTaskRequest.CreateTodoTaskRequestNotifyConfigs() | 
|                     .setDingNotify("1") | 
|                     .setSendTodoApn("true") | 
|                     .setSendAssistantChat("true"); | 
|             //按钮事件 | 
|             CreateTodoTaskRequest.CreateTodoTaskRequestActionListParam actionList0Param = new CreateTodoTaskRequest.CreateTodoTaskRequestActionListParam() | 
|                     .setBody(""); | 
|             CreateTodoTaskRequest.CreateTodoTaskRequestActionList actionList0 = new CreateTodoTaskRequest.CreateTodoTaskRequestActionList() | 
|                     .setTitle("去处理") | 
|                     .setActionType(2) | 
|                     .setParam(actionList0Param) | 
|                     .setUrl(url) //TODO 详情地址 | 
|                     .setActionKey("ak-1-1"); | 
|             //详情页url跳转地址 | 
|             CreateTodoTaskRequest.CreateTodoTaskRequestDetailUrl detailUrl = new CreateTodoTaskRequest.CreateTodoTaskRequestDetailUrl() | 
|                     .setAppUrl("https://www.baidu.com") | 
|                     .setPcUrl("https://www.baidu.com"); | 
|             CreateTodoTaskRequest createTodoTaskRequest = new CreateTodoTaskRequest() | 
|                     .setSubject(title) | 
|                     .setCreatorId(unionIdList.get(Constants.ZERO)) | 
|                     .setDescription(title) | 
|                     .setExecutorIds(unionIdList) | 
|                     .setDetailUrl(detailUrl) | 
|                     .setContentFieldList(fieldList) | 
|                     .setIsOnlyShowExecutor(true) | 
|                     .setPriority(20) | 
|                     .setNotifyConfigs(notifyConfigs) | 
|                     .setActionList(java.util.Arrays.asList(actionList0)) | 
|                     .setTodoType("TODO") | 
|                     .setRemindNotifyConfigs(remindNotifyConfigs); | 
|             try { | 
|                 CreateTodoTaskResponse response = client.createTodoTaskWithOptions(unionIdList.get(Constants.ZERO), createTodoTaskRequest, createTodoTaskHeaders, new com.aliyun.teautil.models.RuntimeOptions()); | 
|                 log.error("待办通知发送成功,发送内容:{}"+JSONObject.toJSONString(response)); | 
|                 return response.getBody().getId(); | 
|             } catch (TeaException err) { | 
|                 if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { | 
|                     log.error("待办通知发送失败,失败原因:{}"+err.message); | 
|                 } | 
|             } catch (Exception _err) { | 
|                 TeaException err = new TeaException(_err.getMessage(), _err); | 
|                 if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { | 
|                     // err 中含有 code 和 message 属性,可帮助开发定位问题 | 
|                     log.error("待办通知发送失败,失败原因:{}"+err.message); | 
|                 } | 
|             } | 
|             return null; | 
|         }catch (Exception e){ | 
|             throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"钉钉待办任务通知发送失败"); | 
|         } | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 处理全部人的待办信息 (流程审批完成、本级审批完成 使用) | 
|      * @param unionId | 
|      * @param taskId | 
|      * api地址 https://open.dingtalk.com/document/orgapp/updates-dingtalk-to-do-tasks | 
|      * @throws Exception | 
|      */ | 
|     public void updToDoNoticeInfoStatus(String unionId,String taskId){ | 
|         try { | 
|             com.aliyun.dingtalktodo_1_0.Client client = DingTalk.createV1Client(); | 
|             UpdateTodoTaskHeaders updateTodoTaskHeaders = new UpdateTodoTaskHeaders(); | 
|             updateTodoTaskHeaders.xAcsDingtalkAccessToken = getToken(); | 
|             UpdateTodoTaskRequest updateTodoTaskRequest = new UpdateTodoTaskRequest() | 
|                     .setOperatorId(unionId) | 
|                     .setDone(true); | 
|             UpdateTodoTaskResponse response = client.updateTodoTaskWithOptions(unionId, taskId, updateTodoTaskRequest, updateTodoTaskHeaders, new RuntimeOptions()); | 
|             log.error("待办通知发送成功,发送内容:{}"+JSONObject.toJSONString(response)); | 
|         } catch (TeaException err) { | 
|             if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { | 
|                 // err 中含有 code 和 message 属性,可帮助开发定位问题 | 
|                 log.error("待办通知发送失败,失败原因:{}"+err.message); | 
|             } | 
|         } catch (Exception _err) { | 
|             TeaException err = new TeaException(_err.getMessage(), _err); | 
|             if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { | 
|                 // err 中含有 code 和 message 属性,可帮助开发定位问题 | 
|                 log.error("待办通知发送失败,失败原因:{}"+err.message); | 
|             } | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 处理对应人员的待办信息 | 
|      * @param unionId 创建人unionId | 
|      * @param taskId  钉钉任务主键 | 
|      * @param dealUnionId | 
|      * api 地址 https://open.dingtalk.com/document/orgapp/update-dingtalk-to-do-status | 
|      * @throws Exception | 
|      */ | 
|     public void updUserToDoNoticeInfoStatus(String unionId,String taskId,String dealUnionId){ | 
|         try { | 
|             com.aliyun.dingtalktodo_1_0.Client client = DingTalk.createV1Client(); | 
|             UpdateTodoTaskExecutorStatusHeaders updateTodoTaskExecutorStatusHeaders = new UpdateTodoTaskExecutorStatusHeaders(); | 
|             updateTodoTaskExecutorStatusHeaders.xAcsDingtalkAccessToken = getToken(); | 
|             UpdateTodoTaskExecutorStatusRequest.UpdateTodoTaskExecutorStatusRequestExecutorStatusList executorStatusList0 = new UpdateTodoTaskExecutorStatusRequest.UpdateTodoTaskExecutorStatusRequestExecutorStatusList() | 
|                     .setId(dealUnionId) | 
|                     .setIsDone(true); | 
|             UpdateTodoTaskExecutorStatusRequest updateTodoTaskExecutorStatusRequest = new UpdateTodoTaskExecutorStatusRequest() | 
|                     .setExecutorStatusList(java.util.Arrays.asList( | 
|                             executorStatusList0 | 
|                     )); | 
|             UpdateTodoTaskExecutorStatusResponse response = client.updateTodoTaskExecutorStatusWithOptions(unionId, taskId, updateTodoTaskExecutorStatusRequest, updateTodoTaskExecutorStatusHeaders, new RuntimeOptions()); | 
|             log.error("待办通知发送成功,发送内容:{}"+JSONObject.toJSONString(response)); | 
|         } catch (TeaException err) { | 
|             if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { | 
|                 // err 中含有 code 和 message 属性,可帮助开发定位问题 | 
|                 log.error("待办通知发送失败,失败原因:{}"+err.message); | 
|             } | 
|   | 
|         } catch (Exception _err) { | 
|             TeaException err = new TeaException(_err.getMessage(), _err); | 
|             if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { | 
|                 // err 中含有 code 和 message 属性,可帮助开发定位问题 | 
|                 log.error("待办通知发送失败,失败原因:{}"+err.message); | 
|             } | 
|         } | 
|   | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 访客报备与访客申请 钉钉待办 | 
|      * @param visits | 
|      * @return | 
|      */ | 
|     public List<CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList> getToDoVisitFiledInfo(Visits visits){ | 
|         List<CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList> list = new ArrayList<>(); | 
|         CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList contentFieldList0 = new CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList() | 
|                 .setFieldKey("来访人") | 
|                 .setFieldValue(visits.getName()); | 
|         list.add(contentFieldList0); | 
|         CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList contentFieldList1 = new CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList() | 
|                 .setFieldKey("入园时间") | 
|                 .setFieldValue(DateUtil.getFomartDate(visits.getStarttime(),"MM-dd HH:mm")); | 
|         list.add(contentFieldList1); | 
|         CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList contentFieldList2 = new CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList() | 
|                 .setFieldKey("离园时间") | 
|                 .setFieldValue(DateUtil.getFomartDate(visits.getEndtime(),"MM-dd HH:mm")); | 
|         list.add(contentFieldList2); | 
|         CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList contentFieldList3 = new CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList() | 
|                 .setFieldKey("来访事由") | 
|                 .setFieldValue(visits.getReason()); | 
|         list.add(contentFieldList3); | 
|         if(StringUtils.isNotBlank(visits.getCarNos())){ | 
|             CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList contentFieldList4 = new CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList() | 
|                     .setFieldKey("随访车辆") | 
|                     .setFieldValue(visits.getCarNos()); | 
|             list.add(contentFieldList4); | 
|         } | 
|         return list; | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 用车申请的 钉钉待办 | 
|      * @param carUseBook | 
|      * @return | 
|      */ | 
|     public List<CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList> getToDoCarUseBookFiledInfo(CarUseBook carUseBook){ | 
|         List<CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList> list = new ArrayList<>(); | 
|         CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList contentFieldList1 = new CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList() | 
|                 .setFieldKey("开始时间") | 
|                 .setFieldValue(DateUtil.getFomartDate(carUseBook.getStartTime(),"MM-dd HH:mm")); | 
|         list.add(contentFieldList1); | 
|         CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList contentFieldList2 = new CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList() | 
|                 .setFieldKey("结束时间") | 
|                 .setFieldValue(DateUtil.getFomartDate(carUseBook.getEndTime(),"MM-dd HH:mm")); | 
|         list.add(contentFieldList2); | 
|         CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList contentFieldList3 = new CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList() | 
|                 .setFieldKey("乘车人数") | 
|                 .setFieldValue(StringUtils.isBlank(carUseBook.getMemberNames())?"0人": (carUseBook.getMemberNames().split(",").length+"人")); | 
|         list.add(contentFieldList3); | 
|         CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList contentFieldList4 = new CreateTodoTaskRequest.CreateTodoTaskRequestContentFieldList() | 
|                 .setFieldKey("用车地点") | 
|                 .setFieldValue(Constants.equalsInteger(carUseBook.getType(),Constants.ZERO)?"市内":"市外"); | 
|         list.add(contentFieldList4); | 
|         return list; | 
|     } | 
|   | 
|   | 
|     public static void main(String[] args) throws Exception { | 
|         DingTalk dingTalk = new DingTalk(); | 
| //        Visits visits = new Visits(); | 
| //        visits.setName("小豆丁"); | 
| //        visits.setStarttime(new Date()); | 
| //        visits.setEndtime(new Date()); | 
| //        visits.setReason("参观"); | 
| //        visits.setCarNos("皖A00001"); | 
| //        dingTalk.toDoNotice("visit_01","小豆丁的访客申请",java.util.Arrays.asList("iPsP86axviPHiSP4nm5YgQNCQiEiE") ,dingTalk.getToDoVisitFiledInfo(visits)); | 
|   | 
|         CarUseBook carUseBook = new CarUseBook(); | 
|         carUseBook.setStartTime(new Date()); | 
|         carUseBook.setEndTime(new Date()); | 
|         carUseBook.setMemberNames("张三,李四,王五"); | 
|         carUseBook.setType(Constants.ZERO); | 
|   | 
|   | 
| //        dingTalk.workInfoOANotice(4015267031L,"1568490244651036",dingTalk.getCarUseNoticeMsg(carUseBook,"用车申请")); | 
|   | 
|   | 
|         dingTalk.toDoNotice("小豆丁提交的公务车用车",java.util.Arrays.asList("iPsP86axviPHiSP4nm5YgQNCQiEiE","XiPYJKRAv9eCoO4UPM20HQQiEiE","eWbHiSp3uRtrMtiiOX5LXamgiEiE") ,dingTalk.getToDoCarUseBookFiledInfo(carUseBook),""); | 
| // | 
|   | 
| //        dingTalk.updUserToDoNoticeInfoStatus("iPsP86axviPHiSP4nm5YgQNCQiEiE", | 
| //                "taska2d004da1f8e84847c895d14e8695102", | 
| //                "XiPYJKRAv9eCoO4UPM20HQQiEiE"); | 
|         ; | 
| //        String appKey  = "dingkfglaktqmfd2dmo2";//systemDictDataBiz.queryByCode("","").getCode(); | 
| //        String appSecret  = "0e22TT2s794Yj49Exgvq8nU2ulpXmxlw9ThBh5s-vDv5Cfspv-f8HPmta4cg2evk";//systemDictDataBiz.queryByCode("","").getCode(); | 
| //        Client client = DingTalk.createClient(); | 
| //        GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest() | 
| //                .setAppKey(appKey) | 
| //                .setAppSecret(appSecret); | 
| //        try { | 
| //            GetAccessTokenResponse getAccessTokenResponse = client.getAccessToken(getAccessTokenRequest); | 
| // | 
| //            //更新Token信息 | 
| //            System.out.println(JSONObject.toJSONString(getAccessTokenResponse)); | 
| // | 
| //        } catch (TeaException err) { | 
| //            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { | 
| //                // err 中含有 code 和 message 属性,可帮助开发定位问题 | 
| //                log.error("更新钉钉Token失败:{}" + err.message); | 
| //            } | 
| // | 
| //        } catch (Exception _err) { | 
| //            TeaException err = new TeaException(_err.getMessage(), _err); | 
| //            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { | 
| //                // err 中含有 code 和 message 属性,可帮助开发定位问题 | 
| //                log.error("更新钉钉Token失败:{}" + err.message); | 
| //            } | 
| //        } | 
|     } | 
|   | 
| } |