dingtalk_oa.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. package cmd
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "strings"
  8. )
  9. type DingTalkConf struct {
  10. AppKey string
  11. AppSecret string
  12. GetTokenUrl string
  13. GetHolidayTypeURL string
  14. GetDeptListUrl string
  15. GetDeptUserListUrl string
  16. GetAttendanceGroupUrl string
  17. GetAttendanceGroupUserIdsUrl string
  18. GetAttendanceClockDataUrl string
  19. GetAttendanceGroupDetailsUrl string
  20. ListAttendanceGroupMenberListByIdsUrl string
  21. Token string
  22. Params map[string]string
  23. Headers map[string]string
  24. Cookie []*http.Cookie
  25. DeptId int64
  26. OpUserId string
  27. ManageGroupId int64
  28. EmployeeGroupId int64
  29. }
  30. // @title GetToken
  31. // @description 获取access token
  32. // @param
  33. // @return
  34. func (m *DingTalkConf) GetToken() error {
  35. params := map[string]string{"appkey": m.AppKey, "appsecret": m.AppSecret}
  36. content, err := GetX(m.GetTokenUrl, "", params, m.Headers, m.Cookie)
  37. if err != nil {
  38. log.Printf("GetToken error : %v", err)
  39. }
  40. fmt.Printf("%v\n", content)
  41. ret := map[string]interface{}{}
  42. err = json.Unmarshal([]byte(content), &ret)
  43. if err != nil {
  44. log.Printf("Unmarshal error : %v", err)
  45. return err
  46. }
  47. m.Token = ret["access_token"].(string)
  48. m.Params["access_token"] = ret["access_token"].(string)
  49. m.Headers["Content-Type"] = "application/json"
  50. return nil
  51. }
  52. func (m *DingTalkConf) GetHolidayType() (err error) {
  53. result := map[string]string{}
  54. PostData := make(map[string]interface{})
  55. PostData["op_userid"] = m.OpUserId
  56. PostData["vacation_source"] = "all"
  57. fmt.Printf("postdata=======>%v\n", PostData)
  58. content, err := PostJson(m.GetHolidayTypeURL, m.Params, m.Headers, PostData, m.Cookie)
  59. if err != nil {
  60. log.Printf("GetDeptUserList PostJson error : %v", err)
  61. return err
  62. }
  63. ret := map[string]interface{}{}
  64. err = json.Unmarshal([]byte(content), &ret)
  65. if err != nil {
  66. log.Printf("Unmarshal error : %v", err)
  67. return err
  68. }
  69. holidatTypes := ret["result"].([]interface{})
  70. for _, holidatType := range holidatTypes {
  71. result[holidatType.(map[string]interface{})["leave_name"].(string)] = holidatType.(map[string]interface{})["leave_code"].(string)
  72. }
  73. fmt.Printf("ret===>%v\n", ret)
  74. return
  75. }
  76. // @title GetDeptList
  77. // @description 获取部门列表,只支持查询下一级子部门 https://developers.dingtalk.com/document/app/obtain-the-department-list-v2
  78. // @param
  79. // @return
  80. func (m *DingTalkConf) GetDeptList(deptId int64) ([]interface{}, error) {
  81. result := []interface{}{}
  82. PostData := make(map[string]interface{})
  83. PostData["dept_id"] = deptId
  84. content, err := PostJson(m.GetDeptListUrl, m.Params, m.Headers, PostData, m.Cookie)
  85. if err != nil {
  86. log.Printf("GetDeptUserList PostJson error : %v", err)
  87. return result, err
  88. }
  89. ret := map[string]interface{}{}
  90. err = json.Unmarshal([]byte(content), &ret)
  91. if err != nil {
  92. log.Printf("Unmarshal error : %v", err)
  93. return result, err
  94. }
  95. //fmt.Printf("ret===>%v\n", ret)
  96. result = ret["result"].([]interface{})
  97. /*
  98. {
  99. "errcode": 0,
  100. "errmsg":"ok",
  101. "result": [
  102. {
  103. "auto_add_user": true,
  104. "create_dept_group": true,
  105. "dept_id": 37xxxx95,
  106. "name": "市场部",
  107. "parent_id": 1
  108. },
  109. {
  110. "auto_add_user": true,
  111. "create_dept_group": true,
  112. "dept_id": 399xxxx96,
  113. "name": "财务部",
  114. "parent_id": 1
  115. }
  116. ],
  117. "request_id": "5um7ykyaalsj"
  118. }
  119. */
  120. return result, nil
  121. }
  122. // @title GetDeptUserList
  123. // @description 获取部门成员的姓名和userid https://developers.dingtalk.com/document/app/queries-the-simple-information-of-a-department-user
  124. // @param
  125. // @return
  126. func (m *DingTalkConf) GetDeptUserList(deptId int64) (map[string]string, error) {
  127. cursor := 0.0
  128. size := 100
  129. PostData := make(map[string]interface{})
  130. PostData["dept_id"] = deptId
  131. PostData["size"] = size
  132. deptUserList := make(map[string]string)
  133. //外层循环,翻页
  134. for {
  135. PostData["cursor"] = cursor
  136. //fmt.Printf("%v\n", cursor)
  137. //请求APi
  138. content, err := PostJson(m.GetDeptUserListUrl, m.Params, m.Headers, PostData, m.Cookie)
  139. if err != nil {
  140. log.Printf("GetDeptUserList PostJson error : %v", err)
  141. }
  142. ret := map[string]interface{}{}
  143. err = json.Unmarshal([]byte(content), &ret)
  144. if err != nil {
  145. log.Printf("Unmarshal error : %v", err)
  146. }
  147. /*
  148. {
  149. "errcode": 0,
  150. "errmsg": "ok",
  151. "result": {
  152. "has_more": false,
  153. "list": [
  154. {
  155. "name": "测试用户2",
  156. "userid": "user100"
  157. },
  158. {
  159. "name": "李思",
  160. "userid": "user1"
  161. }
  162. ]
  163. },
  164. "request_id": "x4p6arvi0fzj"
  165. }
  166. */
  167. result := ret["result"]
  168. //遍历用户信息list
  169. for _, i := range result.(map[string]interface{})["list"].([]interface{}) {
  170. deptUserList[i.(map[string]interface{})["userid"].(string)] = i.(map[string]interface{})["name"].(string)
  171. }
  172. //当前请求返回数据量小于size,跳出循环
  173. if len(result.(map[string]interface{})["list"].([]interface{})) < size {
  174. break
  175. }
  176. if result.(map[string]interface{})["next_cursor"] == nil {
  177. break
  178. }
  179. cursor = result.(map[string]interface{})["next_cursor"].(float64)
  180. }
  181. return deptUserList, nil
  182. }
  183. // @title GetAttendanceGroup
  184. // @description 批量获取考勤组摘要 https://developers.dingtalk.com/document/app/batch-query-of-simple-information-of-the-attendance-group
  185. // @param
  186. // @return
  187. func (m *DingTalkConf) GetAttendanceGroup() ([]map[string]interface{}, error) {
  188. groupData := []map[string]interface{}{}
  189. PostData := make(map[string]interface{})
  190. cursor := 1
  191. PostData["op_user_id"] = m.OpUserId
  192. PostData["cursor"] = cursor
  193. content, err := PostJson(m.GetAttendanceGroupUrl, m.Params, m.Headers, PostData, m.Cookie)
  194. if err != nil {
  195. log.Printf("GetAttendanceClockData PostJson error : %v", err)
  196. return groupData, err
  197. }
  198. ret := map[string]interface{}{}
  199. err = json.Unmarshal([]byte(content), &ret)
  200. if err != nil {
  201. log.Printf("Unmarshal error : %v", err)
  202. return groupData, err
  203. }
  204. /*
  205. {
  206. "errcode": 0,
  207. "result": {
  208. "cursor": 685935028,
  209. "has_more": false,
  210. "result": [
  211. {
  212. "id": 677765054,
  213. "name": "周末加班"
  214. },
  215. {
  216. "id": 685935028,
  217. "name": "考勤"
  218. }
  219. ]
  220. },
  221. "success": true,
  222. "request_id": "wv9973jntamw"
  223. }
  224. */
  225. //fmt.Printf("%v\n", ret)
  226. result := ret["result"]
  227. for _, group := range result.(map[string]interface{})["result"].([]interface{}) {
  228. group_id := int64(group.(map[string]interface{})["id"].(float64))
  229. group_name := group.(map[string]interface{})["name"].(string)
  230. groupData = append(groupData, map[string]interface{}{"group_id": group_id, "group_name": group_name})
  231. }
  232. return groupData, err
  233. }
  234. // @title GetAttendanceClockData
  235. // @description 获取7天内的指定时间段成员的打卡记录, https://developers.dingtalk.com/document/app/open-attendance-clock-in-data
  236. // @param days获取多少天内的考勤数据
  237. // @return
  238. func (m *DingTalkConf) GetAttendanceClockData(days int, userIdList []string) (map[string][]int, error) {
  239. limit := 50 //表示获取考勤数据的条数,最大不能超过50条。
  240. userIdStep := 50 //单次请求传入的userId数量
  241. //最近30天日期数组
  242. workData, _ := GetWorkDate(days)
  243. fmt.Printf("workData lenght %v\n", len(workData))
  244. //post请求的body
  245. PostData := make(map[string]interface{})
  246. PostData["dept_id"] = m.DeptId
  247. PostData["limit"] = limit
  248. //当前部门每个人的考勤数据
  249. attendanceData := make(map[string][]int)
  250. userIdIndex := 0
  251. //userId的遍历
  252. for {
  253. if userIdIndex+1 > len(userIdList) {
  254. break
  255. }
  256. fmt.Printf("=================第%v位至第%v位user开始遍历\n", userIdIndex+1, userIdIndex+userIdStep)
  257. if userIdIndex+userIdStep > len(userIdList) {
  258. PostData["userIdList"] = userIdList[userIdIndex+1:]
  259. } else {
  260. PostData["userIdList"] = userIdList[userIdIndex+1 : userIdIndex+userIdStep]
  261. }
  262. //外面的for是日期遍历,间隔6天
  263. date := 0
  264. dateStep := 6
  265. for {
  266. if date >= len(workData) {
  267. break
  268. }
  269. fmt.Printf("---------------%v开始的考勤\n", workData[date+1])
  270. fmt.Printf("date==>%v\n", date+1)
  271. splits := strings.Split(workData[date+1], "/")
  272. PostData["workDateFrom"] = fmt.Sprintf("%s-%s-%s 00:00:00", splits[0], splits[1], splits[2])
  273. if date+1+dateStep < len(workData) {
  274. splits = strings.Split(workData[date+1+dateStep], "/")
  275. } else {
  276. splits = strings.Split(workData[len(workData)-1], "/")
  277. }
  278. PostData["workDateTo"] = fmt.Sprintf("%s-%s-%s 00:00:00", splits[0], splits[1], splits[2])
  279. //分页遍历
  280. offset := 0 //获取考勤数据的起始点。第一次传0,如果还有多余数据,下次获取传的offset值为之前的offset+limit,
  281. for {
  282. fmt.Printf("---------------从%v条到%v条的数据\n", offset, offset+limit)
  283. PostData["offset"] = offset
  284. //fmt.Printf("offset %v\n", offset)
  285. //fmt.Printf("data %v\n", data)
  286. content, err := PostJson(m.GetAttendanceClockDataUrl, m.Params, m.Headers, PostData, m.Cookie)
  287. if err != nil {
  288. log.Printf("GetAttendanceClockData PostJson error : %v", err)
  289. }
  290. ret := map[string]interface{}{}
  291. err = json.Unmarshal([]byte(content), &ret)
  292. if err != nil {
  293. log.Printf("Unmarshal error : %v", err)
  294. }
  295. //fmt.Printf("%v\n", ret)
  296. //开始解析本次请求的考勤数据,添加到attendanceData
  297. for _, i := range ret["recordresult"].([]interface{}) {
  298. userId := i.(map[string]interface{})["userId"].(string)
  299. userCheckTime := i.(map[string]interface{})["userCheckTime"].(float64)
  300. //把考勤数据加到个人的slice里
  301. attendanceData[userId] = append(attendanceData[userId], int(userCheckTime))
  302. }
  303. //当前请求返回数据量小于size,跳出循环
  304. if len(ret["recordresult"].([]interface{})) < limit {
  305. break
  306. }
  307. offset += limit
  308. //time.Sleep(1*time.Second)
  309. }
  310. date += dateStep
  311. }
  312. userIdIndex += userIdStep
  313. }
  314. return attendanceData, nil
  315. }
  316. // @title GetAttendanceGroupDetails
  317. // @description 获取考勤组列表, https://developers.dingtalk.com/document/app/queries-attendance-group-list-details
  318. // @param
  319. // @return map[5.5天制管理人员:753150009 5天制:761355305 6天制员工:667040040 合肥1:721640063 合肥6天制:795345194 清洁:854690013 音乐:761855162]
  320. func (m *DingTalkConf) GetAttendanceGroupDetails() (map[int64]string, error) {
  321. PostData := make(map[string]interface{})
  322. PostData["offset"] = 0
  323. PostData["size"] = 10
  324. content, err := PostJson(m.GetAttendanceGroupDetailsUrl, m.Params, m.Headers, PostData, m.Cookie)
  325. if err != nil {
  326. log.Printf("GetAttendanceClockData PostJson error : %v", err)
  327. }
  328. ret := map[string]interface{}{}
  329. err = json.Unmarshal([]byte(content), &ret)
  330. if err != nil {
  331. log.Printf("Unmarshal error : %v", err)
  332. }
  333. attendaceGroups := make(map[int64]string)
  334. groups := ret["result"].(map[string]interface{})["groups"]
  335. for _, i := range groups.([]interface{}) {
  336. attendaceGroups[int64(i.(map[string]interface{})["group_id"].(float64))] = i.(map[string]interface{})["group_name"].(string)
  337. }
  338. return attendaceGroups, nil
  339. }
  340. // @title ListAttendanceGroupMenberListByIds
  341. // @description 考勤组成员校验 , https://developers.dingtalk.com/document/app/query-members-by-id
  342. // @param
  343. // @return
  344. func (m *DingTalkConf) ListAttendanceGroupMenberListByIds(groupId int64, userIdList []string) ([]string, error) {
  345. PostData := make(map[string]interface{})
  346. PostData["op_user_id"] = m.OpUserId
  347. PostData["group_id"] = groupId
  348. userids := strings.Join(userIdList, ",")
  349. //fmt.Printf("userids=======>%v\n", userids)
  350. PostData["member_ids"] = userids
  351. PostData["member_type"] = 0
  352. content, err := PostJson(m.ListAttendanceGroupMenberListByIdsUrl, m.Params, m.Headers, PostData, m.Cookie)
  353. if err != nil {
  354. log.Printf("GetAttendanceClockData PostJson error : %v", err)
  355. }
  356. ret := map[string]interface{}{}
  357. err = json.Unmarshal([]byte(content), &ret)
  358. if err != nil {
  359. log.Printf("Unmarshal error : %v", err)
  360. }
  361. //fmt.Printf("%v\n", ret)
  362. userIds := []string{}
  363. for _, i := range ret["result"].([]interface{}) {
  364. userIds = append(userIds, i.(string))
  365. }
  366. return userIds, nil
  367. }