前言
最近小组需要统计部门各种请假次数,写了一个方法,第一次实战中用到递归函数,简单记录一下。
效果展示
这些数据不需要返回json,这里这样是为了方便测试。可以通过这些数据完成其它的操作。
功能实现
钉钉服务端调试工具API Explorer
感兴趣的可以在接口里面详细看一下参数,这里就不一 一解释了
定义model
请求参数
package model
type RequestDingLeave struct {
UseridList string `json:"userid_list"` // 待查询用户的ID列表,每次最多100个。
StartTime int `json:"start_time"` // 开始时间 ,Unix时间戳,支持最多180天的查询。
EndTime int `json:"end_time"` // 结束时间,Unix时间戳,支持最多180天的查询。
Offset int `json:"offset"` // 支持分页查询,与size参数同时设置时才生效,此参数代表偏移量,偏移量从0开始。
Size int `json:"size"` // 支持分页查询,与offset参数同时设置时才生效,此参数代表分页大小,最大20。
}
响应参数
package model
// DingLeaveStatus 请假状态
type DingLeaveStatus struct {
StartTime int64 `json:"start_time"`
DurationPercent int `json:"duration_percent"`
EndTime int64 `json:"end_time"`
LeaveCode string `json:"leave_code"` // 请假类型 个人事假:d4edf257-e581-45f9-b9b9-35755b598952 非个人事假:baf811bc-3daa-4988-9604-d68ec1edaf50 病假:a7ffa2e6-872a-498d-aca7-4554c56fbb52
DurationUnit string `json:"duration_unit"`
UserID string `json:"userid"`
}
// DingLeaveResult 请假列表
type DingLeaveResult struct {
LeaveStatus *[]DingLeaveStatus `json:"leave_status"`
HasMore bool `json:"has_more"` // 是否有更多数据
}
// DingResponse 钉钉响应
type DingResponse struct {
ErrCode int `json:"errcode"`
Result DingLeaveResult `json:"result"`
Success bool `json:"success"`
ErrMsg string `json:"errmsg"`
RequestID string `json:"request_id"`
}
type DingUser struct {
Id string `json:"id"`
Name string `json:"name"`
Type map[string]int
}
功能逻辑
我这里只是想简单的实现一下功能,并没有按照严格标准的mvc分层,还请见谅
package controller
import (
"bytes"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"leave/model"
"net/http"
"time"
)
var tmp = map[string]string{"d4edf257-e581-45f9-b9b9-35755b598952": "个人事假", "a7ffa2e6-872a-498d-aca7-4554c56fbb52": "病假", "baf811bc-3daa-4988-9604-d68ec1edaf50": "非个人事假"} // code与请假类型对应
// GetDepartmentLeaveStatus 统计部门请假状态
func GetDepartmentLeaveStatus(c *gin.Context) {
userList := "323832232226246897,01320463195324064909,02280849645326263552,01546916272226288917" // 模拟数据
leave := model.RequestDingLeave{
UseridList: userList,
StartTime: 1698624000000,
EndTime: int(time.Now().UnixMilli()), // 拿到当前的时间戳
Offset: 0,
Size: 2,
}
res := []model.DingLeaveStatus{}
res, err := GetLeaveStatus(leave, res)
if err != nil {
return
}
statistics := map[string]model.DingUser{}
for _, v := range res {
_, exist := statistics[v.UserID]
if !exist {
statistics[v.UserID] = model.DingUser{Type: map[string]int{}}
}
statistics[v.UserID].Type[tmp[v.LeaveCode]]++
}
c.JSON(http.StatusOK, statistics)
fmt.Println(int(time.Now().Weekday()))
return
}
// GetLeaveStatus 获取请假状态
func GetLeaveStatus(leave model.RequestDingLeave, res []model.DingLeaveStatus) ([]model.DingLeaveStatus, error) {
// 将json数据编码为字节数组
var send func(leave model.RequestDingLeave) error
// 切片作为函数参数传递时为值传递,如果每次传入新的切片需要增加返回值接收,这里直接使用的传入的res作为变量并返回
send = func(leave model.RequestDingLeave) error {
jsonLeave, err := json.Marshal(leave)
if err != nil {
fmt.Println("json.Marshal(leave) failed:", err)
return err
}
url := fmt.Sprintf("https://oapi.dingtalk.com/topapi/attendance/getleavestatus?%s", "access_token=企业token") // access_token 填企业token
buffer := bytes.NewBuffer(jsonLeave)
response, err := http.Post(url, "application/json", buffer)
if err != nil {
fmt.Println("http.Post(\"https://oapi.dingtalk.com/topapi/attendance/getleavestatus\", \"application/json\", buffer) failed:", err)
return err
}
var dingResp model.DingResponse
err = json.NewDecoder(response.Body).Decode(&dingResp) // 将响应的json绑定到dingResp中
if err != nil {
return err
}
res = append(res, *dingResp.Result.LeaveStatus...)
if dingResp.Result.HasMore { // 如果有更多的记录,再次请求并添加到切片后面
leave.Offset += leave.Size
send(leave) // 递归
}
return nil
}
err := send(leave)
return res, err
}
其他
package router
import (
"github.com/gin-gonic/gin"
"leave/controller"
)
func SetupRouter() *gin.Engine {
r := gin.Default()
r.GET("/test", controller.GetDepartmentLeaveStatus)
return r
}
package main
import "leave/router"
func main() {
router := router.SetupRouter()
router.Run()
}