dingtalk_oa.go 12 KB

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