dingtalk_oa.go 12 KB

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