procedure TDingtalkController.GetAttendanceRecords;
var
  UserDataSet: TDataSet;
  UserIds: TList<string>;
  Cursor, PageSize, BatchIndex, UserIndex: Integer;
  RestClient: IMVCRESTClient;
  Response: IMVCRESTResponse;
  AccessToken: string;
  RequestBody, ResponseJSON: TJsonObject;
  UserIdArray, RecordArray: TJsonArray;
  StartDate, EndDate: string;
  NextCursor: Integer;
  AttendanceList: TObjectList<TAttendanceRecord>;
  Attendance: TAttendanceRecord;
  HasMoreRecords: Boolean;
  Serializer: TMVCJsonDataObjectsSerializer;
begin
  ActiveRecordConnectionsRegistry.AddConnection('attendanceDB', 'DB');

  try
    ActiveRecordConnectionsRegistry.SetCurrent('attendanceDB');
    UserIds := TList<string>.Create;
    try
      // 获取所有用户ID
      UserDataSet := TMVCActiveRecord.SelectDataSet('SELECT userid FROM dingtalk_userlist', [], True);
      try
        while not UserDataSet.Eof do
        begin
          UserIds.Add(Trim(UserDataSet.FieldByName('userid').AsString));
          UserDataSet.Next;
        end;
      finally
        UserDataSet.Free;
      end;

      // 设置全天查询范围 (00:00:00 - 23:59:59)
      StartDate := FormatDateTime('yyyy-mm-dd', Now) + ' 00:00:00';
      EndDate := FormatDateTime('yyyy-mm-dd', Now) + ' 23:59:59';

      // 分批次处理用户(每批50人)
      BatchIndex := 0;
      while BatchIndex < UserIds.Count do
      begin
        // 创建当前批次的用户ID数组
        UserIdArray := TJsonArray.Create;
        try
          // 添加当前批次用户
          for UserIndex := BatchIndex to Min(BatchIndex + 49, UserIds.Count - 1) do
            if not UserIds[UserIndex].IsEmpty then
              UserIdArray.Add(UserIds[UserIndex]);

          Cursor := 0;    // 重置游标
          PageSize := 50; // 分页大小
          HasMoreRecords := True;

          TMVCActiveRecord.CurrentConnection.StartTransaction;
          try
            while HasMoreRecords do
            begin
              RequestBody := TJsonObject.Create;
              try
                // 构建请求体
                RequestBody.S['workDateFrom'] := StartDate;
                RequestBody.S['workDateTo'] := EndDate;
                RequestBody.I['offset'] := Cursor;
                RequestBody.I['limit'] := PageSize;
                RequestBody.A['userIdList'] := UserIdArray.Clone; // 正确的数组格式
                logd(RequestBody);
                // 获取访问令牌
                AccessToken := Context.Data['GetAccessToken'];

                // 发送API请求
                RestClient := TMVCRESTClient.New.BaseURL(DINGTALK_BASE_URL);
                Response := RestClient.AddQueryStringParam('access_token', AccessToken).Post('/attendance/list', RequestBody);

                // 检查响应状态
                if not ParseResponse(Response) then
                  Break;
               // logw('Response.Content:' + Response.Content);

                // 解析响应数据
                Serializer := TMVCJsonDataObjectsSerializer.Create;
                try
                  ResponseJSON := Serializer.ParseObject(Response.Content);
                  try
                    RecordArray := ResponseJSON.A['recordresult'];

                  //  logd(RecordArray);

                    if RecordArray.Count > 0 then
                    begin
                      AttendanceList := TObjectList<TAttendanceRecord>.Create(False);
                      try
                        // 反序列化JSON数据
                        Serializer.JsonArrayToList(RecordArray, WrapAsList(AttendanceList), TAttendanceRecord, TMVCSerializationType.stProperties, nil);

                        // 批量插入记录
                        for Attendance in AttendanceList do
                        begin
                          Attendance.PrimaryKeyIsAutogenerated := False;
                          Attendance.Insert;
                         // logd(Attendance);
                        end;
                      finally
                        AttendanceList.Free;
                      end;
                    end;

                    // 检查是否还有更多数据
                    HasMoreRecords := ResponseJSON.O['result'].B['has_more'];
                    if HasMoreRecords then
                      NextCursor := ResponseJSON.O['result'].I['next_cursor']
                    else
                      NextCursor := -1;

                  finally
                    ResponseJSON.Free;
                  end;
                finally
                  Serializer.Free;
                end;

                // 更新游标
                Cursor := NextCursor;
                if NextCursor <= 0 then
                  Break;
              finally
                //RequestBody.Free;
              end;
            end;
            TMVCActiveRecord.CurrentConnection.Commit; // 提交整个批次的事务
          except
            on E: Exception do
            begin
              TMVCActiveRecord.CurrentConnection.Rollback;
              LogE('Error processing batch: ' + E.Message);
              raise;
            end;
          end;

        finally
          UserIdArray.Free;
        end;

        // 准备处理下一批用户
        BatchIndex := BatchIndex + 50;
        if BatchIndex < UserIds.Count then
          Sleep(200); // 添加延迟避免请求过快
      end;
    finally
      UserIds.Free;
    end;
  finally
    ActiveRecordConnectionsRegistry.RemoveConnection('attendanceDB');
  end;
end;
unit Entity.Dingtalk.Attendance_records;

interface

uses
  MVCFramework.Serializer.Commons, MVCFramework.ActiveRecord, System.Classes;

type
  [MVCNameCase(ncCamelCase)]  //必须反序列化成指定格式
  [MVCTable('attendance_records')]
  TAttendanceRecord = class(TMVCActiveRecord)
  private
    [MVCTableField('id', [foPrimaryKey, foAutoGenerated])]
    fID: Int64;
    [MVCTableField('checkType')]
    fChecktype: string;
    [MVCTableField('corpId')]
    fCorpid: string;
    [MVCTableField('locationResult')]
    fLocationresult: string;
    [MVCTableField('baseCheckTime')]
    fBasechecktime: Int64;
    [MVCTableField('groupId')]
    fGroupid: Int64;
    [MVCTableField('timeResult')]
    fTimeresult: string;
    [MVCTableField('userId')]
    fUserid: string;
    [MVCTableField('workDate')]
    fWorkdate: Int64;
    [MVCTableField('sourceType')]
    fSourcetype: string;
    [MVCTableField('userCheckTime')]
    fUserchecktime: Int64;
    [MVCTableField('planId')]
    fPlanid: Int64;

  public
    constructor Create; override;
    destructor Destroy; override;
    [MVCNameAs('id')]
    property ID: Int64 read fID write fID;
    [MVCNameAs('checkType')]
    property Checktype: string read fChecktype write fChecktype;
    [MVCNameAs('corpId')]
    property Corpid: string read fCorpid write fCorpid;
    [MVCNameAs('locationResult')]
    property Locationresult: string read fLocationresult write fLocationresult;
    [MVCNameAs('baseCheckTime')]
    property Basechecktime: Int64 read fBasechecktime write fBasechecktime;
    [MVCNameAs('groupId')]
    property Groupid: Int64 read fGroupid write fGroupid;
    [MVCNameAs('timeResult')]
    property Timeresult: string read fTimeresult write fTimeresult;
    [MVCNameAs('userId')]
    property Userid: string read fUserid write fUserid;
    [MVCNameAs('workDate')]
    property Workdate: Int64 read fWorkdate write fWorkdate;
    [MVCNameAs('sourceType')]
    property Sourcetype: string read fSourcetype write fSourcetype;
    [MVCNameAs('userCheckTime')]
    property Userchecktime: Int64 read fUserchecktime write fUserchecktime;
    [MVCNameAs('planId')]
    property Planid: Int64 read fPlanid write fPlanid;
  end;

implementation

constructor TAttendanceRecord.Create;
begin
  inherited Create;
end;

destructor TAttendanceRecord.Destroy;
begin
  inherited;
end;

initialization
  ActiveRecordMappingRegistry.AddEntity('attendance_records', TAttendanceRecord);

end.

 

posted on 2025-07-24 16:22  redhat588  阅读(42)  评论(0)    收藏  举报