From dd4cd96c69061da3ff80cbfb87237b16cda8abc3 Mon Sep 17 00:00:00 2001
From: doum <doum>
Date: 星期五, 26 九月 2025 18:48:06 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/wuhuyancao' into wuhuyancao

---
 server/system_service/src/main/java/com/doumee/core/utils/Constants.java                             |    6 
 server/system_service/pom.xml                                                                        |    7 
 server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalkStream.java             |   96 +++++
 server/visits/dmvisit_admin/src/main/java/com/doumee/api/business/CompanyController.java             |    3 
 server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java  |  248 +++++++++++++
 server/visits/dmvisit_service/src/main/java/com/doumee/service/business/CompanyService.java          |    7 
 server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/CompanyServiceImpl.java |  312 +++++++++++++++++
 server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/CompanyCloudController.java         |   10 
 server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalk.java                   |  369 ++++++++++++++++++++
 9 files changed, 1,049 insertions(+), 9 deletions(-)

diff --git a/server/system_service/pom.xml b/server/system_service/pom.xml
index 9ac1dbf..daab417 100644
--- a/server/system_service/pom.xml
+++ b/server/system_service/pom.xml
@@ -137,7 +137,12 @@
         <dependency>
             <groupId>com.aliyun</groupId>
             <artifactId>dingtalk</artifactId>
-            <version>1.3.54</version>
+            <version>2.2.25</version>
+        </dependency>
+        <dependency>
+            <groupId>com.dingtalk.open</groupId>
+            <artifactId>app-stream-client</artifactId>
+            <version>1.3.7</version>
         </dependency>
         <dependency>
             <groupId>com.aliyun</groupId>
diff --git a/server/system_service/src/main/java/com/doumee/core/utils/Constants.java b/server/system_service/src/main/java/com/doumee/core/utils/Constants.java
index 900156a..55d1824 100644
--- a/server/system_service/src/main/java/com/doumee/core/utils/Constants.java
+++ b/server/system_service/src/main/java/com/doumee/core/utils/Constants.java
@@ -26,6 +26,8 @@
     public static final int ZERO = 0 ;
     public static final int ONE = 1 ;
     public static final int TWO = 2 ;
+    public static final Integer DD_STATUS_SUCCESS_CODE = 200 ;
+    public static final Long DD_ERR_CODE = 0L ;
     public static final String HK_PARAM ="HK_PARAM" ;
     public static final String HK_WEBSITE_DOMAIN_URL ="HK_WEBSITE_DOMAIN_URL" ;
     public static final String LED_CONTENT_SPEED ="LED_CONTENT_SPEED" ;
@@ -493,6 +495,10 @@
 
 
     public static final String HOME_IMAGE ="HOME_IMAGE";
+    public static final String DD_TALK ="DD_TALK";
+    public static final String APP_KEY ="APP_KEY";
+    public static final String APP_SECRET ="APP_SECRET";
+    public static final String ACCESS_TOKEN ="ACCESS_TOKEN";
 
 
 
diff --git a/server/visits/dmvisit_admin/src/main/java/com/doumee/api/business/CompanyController.java b/server/visits/dmvisit_admin/src/main/java/com/doumee/api/business/CompanyController.java
index 1bcbdc1..1dc6847 100644
--- a/server/visits/dmvisit_admin/src/main/java/com/doumee/api/business/CompanyController.java
+++ b/server/visits/dmvisit_admin/src/main/java/com/doumee/api/business/CompanyController.java
@@ -13,6 +13,7 @@
 import com.doumee.service.business.CompanyService;
 import com.doumee.service.business.ext.ERPSyncService;
 import com.doumee.service.business.impl.hksync.fhk.HkSyncOrgUserFromHKServiceImpl;
+import com.taobao.api.ApiException;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
@@ -163,8 +164,6 @@
     public ApiResponse<List<CompanyDTO>> findCompanyTreePage(Integer type){
         return ApiResponse.success(companyService.findCompanyTreePage(type));
     }
-
-
 
     @ApiOperation("鍏ㄩ噺閮ㄩ棬淇℃伅鍚屾")
     @PostMapping("/syncAll")
diff --git a/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/CompanyCloudController.java b/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/CompanyCloudController.java
index 5db61f1..d4cb723 100644
--- a/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/CompanyCloudController.java
+++ b/server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/CompanyCloudController.java
@@ -16,7 +16,9 @@
 import com.doumee.service.business.ext.ERPSyncService;
 import com.doumee.service.business.impl.hksync.fhk.HkSyncOrgUserFromHKServiceImpl;
 import com.doumee.service.business.impl.hksync.fhk.HkSyncOrgUserFromSelfServiceImpl;
+import com.taobao.api.ApiException;
 import io.swagger.annotations.*;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -176,6 +178,14 @@
         return ApiResponse.success(companyService.findCompanyTreePage(type));
     }
 
+    @ApiOperation("鍏ㄩ噺閮ㄩ棬淇℃伅鍚屾 - 閽夐拤")
+    @PostMapping("/syncAllDingding")
+//    @CloudRequiredPermission("business:company:sync")
+    public ApiResponse syncAllDingding() throws ApiException {
+        companyService.syncDDCompany();
+        return ApiResponse.success("鍚屾鎴愬姛");
+    }
+
 
 
     @ApiOperation("鍏ㄩ噺閮ㄩ棬淇℃伅鍚屾")
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalk.java b/server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalk.java
new file mode 100644
index 0000000..05bda56
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalk.java
@@ -0,0 +1,369 @@
+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.tea.TeaException;
+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.dao.business.dao.CompanyMapper;
+import com.doumee.dao.business.model.Company;
+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.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+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 鍒濆鍖栬处鍙稢lient
+     * @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);
+    }
+
+
+    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)){
+                //瑙f瀽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;
+    }
+
+
+    /**
+     * 鍏ㄩ噺鍚屾 閮ㄩ棬淇℃伅
+     * 鎺ュ彛鏂囨。鍦板潃 https://open.dingtalk.com/document/orgapp/obtain-the-department-list-v2
+     * 鏈帴鍙e彧鏀寔鑾峰彇褰撳墠閮ㄩ棬鐨勪笅涓�绾ч儴闂ㄥ熀纭�淇℃伅锛屼笉鏀寔鑾峰彇褰撳墠閮ㄩ棬涓嬫墍鏈夊眰绾у瓙閮ㄩ棬
+     * @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;
+    }
+
+
+
+    /**
+     * 鍒涘缓缁勭粐閮ㄩ棬 鏆備笉浣跨敤
+     * 鎺ュ彛鏂囨。鍦板潃锛歨ttps://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());
+    }
+
+
+    /**
+     * 鏇存柊缁勭粐閮ㄩ棬 鏆備笉浣跨敤
+     * 鎺ュ彛鏂囨。鍦板潃锛歨ttps://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());
+        }
+    }
+
+
+
+    /**
+     * 鍒犻櫎缁勭粐閮ㄩ棬 鏆備笉浣跨敤
+     * 鎺ュ彛鏂囨。鍦板潃锛歨ttps://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());
+        }
+    }
+
+
+    public static void main(String[] args) throws Exception {
+        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);
+            }
+        }
+    }
+
+
+
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalkStream.java b/server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalkStream.java
new file mode 100644
index 0000000..474b586
--- /dev/null
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalkStream.java
@@ -0,0 +1,96 @@
+package com.doumee.core.dingTalk;
+
+import com.dingtalk.open.app.api.GenericEventListener;
+import com.dingtalk.open.app.api.OpenDingTalkStreamClientBuilder;
+import com.dingtalk.open.app.api.message.GenericOpenDingTalkEvent;
+import com.dingtalk.open.app.api.security.AuthClientCredential;
+import com.dingtalk.open.app.stream.protocol.event.EventAckStatus;
+import com.doumee.biz.system.SystemDictDataBiz;
+import com.doumee.core.utils.Constants;
+import com.doumee.dao.business.dao.CompanyMapper;
+import com.doumee.dao.business.dao.MemberMapper;
+import com.doumee.service.business.CompanyService;
+import com.doumee.service.business.MemberService;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.mp.config.WxMpConfigStorage;
+import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import shade.com.alibaba.fastjson2.JSONObject;
+
+/**
+ * 閽夐拤 璁㈤槄浜嬩欢閫氱煡
+ *
+ * @Author : Rk
+ * @create 2025/9/24 17:14
+ */
+@Slf4j
+@Configuration
+public class DingTalkStream {
+
+    @Autowired
+    private SystemDictDataBiz systemDictDataBiz;
+
+    @Autowired
+    private MemberService memberService;
+
+    @Autowired
+    private CompanyService companyService;
+
+
+    @Bean
+    public void DingTalkStreamRun()  throws Exception {
+        String appKey  =  systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.APP_KEY).getCode();
+        String appSecret  = systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.APP_SECRET).getCode();
+
+        OpenDingTalkStreamClientBuilder
+                .custom()
+                .credential(new AuthClientCredential(appKey, appSecret))
+                //娉ㄥ唽浜嬩欢鐩戝惉
+                .registerAllEventListener(new GenericEventListener() {
+                    @Override
+                    public EventAckStatus onEvent(GenericOpenDingTalkEvent event) {
+                        try {
+                            //浜嬩欢鍞竴Id
+                            String eventId = event.getEventId();
+                            log.error("閽夐拤鎺ㄩ�佷簨浠禝d:{}"+eventId);
+                            //浜嬩欢绫诲瀷
+                            String eventType = event.getEventType();
+                            log.error("閽夐拤鎺ㄩ�佷簨浠剁被鍨�:{}"+eventType);
+                            // org_dept_create 閮ㄩ棬鏂板缓 {"timeStamp":"1758783935796","eventId":"0c779adba04143958a3960e8e36bbce5","deptId":[1040735458]}
+                            // org_dept_modify 閮ㄩ棬淇敼 {"timeStamp":"1758785791639","eventId":"6c2d8c7a61a7419e8928fda3effb3bf4","deptId":[1040735458]}
+                            // org_dept_remove 閮ㄩ棬鍒犻櫎 {"timeStamp":"1758785817760","eventId":"47e289f334e041719ed354052da474de","deptId":[1040735458]}
+
+                            // user_add_org 鍛樺伐娣诲姞
+                            // user_modify_org 鍛樺伐淇敼  {"timeStamp":"1758786235842","diffInfo":[{"prev":{"extFields":"{}","hiredDate":"2022-03-30","name":"浠诲悍","telephone":"145","remark":"","workPlace":"鑾茶姳绉戝垱鍥� F401","jobNumber":"","email":"rk@doumee.com"},"curr":{"extFields":"{}","hiredDate":"2022-03-30","name":"浠诲悍","telephone":"145","remark":"","workPlace":"鑾茶姳绉戝垱鍥� F401","jobNumber":"","email":"rk@doumee.com"},"userid":"1568490244651036"}],"eventId":"e54d8991aed14c669e22e460459433f6","optStaffId":"045831294126209983","userId":["1568490244651036"]}
+                            // user_leave_org 鍛樺伐鍒犻櫎
+
+                            //浜嬩欢浜х敓鏃堕棿
+                            Long bornTime = event.getEventBornTime();
+                            log.error("閽夐拤鎺ㄩ�佷簨浠朵骇鐢熸椂闂�:{}"+bornTime);
+                            //鑾峰彇浜嬩欢浣�
+                            JSONObject bizData = event.getData();
+                            log.error("閽夐拤鎺ㄩ�佷簨浠惰鎯�:{}"+bizData);
+
+                            if(eventType.startsWith("org")){
+                                companyService.ddPushCompanyInfo(eventType,bizData);
+                            }else if(eventType.startsWith("user")){
+
+                            }
+                            //澶勭悊浜嬩欢
+//                            process(bizData);
+                            //娑堣垂鎴愬姛
+                            return EventAckStatus.SUCCESS;
+                        } catch (Exception e) {
+                            //娑堣垂澶辫触
+                            return EventAckStatus.LATER;
+                        }
+                    }
+                })
+                .build().start();
+    }
+
+
+
+}
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/CompanyService.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/CompanyService.java
index 47d0cde..5087d55 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/CompanyService.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/CompanyService.java
@@ -1,11 +1,14 @@
 package com.doumee.service.business;
 
+import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
 import com.doumee.service.business.third.model.LoginUserInfo;
 import com.doumee.service.business.third.model.PageData;
 import com.doumee.service.business.third.model.PageWrap;
 import com.doumee.dao.admin.request.UpdateCompanySortDTO;
 import com.doumee.dao.admin.response.CompanyDTO;
 import com.doumee.dao.business.model.Company;
+import com.taobao.api.ApiException;
+import shade.com.alibaba.fastjson2.JSONObject;
 
 import java.util.List;
 
@@ -126,4 +129,8 @@
     List<Company> companyTree(Integer type);
 
     void updateSort(UpdateCompanySortDTO dto);
+
+    void ddPushCompanyInfo(String eventType, JSONObject eventData) throws ApiException;
+
+    String syncDDCompany()throws ApiException;
 }
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/CompanyServiceImpl.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/CompanyServiceImpl.java
index b2edb5a..7336cb7 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/CompanyServiceImpl.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/CompanyServiceImpl.java
@@ -5,9 +5,15 @@
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dingtalk.api.response.OapiV2DepartmentGetResponse;
+import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
 import com.doumee.biz.system.SystemDictDataBiz;
 import com.doumee.config.DataSyncConfig;
 import com.doumee.core.constants.ResponseStatus;
+import com.doumee.core.dingTalk.DingTalk;
+import com.doumee.core.erp.ErpConstants;
+import com.doumee.core.erp.model.openapi.request.erp.OrgListRequest;
+import com.doumee.core.erp.model.openapi.response.erp.ErpOrgListResponse;
 import com.doumee.core.exception.BusinessException;
 import com.doumee.core.haikang.model.HKConstants;
 import com.doumee.core.haikang.model.param.BaseResponse;
@@ -33,6 +39,7 @@
 import com.doumee.dao.system.model.SystemUser;
 import com.doumee.service.business.CompanyService;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.taobao.api.ApiException;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.shiro.SecurityUtils;
@@ -40,6 +47,8 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import shade.com.alibaba.fastjson2.JSONArray;
+import shade.com.alibaba.fastjson2.JSONObject;
 
 import java.util.*;
 import java.util.stream.Collectors;
@@ -63,6 +72,9 @@
 
     @Autowired
     private CompanyJoinMapper companyJoinMapper;
+
+    @Autowired
+    private DingTalk dingTalk;
 
     @Override
     @Transactional(rollbackFor = {BusinessException.class,Exception.class})
@@ -765,7 +777,305 @@
         for (Company updCompany:companyPool) {
             companyMapper.updateById(updCompany);
         }
-
     }
 
+
+
+    // org_dept_create 閮ㄩ棬鏂板缓 {"timeStamp":"1758783935796","eventId":"0c779adba04143958a3960e8e36bbce5","deptId":[1040735458]}
+    // org_dept_modify 閮ㄩ棬淇敼 {"timeStamp":"1758785791639","eventId":"6c2d8c7a61a7419e8928fda3effb3bf4","deptId":[1040735458]}
+    // org_dept_remove 閮ㄩ棬鍒犻櫎 {"timeStamp":"1758785817760","eventId":"47e289f334e041719ed354052da474de","deptId":[1040735458]}
+
+    @Override
+    public void ddPushCompanyInfo(String eventType, JSONObject eventData) throws ApiException {
+        JSONArray jsonArray = eventData.getJSONArray("deptId");
+        if(jsonArray.isEmpty()){
+            return;
+        }
+        if(eventType.equals("org_dept_remove")){
+            //鍒犻櫎瀵瑰簲閮ㄩ棬淇℃伅
+            List<Long> deptIdList = new ArrayList<>();
+            for (int i = 0; i < jsonArray.size(); i++) {
+                Long deptId = jsonArray.getLong(i);
+                 deptIdList.add(deptId);
+            }
+            if(CollectionUtils.isNotEmpty(deptIdList)){
+                syncDelCompany(deptIdList);
+            }
+        }else if(eventType.equals("org_dept_create")||eventType.equals("org_dept_modify")){
+            for (int i = 0; i < jsonArray.size(); i++) {
+                Company company  = companyMapper.selectOne(new QueryWrapper<Company>().lambda()
+                        .eq(Company::getIsdeleted,Constants.ZERO)
+                        .eq(Company::getErpId,jsonArray.getLong(i))
+                );
+                OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse = dingTalk.syncDepartmentInfo(jsonArray.getLong(i));
+                if(Objects.isNull(company)){
+                    getAddCompanyModel(deptGetResponse,company);
+                }else{
+                    getUpdateCompanyModel(deptGetResponse,company);
+                }
+            }
+        }
+    }
+
+    private void doHkDeleteOrg(List<Integer> delIds,List<String> delHkIds,  Date date) {
+        if(delHkIds.size() == 0){
+            return;
+        }
+        OrgDelRequest request = new OrgDelRequest();
+        request.setIndexCodes( delHkIds.toArray(new String[]{}));
+        BaseResponse<List<OrgUpdateFailureResponse>> result =  HKService.delBatchOrg(request);
+        if(result !=null && StringUtils.equals(result.getCode(),HKConstants.RESPONSE_SUCCEE)){
+            List<String> fIds = new ArrayList<>();
+            if(result.getData()!=null){
+                for(OrgUpdateFailureResponse r : result.getData()){
+                    if(r.getCode().equals("0x00052102")){
+                        //涓嶅瓨鍦ㄧ殑涔熺畻鍒犻櫎鎴愬姛
+                        fIds.add(r.getOrgIndexCode());//鍒犻櫎澶辫触鐨勬暟鎹泦鍚�
+                    }
+                }
+            }
+            //鏍囪鍒犻櫎鎴愬姛鐨勬暟鎹紙娴峰悍瀵规帴鐘舵�佷负宸插悓姝ワ紝锛屽悓姝ュけ璐ョ殑浠嶄负寰呭悓姝ワ紝绛変笅涓�娆$户缁鐞嗭紝鐭ラ亾鍏ㄩ儴鍒犻櫎瀹屾瘯锛�
+            companyMapper.update(null,new UpdateWrapper<Company>().lambda()
+                    .set(Company::getHkStatus,Constants.ONE)
+                    .set(Company::getHkDate,date)
+                    .set(Company::getHkId,null )
+                    .in(Company::getId, delIds)
+                    .notIn(fIds.size()>0,Company::getHkId, fIds));
+            companyMapper.update(null,new UpdateWrapper<Company>().lambda()
+                    .set(Company::getHkStatus,Constants.TWO)
+                    .set(Company::getHkDate,date)
+                    .in(Company::getId, delIds)
+                    .in(fIds.size()>0,Company::getHkId, fIds));
+        }
+    }
+
+    @Override
+    public String syncDDCompany() throws ApiException {
+        List<OapiV2DepartmentGetResponse.DeptGetResponse> list = dingTalk.syncAllDDDepartmentList();
+        if(list !=null && list.size()>0){
+            List<Company> addList = new ArrayList<>();
+            List<Company> updateList = new ArrayList<>();
+            List<Long> delIds = new ArrayList<>();//淇敼涓轰娇鐢ㄩ拤閽塱d  erpId
+            List<Company>  allList = companyMapper.selectList(new QueryWrapper<Company>().lambda()
+                    .eq(Company::getIsdeleted,Constants.ZERO).eq(Company::getType,Constants.ONE));
+            dealCompanyChangeList(list,addList,updateList,delIds,allList);
+            if(delIds.size()>0){
+                syncDelCompany(delIds);
+            }
+            return "鍚屾鏁版嵁锛氭柊澧炪��"+addList.size()+"銆戞潯锛屾洿鏂般��"+updateList.size()+"銆戞潯锛屽垹闄ゃ��"+delIds.size()+"銆戞潯";
+        }else{
+            throw  new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "鍚屾閽夐拤鏁版嵁涓虹┖锛�");
+        }
+    }
+
+    private void dealCompanyChangeList(List<OapiV2DepartmentGetResponse.DeptGetResponse> list, List<Company> addList, List<Company> updateList, List<Long> delIds, List<Company> allList) {
+        Date date = new Date();
+        for(OapiV2DepartmentGetResponse.DeptGetResponse respone : list){
+            //鏍规嵁erpid鏌ヨ浼佷笟淇℃伅锛屽垽鏂槸鏂板杩樻槸鏇存柊
+            Company company = findCompanyByERPId(allList,respone.getDeptId().toString());
+            if(company == null){
+                //濡傛灉鏄柊澧�
+                //灏佽鏂板缁勭粐瀵硅薄鏁版嵁
+                addList.add(getAddCompanyModel(respone,new Company()));
+            }else{
+                updateList.add(getUpdateCompanyModel(respone,company));
+            }
+        }
+        if(allList!=null && allList.size()>0){
+            for(Company  c : allList){
+                if(!isCompanyDeleted(c,list)){
+                    delIds.add(Long.valueOf(c.getErpId()));
+                }
+            }
+        }
+    }
+
+
+    /**
+     * 鏁寸悊閽夐拤鍚屾 鏂板缁勭粐瀵硅薄
+     * @param deptGetResponse
+     * @return
+     */
+    private Company getAddCompanyModel(OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse,Company company) {
+        return  syncDDAddCompanyModel(deptGetResponse,company);
+    }
+
+    /**
+     * 鏁寸悊閽夐拤鍚屾 鏂板 闇�瑕佷慨鏀圭殑缁勭粐瀵硅薄
+     * @param deptGetResponse
+     * @param company
+     * @return
+     */
+    private Company getUpdateCompanyModel(OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse, Company company) {
+        return syncDDEditCompanyModel(deptGetResponse,company);
+    }
+
+
+    /**
+     * 鏍规嵁ERPID  鍒ゆ柇鏁版嵁鏄惁宸插湪闆嗗悎閲屽瓨鍦�
+     * @param allList
+     * @param id
+     * @return
+     */
+    private Company findCompanyByERPId(List<Company> allList, String id) {
+        if(allList!=null){
+            for(Company com :allList){
+                if(StringUtils.equals(com.getErpId(),id)){
+                    return com;
+                }
+            }
+        }
+        return  null;
+    }
+
+    private boolean isCompanyDeleted(Company c, List<OapiV2DepartmentGetResponse.DeptGetResponse> list) {
+        for(OapiV2DepartmentGetResponse.DeptGetResponse m : list){
+            if(StringUtils.equals(c.getErpId(),m.getDeptId().toString())){
+                return  true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * 鏁寸悊 閽夐拤鍚屾鐨� 缁勭粐淇℃伅
+     * @param deptGetResponse
+     * @param company
+     * @return
+     */
+    public Company syncDDAddCompanyModel(OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse,Company company){
+        company = new Company();
+        company.setCreateDate(new Date());
+        company.setIsdeleted(Constants.ZERO);
+        company.setStatus(Constants.ZERO);
+
+        company.setName(deptGetResponse.getName());
+        company.setErpId(deptGetResponse.getDeptId().toString());
+        company.setErpParentId(deptGetResponse.getParentId().toString());
+        company.setSortnum(deptGetResponse.getOrder().intValue());//榛樿鏈�涓婇潰
+
+        company.setType(Constants.ONE);
+        String rootOrgId = systemDictDataBiz.queryByCode(Constants.HK_PARAM,Constants.HK_ROOTORG_CODE).getCode();
+        company.setCompanyPath(company.getId()+"/");//鍚嶇О璺緞
+        company.setCompanyNamePath(company.getName());//鍚嶇О璺緞
+        company.setHkParentId(rootOrgId);
+        String idPath = "";
+        if(StringUtils.isNotBlank(company.getErpParentId()) && !StringUtils.equals(company.getErpParentId(),Constants.ONE+"")){
+            Company parent = companyMapper.selectOne(new QueryWrapper<Company>().lambda().eq(Company::getErpId,company.getErpParentId())
+                    .eq(Company::getIsdeleted,Constants.ZERO).last(" limit 1 "));
+            if(parent == null || Constants.equalsInteger(parent.getIsdeleted(),Constants.ONE)){
+                throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "瀵逛笉璧凤紝鐖剁骇缁勭粐淇℃伅涓嶅瓨鍦▇");
+            }
+//            if(StringUtils.isBlank(parent.getHkId())){
+//                throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "瀵逛笉璧凤紝鐖剁骇缁勭粐淇℃伅灏氭湭鍚屾涓嬪彂鎴愬姛~");
+//            }
+            if(Objects.nonNull(parent.getType())&&!Constants.equalsInteger(parent.getType(),-1)){
+                if(!Constants.equalsInteger(company.getType(),parent.getType())){
+                    throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"瀵逛笉璧凤紝缁勭粐淇℃伅閿欒");
+                }
+            }else if(Objects.isNull(parent.getType())){
+                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"瀵逛笉璧凤紝缁勭粐淇℃伅閿欒");
+            }
+            idPath = parent.getCompanyPath();
+            company.setHkParentId(parent.getHkId());
+            company.setCompanyPath(parent.getCompanyPath()+company.getId()+"/");
+            company.setCompanyNamePath(parent.getCompanyNamePath()+"/"+company.getName());
+        }
+        company.setHkCompanyPath(company.getCompanyNamePath());
+        company.setCreateDate(new Date());
+        company.setIsdeleted(Constants.ZERO);
+        company.setHkStatus(Constants.ZERO);
+        company.setStatus(Constants.ZERO);
+        company.setHkDate(company.getCreateDate());
+        company.setEditDate(company.getCreateDate());
+        company.setEditor(company.getCreator());
+        company.setPinyin(Constants.getChinesePingyin(company.getName()));
+        companyMapper.insert(company);
+
+        company.setHkId(UUID.randomUUID().toString().replace("-",""));
+        //涓嬪彂娴峰悍瀹夐槻骞冲彴
+        Boolean issueStatus = addHkOrg(company);
+        Company com = new Company();
+        com.setId(company.getId());
+        com.setHkId(issueStatus?company.getHkId():null);
+        com.setHkStatus(issueStatus?Constants.ONE:Constants.TWO);
+        com.setCompanyPath(idPath+company.getId()+"/");
+        companyMapper.updateById(com);
+        return company;
+    }
+
+
+    public Company syncDDEditCompanyModel(OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse,Company company){
+        company.setErpParentId(deptGetResponse.getParentId().toString());
+        String idPath = "";
+        if(StringUtils.isNotBlank(company.getErpParentId()) && !StringUtils.equals(company.getErpParentId(),Constants.ONE+"")){
+            Company parent = companyMapper.selectOne(new QueryWrapper<Company>().lambda().eq(Company::getErpId,company.getErpParentId())
+                    .eq(Company::getIsdeleted,Constants.ZERO).last("limit 1 "));
+            if(parent == null || Constants.equalsInteger(parent.getIsdeleted(),Constants.ONE)){
+                throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "瀵逛笉璧凤紝鐖剁骇缁勭粐淇℃伅涓嶅瓨鍦▇");
+            }
+            if(Objects.nonNull(parent.getType())&&!Constants.equalsInteger(parent.getType(),-1)){
+                if(!Constants.equalsInteger(company.getType(),parent.getType())){
+                    throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"瀵逛笉璧凤紝缁勭粐淇℃伅閿欒");
+                }
+            }else if(Objects.isNull(parent.getType())){
+                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"瀵逛笉璧凤紝缁勭粐淇℃伅閿欒");
+            }
+            idPath = parent.getCompanyPath();
+            company.setHkParentId(parent.getHkId());
+            company.setCompanyPath(parent.getCompanyPath()+company.getId()+"/");
+            company.setCompanyNamePath(parent.getCompanyNamePath()+"/"+company.getName());
+        }
+
+        company.setName(deptGetResponse.getName());
+        company.setErpId(deptGetResponse.getDeptId().toString());
+        company.setErpParentId(deptGetResponse.getParentId().toString());
+        company.setSortnum(deptGetResponse.getOrder().intValue());//榛樿鏈�涓婇潰
+        company.setEditDate(new Date());
+        company.setHkCompanyPath(company.getCompanyNamePath());
+        company.setHkStatus(Constants.ZERO);
+        company.setStatus(Constants.ZERO);
+        company.setSortnum(deptGetResponse.getOrder().intValue());
+        company.setHkDate(company.getCreateDate());
+        company.setEditDate(company.getCreateDate());
+        company.setEditor(company.getCreator());
+        company.setPinyin(Constants.getChinesePingyin(company.getName()));
+        companyMapper.updateById(company);
+        //涓嬪彂娴峰悍瀹夐槻骞冲彴
+        Boolean issueStatus = editHkOrg(company);
+        Company com = new Company();
+        com.setId(company.getId());
+        com.setHkId(issueStatus?company.getHkId():null);
+        com.setHkStatus(issueStatus?Constants.ONE:Constants.TWO);
+        com.setCompanyPath(idPath+company.getId()+"/");
+        companyMapper.updateById(com);
+        return company;
+    }
+
+
+
+    public void syncDelCompany(List<Long> deptIdList){
+        List<Company> companyList = companyMapper.selectList(new QueryWrapper<Company>()
+                .lambda()
+                .eq(Company::getIsdeleted,Constants.ZERO)
+                .in(Company::getErpId,deptIdList)
+        );
+        if(CollectionUtils.isNotEmpty(companyList)){
+            List<Integer> delIds = companyList.stream().map(i->i.getId()).collect(Collectors.toList());
+            List<String> delHKIds = companyList.stream().filter(i->StringUtils.isNotBlank(i.getHkId())).map(i->i.getHkId()).collect(Collectors.toList());
+
+            //鏍囪涓氬姟鍒犻櫎
+            companyMapper.update(new UpdateWrapper<Company>().lambda()
+                    .set(Company::getIsdeleted,Constants.ONE)
+                    .set(Company::getEditDate,new Date())
+                    .in(Company::getId,delIds)
+            );
+            //娴峰悍鍒犻櫎鐨勬暟鎹紝杩涜鍒犻櫎
+            doHkDeleteOrg(delIds,delHKIds,new Date());
+        }
+    }
+
+
+
 }
diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
index 830c4fe..43c2c6f 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
@@ -7,10 +7,13 @@
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dingtalk.api.response.OapiV2DepartmentGetResponse;
+import com.dingtalk.api.response.OapiV2UserGetResponse;
 import com.doumee.biz.system.SystemDictDataBiz;
 import com.doumee.config.DataSyncConfig;
 import com.doumee.core.annotation.excel.ExcelImporter;
 import com.doumee.core.constants.ResponseStatus;
+import com.doumee.core.dingTalk.DingTalk;
 import com.doumee.core.exception.BusinessException;
 import com.doumee.core.haikang.model.HKConstants;
 import com.doumee.core.haikang.model.param.BaseResponse;
@@ -54,6 +57,7 @@
 import com.doumee.service.business.third.model.response.TmsEmployeeListResponse;
 import com.doumee.service.system.SystemLoginService;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.taobao.api.ApiException;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -67,6 +71,7 @@
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
+import shade.com.alibaba.fastjson2.JSONArray;
 
 import java.math.BigDecimal;
 import java.util.Date;
@@ -138,7 +143,10 @@
     private SmsEmailService smsEmailService;
 
     @Autowired
-    private SystemLoginService systemLoginService; 
+    private SystemLoginService systemLoginService;
+
+    @Autowired
+    private DingTalk dingTalk;
     
     @Value("${debug_model}")
     private Boolean isDebug;
@@ -211,9 +219,9 @@
 
     private Member initAddMemberModel(Member member, LoginUserInfo loginUserInfo) {
         Member insert=  new Member();
-        insert.setCreator(loginUserInfo.getId());
+        insert.setCreator(Objects.nonNull(loginUserInfo.getId())?loginUserInfo.getId():null);
         insert.setCreateDate(new Date());
-        insert.setEditor(loginUserInfo.getId());
+        insert.setEditor(Objects.nonNull(loginUserInfo.getId())?loginUserInfo.getId():null);
         insert.setEditDate(new Date());
         insert.setHkOrgId(member.getHkOrgId());
         insert.setIsdeleted(Constants.ZERO);
@@ -400,6 +408,10 @@
             }
         }
     }
+
+
+
+
     private Member isMemberUpdateParamValid(Member member) {
         Member model = memberJoinMapper.selectJoinOne(Member.class,new MPJLambdaWrapper<Member>()
                 .selectAll(Member.class)
@@ -980,14 +992,14 @@
             }
             TrainTime trainTime = new TrainTime();
             trainTime.setIsdeleted(Constants.ZERO);
-            trainTime.setCreator(loginUserInfo.getId());
+            trainTime.setCreator(Objects.nonNull(loginUserInfo)?loginUserInfo.getId():null);
             trainTime.setCreateDate(new Date());
             trainTime.setEdirot(trainTime.getCreator());
             trainTime.setEditDate(trainTime.getCreateDate());
             trainTime.setStartTime(updateMember.getTrainStartTime());
             trainTime.setEndTime(updateMember.getTrainEndTime());
             trainTime.setMemberId(updateMember.getId());
-            trainTime.setImportInfo("鐢便��"+loginUserInfo.getRealname()+"銆戜簬"+DateUtil.getPlusTime2(trainTime.getCreateDate())+(i==0?"鍒涘缓":"鏇存柊")+"褰曞叆");
+            trainTime.setImportInfo("鐢便��"+(Objects.nonNull(loginUserInfo)?loginUserInfo.getRealname():"閽夐拤鍚屾")+"銆戜簬"+DateUtil.getPlusTime2(trainTime.getCreateDate())+(i==0?"鍒涘缓":"鏇存柊")+"褰曞叆");
             //瀵煎叆鍩硅鏈夋晥鏈�
             trainTimeMapper.insert(trainTime);
         }
@@ -2330,5 +2342,231 @@
     }
 
 
+    /**
+     * 鍚屾閽夐拤鍐呴儴鍛樺伐淇℃伅
+     */
+    public void syncDDUserInfo() throws ApiException {
+        List<OapiV2UserGetResponse.UserGetResponse>  list = dingTalk.syncAllUserInfo();
+        if(CollectionUtils.isEmpty(list)){
+            return;
+        }
+        List<Member> addList = new ArrayList<>();
+        List<Member> updateList = new ArrayList<>();
+        List<String> delIds = new ArrayList<>();//淇敼涓轰娇鐢ㄩ拤閽塱d  erpId
+        List<Member>  allList = memberMapper.selectList(new QueryWrapper<Member>().lambda()
+                .eq(Member::getIsdeleted,Constants.ZERO)
+                .eq(Member::getType,Constants.TWO));
+        dealMemberChangeList(list,addList,updateList,delIds,allList);
+
+        if(delIds.size()>0){
+            syncDelMember(delIds);
+        }
+
+    }
+
+    private void syncDelMember(List<String> delIds) {
+        List<Member> memberList = memberMapper.selectList(new QueryWrapper<Member>().lambda().in(Member::getErpId,delIds)
+                .eq(Member::getIsdeleted,Constants.ZERO));
+        if(CollectionUtils.isNotEmpty(memberList)){
+            for (Member member:memberList) {
+                this.deleteById(member.getId(),null);
+            }
+        }
+
+    }
+
+
+    private void dealMemberChangeList(List<OapiV2UserGetResponse.UserGetResponse> list, List<Member> addList, List<Member> updateList, List<String> delIds, List<Member> allList) {
+        Date date = new Date();
+        for(OapiV2UserGetResponse.UserGetResponse respone : list){
+            //鏍规嵁erpid鏌ヨ浼佷笟淇℃伅锛屽垽鏂槸鏂板杩樻槸鏇存柊
+            Member member = findMemberByERPId(allList,respone.getUnionid());
+            if(member == null){
+                //濡傛灉鏄柊澧�
+                //灏佽鏂板缁勭粐瀵硅薄鏁版嵁
+                addList.add(getAddMemberModel(respone,new Member()));
+            }else{
+                updateList.add(getUpdateMemberModel(respone,member));
+            }
+        }
+        if(allList!=null && allList.size()>0){
+            for(Member m : allList){
+                if(!isMemberDeleted(m,list)){
+                    delIds.add(m.getErpId());
+                }
+            }
+        }
+    }
+
+    private Member getAddMemberModel(OapiV2UserGetResponse.UserGetResponse deptGetResponse,Member member) {
+        return  syncDDAddMemberModel(deptGetResponse,member);
+    }
+
+
+    private Member getUpdateMemberModel(OapiV2UserGetResponse.UserGetResponse deptGetResponse,Member member) {
+        return  syncDDEditMemberModel(deptGetResponse,member);
+    }
+
+
+    private Member syncDDAddMemberModel(OapiV2UserGetResponse.UserGetResponse deptGetResponse,Member member) {
+        member.setCreateDate(new Date());
+        member.setErpId(deptGetResponse.getUserid());
+        member.setPhone(deptGetResponse.getMobile());
+        member.setName(deptGetResponse.getName());
+        member.setCode(deptGetResponse.getJobNumber());
+        isMemberParamValidDetail(member,deptGetResponse.getDeptIdList());
+        //鑾峰彇鍑虹敓鏃ユ湡
+        //鑴辨晱鎿嶄綔
+        Member insert = initAddMemberModel(member,null);
+        //娴峰悍浜哄憳鏂板涓氬姟
+        insert.setHkStatus(dealHkUserBiz(insert)?Constants.ONE:Constants.TWO);
+        insert.setHkDate(new Date());
+        memberMapper.insert(insert);
+        //濡傛灉鏄唴閮ㄧ粍缁囦汉鍛橈紝鏂板绯荤粺鐧婚檰璐﹀彿
+        systemUserMapper.insert(createSystemUser(insert,systemDictDataBiz));
+        //澶勭悊鍩硅鏈夋晥鏈熶笟鍔�
+        dealTrainTIme(member,0,null);
+        return insert;
+    }
+
+
+    public void isMemberParamValidDetail(Member member,List<Long> deptIdList) {
+        if(memberMapper.selectCount(new QueryWrapper<Member>().lambda()
+                .eq(Member::getPhone,  member.getPhone())
+                .in(Member::getType,new Integer[]{Constants.ZERO,Constants.TWO})
+                .eq(Member::getIsdeleted,Constants.ZERO) ) >0){
+            //throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "鎵嬫満鍙枫��"+member.getPhone()+"銆戝凡琚娇鐢紝涓嶈兘閲嶅");
+        }
+        if(Objects.nonNull(deptIdList)){
+            List<Company> companyList = companyMapper.selectList(new QueryWrapper<Company>().lambda().in(Company::getErpId,deptIdList)
+                    .eq(Company::getType,Constants.ONE).eq(Company::getIsdeleted,Constants.ZERO)
+                    .isNotNull(Company::getHkId)
+            );
+            if(CollectionUtils.isNotEmpty(companyList)){
+                member.setHkOrgId(companyList.get(Constants.ZERO).getHkId());
+                member.setCompanyId(companyList.get(Constants.ZERO).getId());
+            }
+        }
+        member.setCompanyType(Constants.ONE);
+        SystemUser queryUserDto = new SystemUser();
+        queryUserDto.setUsername(member.getPhone());
+        queryUserDto.setDeleted(Boolean.FALSE);
+        SystemUser user = systemUserMapper.selectOne(new QueryWrapper<>(queryUserDto).last("limit 1"));
+        if (user != null) {
+            throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "鎵嬫満鍙枫��"+queryUserDto.getUsername()+"銆戝凡琚娇鐢紝涓嶈兘閲嶅");
+        }
+//        // 楠岃瘉宸ュ彿
+        if (StringUtils.isNotBlank(member.getCode())) {
+            queryUserDto = new SystemUser();
+            queryUserDto.setDeleted(Boolean.FALSE);
+            queryUserDto.setEmpNo(member.getCode());
+            user = systemUserMapper.selectOne(new QueryWrapper<>(queryUserDto).last("limit 1"));
+            if (user != null) {
+                throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "宸ュ彿銆�"+member.getCode()+"銆戝凡瀛樺湪");
+            }
+        }
+    }
+    
+    public Member syncDDEditMemberModel(OapiV2UserGetResponse.UserGetResponse deptGetResponse,Member updateMember) { 
+        updateMember.setEditDate(new Date());
+        updateMember.setErpId(deptGetResponse.getUserid());
+        updateMember.setPhone(deptGetResponse.getMobile());
+        updateMember.setName(deptGetResponse.getName());
+        updateMember.setCode(deptGetResponse.getJobNumber());
+       
+        updateMember.setHkId(null);
+        updateMember.setAuthStatus(Constants.ZERO);
+        Boolean hkFlag = dealHkUserForUpdateBiz(updateMember);
+        memberMapper.update(null,new UpdateWrapper<Member>().lambda()
+                .set(Member::getStartTime,null)
+                .set(Member::getEndTime,null)
+                .set(Member::getRoleId,null)
+                .set(Member::getHkStatus,hkFlag?Constants.ONE:Constants.TWO)
+                .set(StringUtils.isNotBlank(updateMember.getPhone()),Member::getPhone,updateMember.getPhone())
+                .set(StringUtils.isNotBlank(updateMember.getName()),Member::getName,updateMember.getName())
+                .set(Member::getEditDate,updateMember.getEditDate())
+                .set(Member::getEditor,updateMember.getEditor())
+                .set(StringUtils.isNotBlank(updateMember.getName()),Member::getPinyin,Constants.getChinesePingyin(updateMember.getName()))
+                .set(StringUtils.isNotBlank(updateMember.getIdcardNo()),Member::getIdcardNo,updateMember.getIdcardNo())
+                .set(StringUtils.isNotBlank(updateMember.getIdcardDecode()),Member::getIdcardDecode,updateMember.getIdcardDecode())
+                .set( Member::getAuthStatus,Constants.ZERO)
+                .set(updateMember.getSex()!=null,Member::getSex,updateMember.getSex())
+                .set(updateMember.getFaceStatus()!=null,Member::getFaceStatus,updateMember.getFaceStatus())
+                .set(updateMember.getHkDate()!=null,Member::getHkDate,updateMember.getHkDate())
+                .set(StringUtils.isNotBlank(updateMember.getRemark()),Member::getRemark,updateMember.getRemark())
+                .set(StringUtils.isNotBlank(updateMember.getFaceImg()),Member::getFaceImg,updateMember.getFaceImg())
+                .set(updateMember.getFaceId()!=null,Member::getFaceId,updateMember.getFaceId())
+                .set(updateMember.getCompanyId()!=null,Member::getCompanyId,updateMember.getCompanyId())
+                .set(Member::getCode,updateMember.getCode())
+                .set( updateMember.getPositionId()!=null,Member::getPositionId,updateMember.getPositionId())
+                .set( updateMember.getIsDangyuan()!=null,Member::getIsDangyuan,updateMember.getIsDangyuan())
+                .set( updateMember.getJobDate()!=null,Member::getJobDate,updateMember.getJobDate())
+                .eq(Member::getId,updateMember.getId()));
+        dealTrainTIme(updateMember,1,null);
+        cancelAllMemberEmpower(updateMember,memberRoleMapper,empowerMapper);
+        //璁板綍鎿嶄綔鏃ュ織
+        saveUserActionBiz(updateMember,null,Constants.UserActionType.EDIT,userActionJoinMapper,null);
+        return updateMember;
+    }
+
+    /**
+     * 鏍规嵁ERPID  鍒ゆ柇鏁版嵁鏄惁宸插湪闆嗗悎閲屽瓨鍦�
+     * @param allList
+     * @param id
+     * @return
+     */
+    private Member findMemberByERPId(List<Member> allList, String id) {
+        if(allList!=null){
+            for(Member com :allList){
+                if(StringUtils.equals(com.getErpId(),id)){
+                    return com;
+                }
+            }
+        }
+        return  null;
+    }
+
+    private boolean isMemberDeleted(Member member, List<OapiV2UserGetResponse.UserGetResponse> list) {
+        for(OapiV2UserGetResponse.UserGetResponse m : list){
+            if(StringUtils.equals(m.getUnionid(),member.getErpId())){
+                return  true;
+            }
+        }
+        return false;
+    }
+
+
+    public void ddPushMemberInfo(String eventType, shade.com.alibaba.fastjson2.JSONObject eventData) throws ApiException {
+        JSONArray jsonArray = eventData.getJSONArray("userId");
+        if(jsonArray.isEmpty()){
+            return;
+        }
+        if(eventType.equals("user_leave_org")){
+            //鍒犻櫎瀵逛汉鍛樹俊鎭�
+            List<String> userIdList = new ArrayList<>();
+            for (int i = 0; i < jsonArray.size(); i++) {
+                String deptId = jsonArray.getString(i);
+                userIdList.add(deptId);
+            }
+            if(CollectionUtils.isNotEmpty(userIdList)){
+                syncDelMember(userIdList);
+            }
+        }else if(eventType.equals("user_add_org")||eventType.equals("user_modify_org")){
+            for (int i = 0; i < jsonArray.size(); i++) {
+                Member member  = memberMapper.selectOne(new QueryWrapper<Member>().lambda()
+                        .eq(Member::getIsdeleted,Constants.ZERO)
+                        .eq(Member::getErpId,jsonArray.getLong(i))
+                        .last(" limit 1")
+                );
+                OapiV2UserGetResponse.UserGetResponse deptGetResponse = dingTalk.syncUserInfo(jsonArray.getString(i));
+                if(Objects.isNull(member)){
+                    getAddMemberModel(deptGetResponse,member);
+                }else{
+                    getUpdateMemberModel(deptGetResponse,member);
+                }
+            }
+        }
+    }
+
 
 }

--
Gitblit v1.9.3