WinForm調用釘釘獲取考勤結果


關注點

  • 1、釘釘AccessToken的獲取和防止過期
  • 2、使用TPL並行編程調用釘釘接口

需求詳解

公司前台有個大屏,領導想顯示全部員工的考勤結果統計情況和車間的實時監控視頻,還有車間的看板。簡單說就是把大屏分割成幾個區域。現在遇到的難題是釘釘獲取考勤結果的api是只有明細記錄,比如你公司1000人,那么可能回給你2000條考勤結果。分別是上班考勤和下班考勤的。沒有整個公司的,我就需要這么一條數據就行了。但人家沒有這樣的接口提供。卷起袖子,干!

趟坑過程

考勤打卡數據開放

業務場景

該接口僅限企業接入使用,用於返回企業內員工的實際打卡結果。比如,企業給一個員工設定的排班是上午9點和下午6點各打一次卡,即使員工在這期間打了多次,該接口也只會返回兩條記錄,包括上午的打卡結果和下午的打卡結果

考勤打卡數據開放

請求說明(ISV無調用權限)
如果你是ISV(應用服務商,將開發的應用上架到釘釘應用市場,提供給釘釘其他企業用戶使用),則無調用權限
如果你是企業內部開發者(將自己公司的HR、OA、客戶管理、業務管理等系統接入釘釘),有權限調用
2017-10-16更新:新增用戶userId列表參數(userIdList)和分頁參數(offset,limit),提升接口穩定性。

Https請求方式: POST

https://oapi.dingtalk.com/attendance/list?access_token=ACCESS_TOKEN

請求包結構體
1
2
3
4
5
6
7
{
     "workDateFrom" : "yyyy-MM-dd hh:mm:ss" ,
     "workDateTo" : "yyyy-MM-dd hh:mm:ss" ,
     "userIdList" :[ "員工UserId列表" ],    // 必填,與offset和limit配合使用,不傳表示分頁獲取全員的數據
     "offset" : 0 ,    // 必填,第一次傳0,如果還有多余數據,下次傳之前的offset加上limit的值
     "limit" : 1 ,     // 必填,表示數據條數,最大不能超過50條
}
參數說明

 

參數 參數類型 必須 說明
access_token String 調用接口憑證
workDateFrom String 查詢考勤打卡記錄的起始工作日
workDateTo String 查詢考勤打卡記錄的結束工作日
userIdList List 員工在企業內的UserID列表,企業用來唯一標識用戶的字段
offset Long 表示獲取考勤數據的起始點,第一次傳0,如果還有多余數據,下次獲取傳的offset值為之前的offset+limit
limit Long 表示獲取考勤數據的條數,最大不能超過50條

1)獲取AccessToken

釘釘的服務器很牛X可以並行訪問的。但是獲取回來的數據集有點亂,其中有個關於分頁的參數需要順序讀取,就是“hasMore”還有沒有下一頁。所以最終沒有使用TPL。

 

        /// <summary>
        /// 獲取AccessToken
        /// </summary>
        /// <returns></returns>
        private AccessToken GetAccessToken()
        {
            string URL_GetToken = "https://oapi.dingtalk.com/gettoken?corpid={0}&corpsecret={1}";
            string fileName = AppDomain.CurrentDomain.BaseDirectory + "AccessToken.xml";
            if (!System.IO.File.Exists(fileName))
            {
                string respon = Program.HttpGetRequest(string.Format(URL_GetToken, Program.CorpId, Program.CorpSecret));
                DingTalkRespond obj = JsonConvert.DeserializeObject<DingTalkRespond>(respon);
                if (obj != null && obj.errcode == 0)
                {
                    var result = new AccessToken
                    {
                        access_token = obj.access_token,
                        expires_in = GetCurrentTimeStamp()
                    };
                    SerializerHelper.SerializerToXML(fileName, result);
                    return result;
                }
                else
                    return new AccessToken
                    {
                        access_token = obj.access_token,
                        expires_in = GetCurrentTimeStamp()
                    };
            }
            else
            {
                var fileResult = SerializerHelper.LoadFromXML<AccessToken>(fileName);
                long ts = (GetCurrentTimeStamp() - fileResult.expires_in) / 1000;
                if (ts >= 7200)
                {
                    string respon = Program.HttpGetRequest(string.Format(URL_GetToken, Program.CorpId, Program.CorpSecret));
                    DingTalkRespond obj = JsonConvert.DeserializeObject<DingTalkRespond>(respon);
                    if (obj != null && obj.errcode == 0)
                    {
                        fileResult.access_token = obj.access_token;
                        fileResult.expires_in = GetCurrentTimeStamp();
                        SerializerHelper.SerializerToXML(fileName, fileResult);
                    }
                }
                return fileResult;
            }
        }

 

2)獲取企業總人數

 

/// <summary>
        /// 獲取公司總人數
        /// </summary>
        /// <returns></returns>
        private int GetFactoryEmployeeCount(AccessToken token)
        {
            int result = 0;
            string url = string.Format("https://oapi.dingtalk.com/user/get_org_user_count?access_token={0}&onlyActive=0", token.access_token);
            string jsonObj = Program.HttpGetRequest(url);
            var objResult = JsonConvert.DeserializeObject<DingTalkRespond>(jsonObj);
            if (objResult != null && objResult.errcode == 0)
                result = objResult.count;
            return result;
        }

 

3)獲取全體員工的考勤結果

 

  /// <summary>
        /// 獲取指定頁的考勤結果
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        private void GetAttendance(AccessToken token)
        {
            EmployeeAttendanceList.Clear();
            string url = string.Format("https://oapi.dingtalk.com/attendance/list?access_token={0}", token.access_token);
            int offset = 0;
            bool bHasMore = true;
            while (bHasMore)
            {
                var request = new AttendanceRequest
                {
                    workDateFrom = DateTime.Now.ToString("yyyy-MM-dd") + " 00:00:00",
                    workDateTo = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                    limit = 50,
                    userIdList = null,
                    offset = offset * 50
                };
                string jsonRequest = JsonConvert.SerializeObject(request).Replace("null", "[]");
                string jsonResult = Program.PostJsonData(url, jsonRequest);
                var objResult = JsonConvert.DeserializeObject<DingTalkRespond>(jsonResult);
                if (objResult != null && objResult.errcode == 0)
                {
                    foreach (var item in objResult.recordresult)
                    {
                        if (!EmployeeAttendanceList.Any(a => a.id == item.id))
                            EmployeeAttendanceList.Add(item);
                    }
                    offset++;
                    bHasMore = objResult.hasMore;
                }
                else
                    break;
            }
            EmployeeAttendanceList = EmployeeAttendanceList.Where(a => a.checkType == "OnDuty").OrderBy(e => e.id).ToList();
        }

 

 private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            AccessToken token = GetAccessToken();
            GetAttendance(token);
            var report = from q in EmployeeAttendanceList
                         group q by q.timeResult into g
                         select new AttendanceReportItemDTO
                         {
                             TimeResult = g.Key,
                             PersonNumber = g.Count()
                         };
            BulletinBoardInit();
            #region 考勤統計
            attendanceReport.Total = GetFactoryEmployeeCount(token);
            var normalObj = report.Where(p => p.TimeResult == "正常").FirstOrDefault();
            attendanceReport.Normal = normalObj == null ? 0 : normalObj.PersonNumber;
            var lateObj = report.Where(p => p.TimeResult == "遲到").FirstOrDefault();
            attendanceReport.Late = lateObj == null ? 0 : lateObj.PersonNumber;
            var earlyObj = report.Where(p => p.TimeResult == "早退").FirstOrDefault();
            attendanceReport.Early = earlyObj == null ? 0 : earlyObj.PersonNumber;
            var seriousLateObj = report.Where(p => p.TimeResult == "嚴重遲到").FirstOrDefault();
            attendanceReport.SeriousLate = seriousLateObj == null ? 0 : seriousLateObj.PersonNumber;
            var absenteeismObj = report.Where(p => p.TimeResult == "曠工").FirstOrDefault();
            attendanceReport.Absenteeism = absenteeismObj == null ? 0 : absenteeismObj.PersonNumber;
            int total_temp = report.Sum(p => p.PersonNumber);
            var notSignedObj = report.Where(p => p.TimeResult == "未打卡").FirstOrDefault();
            attendanceReport.NotSigned = notSignedObj == null ? 0 : notSignedObj.PersonNumber;
            attendanceReport.NotSigned = attendanceReport.NotSigned + (attendanceReport.Total - total_temp);
            #endregion 
            #region 判斷有沒有公告信息
            if (BulletinImages != null && BulletinImages.Length > 0)
            {
                if (BulletinImages.Length == 1)
                {
                    pbxNotity.Image = Image.FromFile(BulletinImages[0]);
                }
                if (BulletinImages.Length > 1)
                {
                    if (notifyShowIndex == BulletinImages.Length - 1)
                    {
                        notifyShowIndex = 0;
                    }
                    pbxNotity.Image = Image.FromFile(BulletinImages[notifyShowIndex]);
                    notifyShowIndex++;
                }
            }
            else
            {
                Action task = () =>
                {
                    BulletinBoardInit();
                };
                task.BeginInvoke(null, null);
                string dir = AppDomain.CurrentDomain.BaseDirectory + "公告欄圖片\\";
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                string[] bgFiles = Directory.GetFiles(dir);
                if (bgFiles != null && bgFiles.Length > 0)
                {
                    int imgIndex = rd.Next(bgFiles.Length);
                    pbxNotity.BackgroundImage = Image.FromFile(bgFiles[imgIndex]);
                }
            }
            #endregion 
        }

 

 

 

 

效果展示


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM