Forráskód Böngészése

企业微信增加审批单据对接

zhouy 3 éve
szülő
commit
399207fb97

+ 26 - 2
qywx-sdk/src/main/java/com/usoftchina/qywx/sdk/OaSdk.java

@@ -73,7 +73,31 @@ public class OaSdk extends BaseSdk {
         return resp.getBody();
     }
 
-    public void applyApproval(ApplyApprovalReq req) {
-
+    /**
+     * 批量获取审批单号
+     * 支持按模板类型、申请人、部门、申请单审批状态等条件筛选。
+     * 一次拉取调用最多拉取100个审批记录,可以通过多次拉取的方式来满足需求,但调用频率不可超过600次/分。
+     * */
+    public GetApprovalCodeResp getApprovalCode(GetApprovalCodeReq req){
+        ResponseEntity<GetApprovalCodeResp> resp = restTemplate.postForEntity(
+                baseUrl + "/cgi-bin/oa/getapprovalinfo?access_token={access_token}",
+                req.build(),
+                GetApprovalCodeResp.class,
+                new ModelMap("access_token", getAccessToken(APPROVAL_AGENT_CODE)));
+        assertOK(resp);
+        System.out.println(resp.getBody().getSp_no_list());
+        return resp.getBody();
+    }
+    /**
+     * 获取审批申请详情
+     * */
+    public GetApprovalDetailResp.ApprovalDetail getApprovalDetail(String spNo){
+        ResponseEntity<GetApprovalDetailResp> resp = restTemplate.postForEntity(
+                baseUrl + "/cgi-bin/oa/getapprovaldetail?access_token={access_token}",
+                new ModelMap("sp_no", spNo),
+                GetApprovalDetailResp.class,
+                new ModelMap("access_token", getAccessToken(APPROVAL_AGENT_CODE)));
+        assertOK(resp);
+        return resp.getBody().getInfo();
     }
 }

+ 115 - 0
qywx-sdk/src/main/java/com/usoftchina/qywx/sdk/dto/GetApprovalCodeReq.java

@@ -0,0 +1,115 @@
+package com.usoftchina.qywx.sdk.dto;
+
+import org.springframework.ui.ModelMap;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author: zhouy
+ * @date: 2021/10/12 11:27
+ * @desc: 获取审批单据请求信息
+ */
+public class GetApprovalCodeReq {
+    /**
+     * 开始时间
+     * */
+    private Long starttime;
+    /**
+     * 结束时间
+     * */
+    private Long endtime;
+    /**
+     * 分页查询游标,默认为0,后续使用返回的next_cursor进行分页拉取
+     * */
+    private Integer cursor;
+    /**
+     * 一次请求拉取审批单数量,默认值为100,上限值为100。若accesstoken为自建应用,仅允许获取在应用可见范围内申请人提交的表单,返回的sp_no_list个数可能和size不一致,开发者需用next_cursor判断表单记录是否拉取完
+     * */
+    private Integer size;
+
+    /**
+    * 筛选条件
+    * */
+    private List<GetApprovalCodeFilter> filters;
+
+    public Long getStarttime() {
+        return starttime;
+    }
+
+    public void setStarttime(Long starttime) {
+        this.starttime = starttime;
+    }
+
+    public Long getEndtime() {
+        return endtime;
+    }
+
+    public void setEndtime(Long endtime) {
+        this.endtime = endtime;
+    }
+
+    public Integer getCursor() {
+        return cursor;
+    }
+
+    public void setCursor(Integer cursor) {
+        this.cursor = cursor;
+    }
+
+    public Integer getSize() {
+        return size;
+    }
+
+    public void setSize(Integer size) {
+        this.size = size;
+    }
+
+    public List<GetApprovalCodeFilter> getFilters() {
+        return filters;
+    }
+
+    public void setFilters(List<GetApprovalCodeFilter> filters) {
+        this.filters = filters;
+    }
+
+    public  class GetApprovalCodeFilter {
+        private String key;
+        private String value;
+
+        public GetApprovalCodeFilter(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        public Map<String, Object> build() {
+            Map<String, Object> data = new HashMap<>(2);
+            data.put("key", key);
+            data.put("value", value);
+            return data;
+        }
+    }
+
+    public GetApprovalCodeReq(Long starttime, Long endtime, Integer cursor){
+        this.starttime = starttime;
+        this.endtime = endtime;
+        this.cursor = cursor;
+        this.size = 100;
+    }
+
+    public Map<String, Object> build() {
+        Map<String, Object> data = new HashMap<>(5);
+        data.put("starttime", starttime);
+        data.put("endtime", endtime);
+        data.put("cursor", cursor);
+        data.put("size", size);
+        if (null != filters) {
+            data.put("filters",
+                    filters.stream().map(filter -> filter.build()).collect(Collectors.toList())
+            );
+        }
+        return data;
+    }
+}

+ 30 - 0
qywx-sdk/src/main/java/com/usoftchina/qywx/sdk/dto/GetApprovalCodeResp.java

@@ -0,0 +1,30 @@
+package com.usoftchina.qywx.sdk.dto;
+
+
+import java.util.Set;
+
+/**
+ * @author: zhouy
+ * @date: 2021/10/12 11:23
+ * @desc: 获取审批业务单号list
+ */
+public class GetApprovalCodeResp extends BaseResp {
+    private Set<String> sp_no_list;
+    private Integer next_cursor;
+
+    public Set<String> getSp_no_list() {
+        return sp_no_list;
+    }
+
+    public void setSp_no_list(Set<String> sp_no_list) {
+        this.sp_no_list = sp_no_list;
+    }
+
+    public Integer getNext_cursor() {
+        return next_cursor;
+    }
+
+    public void setNext_cursor(Integer next_cursor) {
+        this.next_cursor = next_cursor;
+    }
+}

+ 168 - 0
qywx-sdk/src/main/java/com/usoftchina/qywx/sdk/dto/GetApprovalDetailResp.java

@@ -0,0 +1,168 @@
+package com.usoftchina.qywx.sdk.dto;
+
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.List;
+
+/**
+ * @author: zhouy
+ * @date: 2021/10/12 11:23
+ * @desc: 获取审批业务单号list
+ */
+public class GetApprovalDetailResp extends BaseResp {
+
+    private ApprovalDetail info;
+
+    public ApprovalDetail getInfo() {
+        return info;
+    }
+
+    public void setInfo(ApprovalDetail info) {
+        this.info = info;
+    }
+
+    public static class ApprovalDetail {
+       private String sp_no;
+       private String sp_name;
+       private Integer sp_status;
+       private String template_id;
+       private Long apply_time;
+       private Object sp_record;
+       private ApplyData apply_data;
+
+        public String getSp_no() {
+            return sp_no;
+        }
+
+        public void setSp_no(String sp_no) {
+            this.sp_no = sp_no;
+        }
+
+        public String getSp_name() {
+            return sp_name;
+        }
+
+        public void setSp_name(String sp_name) {
+            this.sp_name = sp_name;
+        }
+
+        public Integer getSp_status() {
+            return sp_status;
+        }
+
+        public void setSp_status(Integer sp_status) {
+            this.sp_status = sp_status;
+        }
+
+        public String getTemplate_id() {
+            return template_id;
+        }
+
+        public void setTemplate_id(String template_id) {
+            this.template_id = template_id;
+        }
+
+        public Long getApply_time() {
+            return apply_time;
+        }
+
+        public void setApply_time(Long apply_time) {
+            this.apply_time = apply_time;
+        }
+
+        public Object getSp_record() {
+            return sp_record;
+        }
+
+        public void setSp_record(Object sp_record) {
+            this.sp_record = sp_record;
+        }
+
+        public ApplyData getApply_data() {
+            return apply_data;
+        }
+
+        public void setApply_data(ApplyData apply_data) {
+            this.apply_data = apply_data;
+        }
+    }
+
+    public static class ApplyData {
+        private  List<ApplyDataContent> contents;
+
+        public List<ApplyDataContent> getContents() {
+            return contents;
+        }
+
+        public void setContents(List<ApplyDataContent> contents) {
+            this.contents = contents;
+        }
+    }
+
+    public static class ApplyDataContent {
+        private String control;
+        private String id;
+        private String title;
+        private String value;
+
+        public String getControl() {
+            return control;
+        }
+
+        public void setControl(String control) {
+            this.control = control;
+        }
+
+        public String getId() {
+            return id;
+        }
+
+        public void setId(String id) {
+            this.id = id;
+        }
+
+        public String getTitle() {
+            return title;
+        }
+
+        public void setTitle(String title) {
+            this.title = title;
+        }
+
+        public String getValue() {
+            return value;
+        }
+
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return "ApplyDataContent{" +
+                    "control='" + control + '\'' +
+                    ", id='" + id + '\'' +
+                    ", title=" + title +
+                    ", value=" + value +
+                    '}';
+        }
+        public String getCNTitle(){
+            return  JSONArray.parseArray(title).stream().filter(o -> {
+                return  JSONObject.parseObject( String.valueOf(o)).getString("lang").equals("zh_CN");
+            }).findFirst().get().toString();
+        }
+
+        public String getFormatValue(){
+            switch (control){
+                case "Textarea" :
+                    return JSONObject.parseObject(value).getString("text");
+                default :
+                    return value;
+            }
+        }
+
+    }
+
+}

+ 2 - 2
qywx-sdk/src/test/java/com/usoftchina/qywx/sdk/test/BaseTest.java

@@ -18,7 +18,7 @@ public abstract class BaseTest {
 
     static {
         properties = new QywxProperties();
-        properties.setCorpId("wwd42c39382ee6298e");
+        properties.setCorpId("wwbdf616a7b98dfe14");
         List<Agent> agents = new ArrayList<>(3);
         // 通讯录
         agents.add(new Agent("AddressBook", null, "uXuJXVLSjMsvvqPeb8tFDAVDZAphz1PoMcMN4KDuV7g"));
@@ -27,7 +27,7 @@ public abstract class BaseTest {
         // 打卡
         agents.add(new Agent("Checkin", 3010011, "UqGEo3694hopQIfsd3fEDSTJ0tmHAehavWzv082fkp0"));
         // 审批
-        agents.add(new Agent("Approval", 3010040, "sSwb62-S-bGftHcCVChnxASz8SnqnvobtIU8Q42kT2w"));
+        agents.add(new Agent("Approval", 3010040, "-vQnHTrVTBGw6DM-3wTWfi40X0R-9aDZDoH2oBU9kxw"));
 
         // UAS系统
         agents.add(new Agent("Uas", 1000003, "mMojQmQVSeYmh575GhLObRxRFCYKIwvzwOXM8qqaOnY"));

+ 35 - 6
qywx-sdk/src/test/java/com/usoftchina/qywx/sdk/test/OaSdkTest.java

@@ -2,17 +2,13 @@ package com.usoftchina.qywx.sdk.test;
 
 import com.alibaba.fastjson.JSON;
 import com.usoftchina.qywx.sdk.OaSdk;
-import com.usoftchina.qywx.sdk.dto.GetCheckinDataReq;
-import com.usoftchina.qywx.sdk.dto.GetCheckinDataResp;
-import com.usoftchina.qywx.sdk.dto.GetCheckinOptionReq;
-import com.usoftchina.qywx.sdk.dto.GetCheckinOptionResp;
+import com.usoftchina.qywx.sdk.dto.*;
 import org.junit.Test;
 import org.springframework.util.CollectionUtils;
 
 import java.time.LocalDate;
 import java.time.ZoneId;
-import java.util.Arrays;
-import java.util.List;
+import java.util.*;
 
 /**
  * @author yingp
@@ -43,4 +39,37 @@ public class OaSdkTest extends BaseTest {
             System.out.println(JSON.toJSONString(dataList));
         }
     }
+
+    @Test
+    public void getApproval() {
+
+        long unixStartTime = 1634000400 ;
+        long unixEndTime = 1634119200;
+        System.out.println(System.currentTimeMillis());
+        System.out.println(new Date().getTime());
+        long a = 1634127666*1000;
+        System.out.println(a);
+        System.out.println( ((Long)Long.parseLong("1634127666")).longValue()*1000);
+        Long timestamp = Long.parseLong("1634127666")*1000;
+        System.out.println(new java.util.Date( Long.parseLong("1634127666")*1000));
+     String date = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new java.util.Date(timestamp));
+     System.out.println(date);
+       /* Integer cursor = 0;
+        GetApprovalCodeResp resp = null;
+        Set<String> approvalCodes = new HashSet<String>();
+        GetApprovalCodeReq req = new GetApprovalCodeReq(unixStartTime, unixEndTime,cursor);
+        GetApprovalCodeResp getApprovalCodeResp = sdk.getApprovalCode(req);
+        approvalCodes.addAll(getApprovalCodeResp.getSp_no_list());
+        System.out.println(new Date().getTime()/1000);
+        System.out.println(approvalCodes.size());
+        *//**
+         * 同步详情信息
+         * *//*
+        approvalCodes.stream().forEach(code -> {
+            GetApprovalDetailResp.ApprovalDetail detail = sdk.getApprovalDetail(code);
+            System.out.println(detail.getTemplate_id());
+            System.out.println(detail.getApply_data().getContents());
+            System.out.println(detail.getApply_time());
+        });*/
+    }
 }

+ 7 - 2
uas-office-core/src/main/java/com/usoftchina/uas/office/jdbc/SchemaUtils.java

@@ -120,7 +120,12 @@ public class SchemaUtils {
             if (isTableExists(name, jdbcTemplate)) {
                 columnBuilderList.forEach(builder -> {
                     if (isColumnExists(name, builder.name, jdbcTemplate)) {
-                        builder.modify(this, jdbcTemplate);
+                        try {
+                            builder.modify(this, jdbcTemplate);
+                        }catch (Exception e){
+
+                        }
+
                     } else {
                         builder.add(this, jdbcTemplate);
                     }
@@ -257,7 +262,7 @@ public class SchemaUtils {
                 str.append(" primary key");
             }
             if (null != defaultValue) {
-                str.append("default ");
+                str.append(" default ");
                 if (colType.toLowerCase().startsWith("varchar")) {
                     str.append("'").append(defaultValue).append("'");
                 } else {

+ 63 - 0
uas-office-qywx-server/src/main/resources/erp_schema.json

@@ -12,6 +12,69 @@
       }
     ]
   },
+  {
+    "name": "QywxOASyncRecord",
+    "columns": [
+      {
+        "name": "sync_time",
+        "type": "date"
+      },
+      {
+        "name": "update_time",
+        "type": "date"
+      }
+    ]
+  },
+  {
+    "name": "QywxApprovalRecord",
+    "columns": [
+      {
+        "name": "sync_time",
+        "type": "date"
+      },
+      {
+        "name": "spno",
+        "type": "varchar2(30)"
+      },
+      {
+        "name": "spname",
+        "type": "varchar2(100)"
+      },
+      {
+        "name": "apply_time",
+        "type": "date"
+      },
+      {
+        "name": "state",
+        "type": "number",
+        "defaultValue": 0
+      }
+    ]
+  },
+  {
+    "name": "QywxApprovalRecordDet",
+    "columns": [
+      {
+        "name": "control",
+        "type": "varchar2(50)"
+      },
+      {
+        "name": "id",
+        "type": "varchar2(50)"
+      },
+      {
+        "name": "title",
+        "type": "varchar2(200)"
+      },
+      {
+        "name": "value",
+        "type": "clob"
+      },{
+        "name": "maincode",
+        "type": "varchar2(50)"
+      }
+    ]
+  },
   {
     "name": "QywxAgent",
     "columns": [

+ 60 - 0
uas-office-qywx/src/main/java/com/usoftchina/uas/office/qywx/entity/QywxApprovalRecord.java

@@ -0,0 +1,60 @@
+package com.usoftchina.uas.office.qywx.entity;
+
+import com.usoftchina.qywx.sdk.dto.GetApprovalDetailResp;
+import com.usoftchina.qywx.sdk.dto.GetCheckinDataResp;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author: zhouy
+ * @date: 2021/10/13 18:02
+ * @desc: 审批单据记录
+ */
+public class QywxApprovalRecord {
+    private String spno;
+    private String spname;
+    private Date apply_time;
+    private Date sync_time;
+    List<QywxApprovalRecordDet> details;
+
+    public String getSpno() {
+        return spno;
+    }
+
+    public void setSpno(String spno) {
+        this.spno = spno;
+    }
+
+    public String getSpname() {
+        return spname;
+    }
+
+    public void setSpname(String spname) {
+        this.spname = spname;
+    }
+
+    public Date getApply_time() {
+        return apply_time;
+    }
+
+    public void setApply_time(Date apply_time) {
+        this.apply_time = apply_time;
+    }
+
+    public Date getSync_time() {
+        return sync_time;
+    }
+
+    public void setSync_time(Date sync_time) {
+        this.sync_time = sync_time;
+    }
+
+    public List<QywxApprovalRecordDet> getDetails() {
+        return details;
+    }
+
+    public void setDetails(List<QywxApprovalRecordDet> details) {
+        this.details = details;
+    }
+}

+ 53 - 0
uas-office-qywx/src/main/java/com/usoftchina/uas/office/qywx/entity/QywxApprovalRecordDet.java

@@ -0,0 +1,53 @@
+package com.usoftchina.uas.office.qywx.entity;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONPObject;
+
+import java.util.Date;
+
+/**
+ * @author: zhouy
+ * @date: 2021/10/13 18:02
+ * @desc: 审批单据组件详情
+ */
+public class QywxApprovalRecordDet {
+    private String control;
+    private String id;
+    private String title;
+    private String value;
+
+    public String getControl() {
+        return control;
+    }
+
+    public void setControl(String control) {
+        this.control = control;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+
+}

+ 34 - 0
uas-office-qywx/src/main/java/com/usoftchina/uas/office/qywx/manage/entity/QywxOASyncRecord.java

@@ -0,0 +1,34 @@
+package com.usoftchina.uas.office.qywx.manage.entity;
+
+import java.util.Date;
+
+/**
+ * @author yingp
+ * @date 2020/2/17
+ */
+public class QywxOASyncRecord {
+    /**
+     * 同步时间
+     */
+    private Date sync_time;
+    /**
+     * 更新时间
+     * */
+    private Date update_time;
+
+    public Date getSync_time() {
+        return sync_time;
+    }
+
+    public void setSync_time(Date sync_time) {
+        this.sync_time = sync_time;
+    }
+
+    public Date getUpdate_time() {
+        return update_time;
+    }
+
+    public void setUpdate_time(Date update_time) {
+        this.update_time = update_time;
+    }
+}

+ 70 - 0
uas-office-qywx/src/main/java/com/usoftchina/uas/office/qywx/manage/service/QywxOASyncService.java

@@ -0,0 +1,70 @@
+package com.usoftchina.uas.office.qywx.manage.service;
+
+import com.usoftchina.qywx.sdk.dto.GetApprovalDetailResp;
+import com.usoftchina.uas.office.qywx.manage.entity.QywxOASyncRecord;
+import com.usoftchina.uas.office.service.AbstractService;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.support.AbstractLobCreatingPreparedStatementCallback;
+import org.springframework.jdbc.support.lob.DefaultLobHandler;
+import org.springframework.jdbc.support.lob.LobCreator;
+import org.springframework.jdbc.support.lob.LobHandler;
+import org.springframework.stereotype.Service;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Date;
+
+/**
+ * @author yingp
+ * @date 2020/2/17
+ */
+@Service
+public class QywxOASyncService extends AbstractService {
+
+    public QywxOASyncRecord find() {
+        return queryForBean("select * from QywxOASyncRecord", QywxOASyncRecord.class);
+    }
+
+    public Long getLastSyncTime() {
+        QywxOASyncRecord record = find();
+        if (null != record && null != record.getSync_time()) {
+            return record.getSync_time().getTime();
+        }
+        return null;
+    }
+
+    public void setSyncTime(Date syncTime) {
+        QywxOASyncRecord record = find();
+        if (null == record) {
+            jdbcTemplate.update("insert into QywxOASyncRecord(sync_time, update_time) values (?, sysdate)", syncTime);
+        } else {
+            jdbcTemplate.update("update QywxOASyncRecord set sync_time=?, update_time=sysdate  ", syncTime);
+        }
+    }
+    /**
+     * 保存审批详情
+     * */
+    public void saveApproval(GetApprovalDetailResp.ApprovalDetail detail, Date syncTime) {
+        System.out.println(detail.getApply_time());
+        System.out.println(new Date(detail.getApply_time().longValue()*1000));
+        jdbcTemplate.update("insert into QywxApprovalRecord(sync_time, spno, spname, apply_time ) values (?, ?, ? ,?)", syncTime, detail.getSp_no(), detail.getSp_name(), new Date(detail.getApply_time()*1000));
+        /**
+         * 保存详情信息
+         * */
+        LobHandler lobHandler = new DefaultLobHandler();
+        String sql="INSERT INTO  QywxApprovalRecordDet(maincode, control,id, title, value ) values(?,?,?,?,?)";
+
+        detail.getApply_data().getContents().stream().forEach(content -> {
+            jdbcTemplate.execute(sql, new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
+                @Override
+                protected void setValues(PreparedStatement ps, LobCreator lob) throws SQLException, DataAccessException {
+                    ps.setString(1, detail.getSp_no());
+                    ps.setString(2, content.getControl());
+                    ps.setString(3, content.getId());
+                    ps.setString(4, content.getCNTitle());
+                    lob.setClobAsString(ps, 5, content.getFormatValue());
+                }
+            });
+        });
+    }
+}

+ 81 - 0
uas-office-qywx/src/main/java/com/usoftchina/uas/office/qywx/task/QywxOATask.java

@@ -0,0 +1,81 @@
+package com.usoftchina.uas.office.qywx.task;
+
+import com.usoftchina.qywx.sdk.OaSdk;
+import com.usoftchina.qywx.sdk.dto.*;
+import com.usoftchina.uas.office.entity.DataCenter;
+import com.usoftchina.uas.office.jdbc.DataSourceHolder;
+import com.usoftchina.uas.office.qywx.entity.CardLog;
+import com.usoftchina.uas.office.qywx.entity.Employee;
+import com.usoftchina.uas.office.qywx.entity.OutSign;
+import com.usoftchina.uas.office.qywx.manage.service.QywxOASyncService;
+import com.usoftchina.uas.office.qywx.manage.service.QywxSettingService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author: zhouy
+ * @date: 2021/9/10 16:56
+ * @desc: 企业微信OA单据对接
+ */
+@Component
+public class QywxOATask {
+
+    @Autowired
+    private OaSdk oaSdk;
+
+    @Autowired
+    private QywxOASyncService syncService;
+
+    @Scheduled(fixedDelay = 300000, initialDelay = 30000)
+    public void syncApprovalCode() {
+        if (!oaSdk.isAgentEnabled(OaSdk.APPROVAL_AGENT_CODE)) {
+            return;
+        }
+        DataCenter dataCenter = DataCenter.INSTANCE;
+        if (null != dataCenter.getUsername() && null != dataCenter.getPassword() && null != dataCenter.getUrl()) {
+            try {
+                DataSourceHolder.set(dataCenter);
+                //取上次对接时间
+                Long lastTime = syncService.getLastSyncTime();
+                if (lastTime == null) {
+                    lastTime = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
+                }
+                Date now = new Date();
+                long unixStartTime = lastTime/1000 ;
+                long unixEndTime = now.getTime()/1000;
+                Integer cursor = 0;
+                GetApprovalCodeResp resp = null;
+                Set<String> approvalCodes = new HashSet<String>();
+                while (cursor != null){
+                    resp = syncApprovalCode(unixStartTime, unixEndTime , cursor);
+                    if(!resp.getSp_no_list().isEmpty()) {
+                        approvalCodes.addAll(resp.getSp_no_list());
+                    }
+                    cursor = resp.getNext_cursor() != null ? resp.getNext_cursor() : null;
+                }
+                approvalCodes.stream().forEach(code -> {
+                    GetApprovalDetailResp.ApprovalDetail detail = oaSdk.getApprovalDetail(code);
+                    syncService.saveApproval(detail, now);
+                });
+                syncService.setSyncTime(now);
+            } finally {
+                DataSourceHolder.clear();
+            }
+        }
+    }
+    private GetApprovalCodeResp syncApprovalCode(Long startTime, Long endTime, Integer cursor){
+        GetApprovalCodeReq req = new GetApprovalCodeReq(startTime, endTime,cursor);
+        return oaSdk.getApprovalCode(req);
+    }
+
+}