package xnet import ( "encoding/json" "fmt" "gcore/core" "gcore/xnet" "log" "net/http" "strings" ) type DevConf struct { AppKey string AppSecret string GetTokenUrl string GetDeptListUrl string GetDeptUserListUrl string GetAttendanceGroupUrl string GetAttendanceGroupUserIdsUrl string GetAttendanceClockDataUrl string GetAttendanceGroupDetailsUrl string ListAttendanceGroupMenberListByIdsUrl string Token string Params map[string]string Headers map[string]string Cookie []*http.Cookie DeptId int64 OpUserId int64 ManageGroupId int64 EmployeeGroupId int64 } // @title GetToken // @description 获取access token // @param // @return func (m *DevConf) GetToken() error { params := map[string]string{"appkey": m.AppKey, "appsecret": m.AppSecret} content, err := xnet.GetX(m.GetTokenUrl, params, m.Headers, m.Cookie) if err != nil { log.Printf("GetToken error : %v", err) } //fmt.Printf("%v\n", content) ret := map[string]interface{}{} err = json.Unmarshal([]byte(content), &ret) if err != nil { log.Printf("Unmarshal error : %v", err) return err } m.Token = ret["access_token"].(string) m.Params["access_token"] = ret["access_token"].(string) m.Headers["Content-Type"] = "application/json" return nil } // @title GetDeptList // @description 获取部门列表,只支持查询下一级子部门 https://developers.dingtalk.com/document/app/obtain-the-department-list-v2 // @param // @return func (m *DevConf) GetDeptList(deptId int64) ([]interface{}, error) { result := []interface{}{} PostData := make(map[string]interface{}) PostData["dept_id"] = deptId content, err := xnet.PostJson(m.GetDeptListUrl, m.Params, m.Headers, PostData, m.Cookie) if err != nil { log.Printf("GetDeptUserList PostJson error : %v", err) return result, err } ret := map[string]interface{}{} err = json.Unmarshal([]byte(content), &ret) if err != nil { log.Printf("Unmarshal error : %v", err) return result, err } //fmt.Printf("ret===>%v\n", ret) result = ret["result"].([]interface{}) /* { "errcode": 0, "errmsg":"ok", "result": [ { "auto_add_user": true, "create_dept_group": true, "dept_id": 37xxxx95, "name": "市场部", "parent_id": 1 }, { "auto_add_user": true, "create_dept_group": true, "dept_id": 399xxxx96, "name": "财务部", "parent_id": 1 } ], "request_id": "5um7ykyaalsj" } */ return result, nil } // @title GetDeptUserList // @description 获取部门成员的姓名和userid https://developers.dingtalk.com/document/app/queries-the-simple-information-of-a-department-user // @param // @return func (m *DevConf) GetDeptUserList(deptId int64) (map[string]string, error) { cursor := 0.0 size := 100 PostData := make(map[string]interface{}) PostData["dept_id"] = deptId PostData["size"] = size deptUserList := make(map[string]string) //外层循环,翻页 for { PostData["cursor"] = cursor //fmt.Printf("%v\n", cursor) //请求APi content, err := xnet.PostJson(m.GetDeptUserListUrl, m.Params, m.Headers, PostData, m.Cookie) if err != nil { log.Printf("GetDeptUserList PostJson error : %v", err) } ret := map[string]interface{}{} err = json.Unmarshal([]byte(content), &ret) if err != nil { log.Printf("Unmarshal error : %v", err) } /* { "errcode": 0, "errmsg": "ok", "result": { "has_more": false, "list": [ { "name": "测试用户2", "userid": "user100" }, { "name": "李思", "userid": "user1" } ] }, "request_id": "x4p6arvi0fzj" } */ result := ret["result"] //遍历用户信息list for _, i := range result.(map[string]interface{})["list"].([]interface{}) { deptUserList[i.(map[string]interface{})["userid"].(string)] = i.(map[string]interface{})["name"].(string) } //当前请求返回数据量小于size,跳出循环 if len(result.(map[string]interface{})["list"].([]interface{})) < size { break } if result.(map[string]interface{})["next_cursor"] == nil { break } cursor = result.(map[string]interface{})["next_cursor"].(float64) } return deptUserList, nil } // @title GetAttendanceGroup // @description 批量获取考勤组摘要 https://developers.dingtalk.com/document/app/batch-query-of-simple-information-of-the-attendance-group // @param // @return func (m *DevConf) GetAttendanceGroup() ([]map[string]interface{}, error) { groupData := []map[string]interface{}{} PostData := make(map[string]interface{}) cursor := 1 PostData["op_user_id"] = m.OpUserId PostData["cursor"] = cursor content, err := xnet.PostJson(m.GetAttendanceGroupUrl, m.Params, m.Headers, PostData, m.Cookie) if err != nil { log.Printf("GetAttendanceClockData PostJson error : %v", err) return groupData, err } ret := map[string]interface{}{} err = json.Unmarshal([]byte(content), &ret) if err != nil { log.Printf("Unmarshal error : %v", err) return groupData, err } /* { "errcode": 0, "result": { "cursor": 685935028, "has_more": false, "result": [ { "id": 677765054, "name": "周末加班" }, { "id": 685935028, "name": "考勤" } ] }, "success": true, "request_id": "wv9973jntamw" } */ //fmt.Printf("%v\n", ret) result := ret["result"] for _, group := range result.(map[string]interface{})["result"].([]interface{}) { group_id := int64(group.(map[string]interface{})["id"].(float64)) group_name := group.(map[string]interface{})["name"].(string) groupData = append(groupData, map[string]interface{}{"group_id": group_id, "group_name": group_name}) } return groupData, err } // @title GetAttendanceClockData // @description 获取7天内的指定时间段成员的打卡记录, https://developers.dingtalk.com/document/app/open-attendance-clock-in-data // @param days获取多少天内的考勤数据 // @return func (m *DevConf) GetAttendanceClockData(days int, userIdList []string) (map[string][]int, error) { limit := 50 //表示获取考勤数据的条数,最大不能超过50条。 userIdStep := 50 //单次请求传入的userId数量 //最近30天日期数组 workData, _ := core.GetWorkDate(days) fmt.Printf("workData lenght %v\n", len(workData)) //post请求的body PostData := make(map[string]interface{}) PostData["dept_id"] = m.DeptId PostData["limit"] = limit //当前部门每个人的考勤数据 attendanceData := make(map[string][]int) userIdIndex := 0 //userId的遍历 for { if userIdIndex+1 > len(userIdList) { break } fmt.Printf("=================第%v位至第%v位user开始遍历\n", userIdIndex+1, userIdIndex+userIdStep) if userIdIndex+userIdStep > len(userIdList) { PostData["userIdList"] = userIdList[userIdIndex+1:] } else { PostData["userIdList"] = userIdList[userIdIndex+1 : userIdIndex+userIdStep] } //外面的for是日期遍历,间隔6天 date := 0 dateStep := 6 for { if date >= len(workData) { break } fmt.Printf("---------------%v开始的考勤\n", workData[date+1]) fmt.Printf("date==>%v\n", date+1) splits := strings.Split(workData[date+1], "/") PostData["workDateFrom"] = fmt.Sprintf("%s-%s-%s 00:00:00", splits[0], splits[1], splits[2]) if date+1+dateStep < len(workData) { splits = strings.Split(workData[date+1+dateStep], "/") } else { splits = strings.Split(workData[len(workData)-1], "/") } PostData["workDateTo"] = fmt.Sprintf("%s-%s-%s 00:00:00", splits[0], splits[1], splits[2]) //分页遍历 offset := 0 //获取考勤数据的起始点。第一次传0,如果还有多余数据,下次获取传的offset值为之前的offset+limit, for { fmt.Printf("---------------从%v条到%v条的数据\n", offset, offset+limit) PostData["offset"] = offset //fmt.Printf("offset %v\n", offset) //fmt.Printf("data %v\n", data) content, err := xnet.PostJson(m.GetAttendanceClockDataUrl, m.Params, m.Headers, PostData, m.Cookie) if err != nil { log.Printf("GetAttendanceClockData PostJson error : %v", err) } ret := map[string]interface{}{} err = json.Unmarshal([]byte(content), &ret) if err != nil { log.Printf("Unmarshal error : %v", err) } //fmt.Printf("%v\n", ret) //开始解析本次请求的考勤数据,添加到attendanceData for _, i := range ret["recordresult"].([]interface{}) { userId := i.(map[string]interface{})["userId"].(string) userCheckTime := i.(map[string]interface{})["userCheckTime"].(float64) //把考勤数据加到个人的slice里 attendanceData[userId] = append(attendanceData[userId], int(userCheckTime)) } //当前请求返回数据量小于size,跳出循环 if len(ret["recordresult"].([]interface{})) < limit { break } offset += limit //time.Sleep(1*time.Second) } date += dateStep } userIdIndex += userIdStep } return attendanceData, nil } // @title GetAttendanceGroupDetails // @description 获取考勤组列表, https://developers.dingtalk.com/document/app/queries-attendance-group-list-details // @param // @return map[5.5天制管理人员:753150009 5天制:761355305 6天制员工:667040040 合肥1:721640063 合肥6天制:795345194 清洁:854690013 音乐:761855162] func (m *DevConf) GetAttendanceGroupDetails() (map[int64]string, error) { PostData := make(map[string]interface{}) PostData["offset"] = 0 PostData["size"] = 10 content, err := xnet.PostJson(m.GetAttendanceGroupDetailsUrl, m.Params, m.Headers, PostData, m.Cookie) if err != nil { log.Printf("GetAttendanceClockData PostJson error : %v", err) } ret := map[string]interface{}{} err = json.Unmarshal([]byte(content), &ret) if err != nil { log.Printf("Unmarshal error : %v", err) } attendaceGroups := make(map[int64]string) groups := ret["result"].(map[string]interface{})["groups"] for _, i := range groups.([]interface{}) { attendaceGroups[int64(i.(map[string]interface{})["group_id"].(float64))] = i.(map[string]interface{})["group_name"].(string) } return attendaceGroups, nil } // @title ListAttendanceGroupMenberListByIds // @description 考勤组成员校验 , https://developers.dingtalk.com/document/app/query-members-by-id // @param // @return func (m *DevConf) ListAttendanceGroupMenberListByIds(groupId int64, userIdList []string) ([]string, error) { PostData := make(map[string]interface{}) PostData["op_user_id"] = m.OpUserId PostData["group_id"] = groupId userids := strings.Join(userIdList, ",") //fmt.Printf("userids=======>%v\n", userids) PostData["member_ids"] = userids PostData["member_type"] = 0 content, err := xnet.PostJson(m.ListAttendanceGroupMenberListByIdsUrl, m.Params, m.Headers, PostData, m.Cookie) if err != nil { log.Printf("GetAttendanceClockData PostJson error : %v", err) } ret := map[string]interface{}{} err = json.Unmarshal([]byte(content), &ret) if err != nil { log.Printf("Unmarshal error : %v", err) } //fmt.Printf("%v\n", ret) userIds := []string{} for _, i := range ret["result"].([]interface{}) { userIds = append(userIds, i.(string)) } return userIds, nil }