commit 6274873ecdafebcdede1bb5fdd2db883fa38577f Author: Your Name Date: Sun Jul 21 02:13:35 2024 +0800 first diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..83eb8ba --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/udesk.iml b/.idea/udesk.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/udesk.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7d30d9f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM alpine:latest +ENV TZ=Asia/Shanghai +USER root + +# 合并复制指令 +COPY udeskstate /usr/local/bin/ \ +./*.json /conf/ + +# 设置执行权限 +RUN chmod +x /usr/local/bin/udeskstate + +# ENTRYPOINT 指令只有一条,已经是最优 +ENTRYPOINT ["udeskstate"] \ No newline at end of file diff --git a/email.json b/email.json new file mode 100644 index 0000000..3eb9939 --- /dev/null +++ b/email.json @@ -0,0 +1,18 @@ +{ + "吴彬": "binwu@alauda.io", + "冯浪": "langfeng@alauda.io", + "李斌": "binli@alauda.io", + "杨学成": "xcyang@alauda.io", + "罗舒文": "swluo@alauda.io", + "杨慧": "huiyang1@alauda.io", + "吴舒汀": "stwu@alauda.io", + "王硕": "shuowang@alauda.io", + "崔星林": "xlcui@alauda.io", + "孙嘉彤": "jtsun@alauda.io", + "王奥": "aowang@alauda.io", + "霍佳琦": "jqhuo@alauda.io", + "王培伦": "plwang@alauda.io", + "李晓升": "xsli@alauda.io", + "孙凯": "kaisun@alauda.io", + "王杭渝": "hywang@alauda.io" +} \ No newline at end of file diff --git a/exceldeal/exceldeal.go b/exceldeal/exceldeal.go new file mode 100644 index 0000000..6f7d935 --- /dev/null +++ b/exceldeal/exceldeal.go @@ -0,0 +1,125 @@ +package exceldeal + +import ( + "encoding/json" + "github.com/xuri/excelize/v2" + "log" + "os" + "strings" + "time" +) + +var nowMouth = time.Now().Month().String() +var nowDay = time.Now().Day() +var M = dateToChinese(nowMouth) + +func JsonDeal(file string, remindList []string, closeList []string) (r, c []string) { + emailJson, err := os.ReadFile(file) + if err != nil { + log.Printf("打开邮箱json文件失败,错误是:%v\n", err) + return + } + var email map[string]string + err = json.Unmarshal(emailJson, &email) + if err != nil { + log.Printf("json反序列化失败:%v\n", err) + return nil, nil + } + + for k, v := range email { + for _, m := range remindList { + if k == m { + r = append(r, v) + } + } + for _, m := range closeList { + if k == m { + c = append(c, v) + } + } + + } + + return r, c +} + +// 寻找当前月的值班表,并且得到应该提醒的传值和关闭的传值 + +func GetSheetName(file string) (remindList, closeList []string, err error) { + f, err := excelize.OpenFile(file) + if err != nil { + return + } + defer f.Close() + //遍历所有工作表的A2格 + sheets := f.GetSheetMap() + var sheetName string + for _, s := range sheets { + //// 读取A2单元格的值 + a2value, err := f.GetCellValue(s, "A2") + if err != nil { + log.Println(err) + return nil, nil, err + } + //检查月份是否与当前月份相等 + //如果与当前时间的月份相等则记录工作表名称 + if a2value == M { + sheetName = s + } + } + rows, _ := f.GetRows(sheetName) + for i, row := range rows { + log.Printf("按行读取excel中的值:索引:%v,行值:%v\n", i, row) + if i == nowDay { + nowRow := cleanSlice(row) + remindList = append(remindList, nowRow[2], nowRow[3]) + + } else if i == nowDay-1 { + yesterdayRow := cleanSlice(row) + closeList = append(closeList, yesterdayRow[2], yesterdayRow[3]) + } + } + + return remindList, closeList, nil + +} + +func dateToChinese(m string) (M string) { + switch m { + case "January": + M = "一月" + case "February": + M = "二月" + case "March": + M = "三月" + case "April": + M = "四月" + case "May": + M = "五月" + case "June": + M = "六月" + case "July": + M = "七月" + case "August": + M = "八月" + case "September": + M = "九月" + case "October": + M = "十月" + case "November": + M = "十一月" + case "December": + M = "十二月" + } + return M +} + +func cleanSlice(strSlice []string) (cleanedSlice []string) { + for _, s := range strSlice { + cleaned := strings.TrimSpace(s) + if cleaned != "" { + cleanedSlice = append(cleanedSlice, cleaned) + } + } + return cleanedSlice +} diff --git a/exceldeal/notify.go b/exceldeal/notify.go new file mode 100644 index 0000000..a91d277 --- /dev/null +++ b/exceldeal/notify.go @@ -0,0 +1,56 @@ +package exceldeal + +import ( + "bytes" + "encoding/json" + "fmt" + "log" + "net/http" + "os" +) + +var webhookURL = getWebhook() + +type webHook struct { + WebHookURL string `json:"webhook"` +} + +func getWebhook() string { + wb, err := os.ReadFile("./wechatwebhook.json") + fmt.Println(string(wb)) + if err != nil { + log.Printf("打开webhook文件失败:%v\n", err) + return "" + } + var webhook webHook + err = json.Unmarshal(wb, &webhook) + if err != nil { + log.Printf("webhook config 反序列化失败: %v\n", err) + return "" + } + hook := webhook.WebHookURL + return hook +} + +func Send(repContent string) { + // 替换为你的企业微信机器人Webhook URL + + // 创建消息体 + requestBody := []byte(`{ + "msgtype": "text", + "text": { + "content": "` + repContent + `" + } + }`) + + // 发送HTTP POST请求到企业微信机器人Webhook + resp, err := http.Post(webhookURL, "application/json", bytes.NewBuffer(requestBody)) + if err != nil { + log.Fatalf("发送消息失败: %v", err) + return + } + defer resp.Body.Close() + + log.Println("发送企业微信机器人成功!") + +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..12c8f17 --- /dev/null +++ b/go.mod @@ -0,0 +1,17 @@ +module udesk + +go 1.22 + +require ( + github.com/google/uuid v1.6.0 // indirect + github.com/jasonlvhit/gocron v0.0.1 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/richardlehane/mscfb v1.0.4 // indirect + github.com/richardlehane/msoleps v1.0.3 // indirect + github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect + github.com/xuri/excelize/v2 v2.8.1 // indirect + github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/text v0.16.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ce06a91 --- /dev/null +++ b/go.sum @@ -0,0 +1,48 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jasonlvhit/gocron v0.0.1 h1:qTt5qF3b3srDjeOIR4Le1LfeyvoYzJlYpqvG7tJX5YU= +github.com/jasonlvhit/gocron v0.0.1/go.mod h1:k9a3TV8VcU73XZxfVHCHWMWF9SOqgoku0/QlY2yvlA4= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= +github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= +github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM= +github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7psK/lVsjIS2otl+1WyRyY= +github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= +github.com/xuri/excelize/v2 v2.8.1 h1:pZLMEwK8ep+CLIUWpWmvW8IWE/yxqG0I1xcN6cVMGuQ= +github.com/xuri/excelize/v2 v2.8.1/go.mod h1:oli1E4C3Pa5RXg1TBXn4ENCXDV5JUMlBluUhG7c+CEE= +github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A= +github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go new file mode 100644 index 0000000..b864b57 --- /dev/null +++ b/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + "github.com/jasonlvhit/gocron" + "log" + "udesk/exceldeal" + "udesk/udesk/modifystate" +) + +func main() { + log.Printf("准备执行...") + // 定义任务 + //gocron.Every(5).Second().Do(job) + gocron.Every(1).Day().At("09:30").Do(job) + //gocron.Every(1).Minutes().Do(job) + // 开始定时任务 + <-gocron.Start() +} + +// 定义执行的job +func job() { + fmt.Println("任务开始") + remindList, closeList, err := exceldeal.GetSheetName("./standby.xlsx") + if err != nil { + log.Fatalf("打开值班表失败:%v", err) + } + log.Println("应在线人员名字:", remindList) + log.Println("应离线人员名字:", closeList) + remindEmail, closeEmail := exceldeal.JsonDeal("./email.json", remindList, closeList) + log.Println("应在线人员邮箱:", remindEmail) + log.Println("应离线人员邮箱:", closeEmail) + + for _, rEmail := range closeEmail { + err = modifystate.PostToModifyState(rEmail, "offline") + if err != nil { + return + } + } + + for _, rEmail := range remindEmail { + err = modifystate.PostToModifyState(rEmail, "idle") + if err != nil { + return + } + } + + message := fmt.Sprintf("今日小雀: %v,备班1: %v\n昨日小雀: %v,备班1: %v\nudesk呼叫状态已修改。", remindList[0], remindList[1], closeList[0], closeList[1]) + exceldeal.Send(message) + fmt.Println("任务结束") +} diff --git a/standby.xlsx b/standby.xlsx new file mode 100644 index 0000000..70d7257 Binary files /dev/null and b/standby.xlsx differ diff --git a/udesk/auth/base.go b/udesk/auth/base.go new file mode 100644 index 0000000..b516929 --- /dev/null +++ b/udesk/auth/base.go @@ -0,0 +1,35 @@ +package auth + +const ( + Email = "hbqi@alauda.io" + Sign_version = "v2" + Password = "Ye_qiu@123" + Auth_token_url = "https://servicecenter-alauda.udesk.cn/open_api_v1/log_in" +) + +//获取鉴权token的账号密码请求体对象 + +type RequestUdeskBody struct { + Email string `json:"email"` + Password string `json:"password"` +} + +//udesk鉴权接口返回token对象 + +type UdeskToken struct { + Code string `json:"code"` + Open_api_auth_token string `json:"open_api_auth_token"` +} + +// 定义认证对象 +type Authobj struct { + Email, + Timestamp, + Sign, + Nonce, + Sign_version string +} + +//全局声明返回体对象 + +var u = newRespUdeskBody() diff --git a/udesk/auth/function.go b/udesk/auth/function.go new file mode 100644 index 0000000..11d57e0 --- /dev/null +++ b/udesk/auth/function.go @@ -0,0 +1,90 @@ +package auth + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "github.com/google/uuid" + "io" + "net/http" + "strconv" + "time" +) + +//新建请求体对象 + +func newReqUdeskToken() RequestUdeskBody { + return RequestUdeskBody{ + Email: Email, + Password: Password, + } +} + +// 新建返回体对象 +func newRespUdeskBody() UdeskToken { + return UdeskToken{ + Code: "", + Open_api_auth_token: "", + } +} + +//获取Unix时间戳 + +func GetTimeStamp() string { + return strconv.FormatInt(time.Now().Unix(), 10) +} + +//获取nonce + +func GetNonce() string { + randomUUID := uuid.New() + nonce := randomUUID.String() + return nonce +} + +// sha256转换函数 +func calculateSHA256(input string) string { + // 将字符串转换为字节数组 + inputBytes := []byte(input) + + // 创建SHA-256哈希对象 + hasher := sha256.New() + + // 将字节数组写入哈希对象 + hasher.Write(inputBytes) + + // 计算哈希值并返回 + hashInBytes := hasher.Sum(nil) + hashString := hex.EncodeToString(hashInBytes) + + return hashString +} + +// 获取鉴权token对象 + +func GetUdeskAuthToken() UdeskToken { + reqBody := newReqUdeskToken() + jsonData, err := json.Marshal(reqBody) + if err != nil { + fmt.Printf("获取udesk管理员token过程中转换请求体json失败,错误是:%v", err) + } + payload := bytes.NewBufferString(string(jsonData)) + resp, err := http.Post(Auth_token_url, "application/json", payload) + if err != nil { + fmt.Printf("获取udesk管理员token过程中请求获取token接口失败,错误是:%v", err) + } + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + return + } + }(resp.Body) + body, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Printf("获取udesk管理员token过程中获取token接口响应失败,错误是:%v", err) + } + json.Unmarshal(body, &u) + return u +} diff --git a/udesk/auth/geturl.go b/udesk/auth/geturl.go new file mode 100644 index 0000000..0a7904b --- /dev/null +++ b/udesk/auth/geturl.go @@ -0,0 +1,17 @@ +package auth + +import "strings" + +//最终请求的url后缀拼接 + +func Geturlstring(url string) string { + var authobj = u.getAuthobj() //必须要同步处理timestamp和sign的关系,否则会鉴权失败,所以从同一个结构体中取值 + var builder strings.Builder + builder.WriteString(url) + builder.WriteString("email=" + authobj.Email) + builder.WriteString("×tamp=" + authobj.Timestamp) + builder.WriteString("&sign=" + authobj.Sign) + builder.WriteString("&nonce=" + authobj.Nonce) + builder.WriteString("&sign_version=" + authobj.Sign_version) + return builder.String() +} diff --git a/udesk/auth/method.go b/udesk/auth/method.go new file mode 100644 index 0000000..e26baa8 --- /dev/null +++ b/udesk/auth/method.go @@ -0,0 +1,37 @@ +package auth + +import ( + "strings" +) + +//获取token字符串 + +func (UdeskToken) getTokenString() string { + token := GetUdeskAuthToken().Open_api_auth_token + return token +} + +//计算sign并返回authobj + +func (UdeskToken) getAuthobj() Authobj { + token := u.getTokenString() + timestamp := GetTimeStamp() + nonce := GetNonce() + var builder strings.Builder + builder.WriteString(Email + "&") + builder.WriteString(token + "&") + builder.WriteString(timestamp + "&") + builder.WriteString(nonce + "&") + builder.WriteString(Sign_version) + str2sha256 := builder.String() + hashResult := calculateSHA256(str2sha256) + //fmt.Println(str2sha256) + return Authobj{ + Email: Email, + Timestamp: timestamp, + Sign: hashResult, + Nonce: nonce, + Sign_version: Sign_version, + } + +} diff --git a/udesk/modifystate/modifystate.go b/udesk/modifystate/modifystate.go new file mode 100644 index 0000000..0afc07a --- /dev/null +++ b/udesk/modifystate/modifystate.go @@ -0,0 +1,46 @@ +package modifystate + +import ( + "fmt" + "io" + "log" + "net/http" + "strings" + "udesk/udesk/auth" +) + +func PostToModifyState(email, state string) error { + // 获取 URL + url := fmt.Sprintf("https://servicecenter-alauda.udesk.cn/open_api_v1/callcenter/agent_state?email=%s&", email) + url = auth.Geturlstring(url) + + // 请求体 + bodystring := fmt.Sprintf("{\"agent_email\": \"%s\",\"agent_work_state\": \"%s\"}", email, state) + + // 创建请求 + req, err := http.NewRequest("POST", url, strings.NewReader(bodystring)) + if err != nil { + return err + } + + // 设置请求头 + req.Header.Set("Content-Type", "application/json") + + // 发送请求 + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + // 读取响应体 + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + // 打印响应体 + log.Printf("send udesk to modify state,Response is: %s", string(respBody)) + return nil +} diff --git a/wechatwebhook.json b/wechatwebhook.json new file mode 100644 index 0000000..5e58a04 --- /dev/null +++ b/wechatwebhook.json @@ -0,0 +1,3 @@ +{ + "webhook": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=9e27f428-7fb9-4771-8e48-231f59eb1ec4" +}