From 5e88833854780d79ccfc662daa3d23d353fad30b Mon Sep 17 00:00:00 2001 From: duyu Date: Wed, 21 Aug 2024 10:18:34 +0800 Subject: [PATCH] ding --- app/http/controllers/dingding/dingding.go | 30 ++++ app/http/entities/dingding/dingding.go | 10 ++ app/http/routes/route.go | 4 +- app/models/dinglist/dinglist.go | 126 ++++++++++++++ app/services/dingding/dingding.go | 176 ++++++++++++++++++++ app/services/orders/orders.go | 2 +- app/services/transfersys/transfersys.go | 33 ++++ app/services/transfersys/transfersys_rdb.go | 1 + build/sql/db.sql | 9 +- main.go | 3 +- 10 files changed, 389 insertions(+), 5 deletions(-) create mode 100644 app/http/controllers/dingding/dingding.go create mode 100644 app/http/entities/dingding/dingding.go create mode 100644 app/models/dinglist/dinglist.go create mode 100644 app/services/dingding/dingding.go diff --git a/app/http/controllers/dingding/dingding.go b/app/http/controllers/dingding/dingding.go new file mode 100644 index 0000000..ca55c33 --- /dev/null +++ b/app/http/controllers/dingding/dingding.go @@ -0,0 +1,30 @@ +package dingding + +import ( + "com.snow.auto_monitor/app/constants/errorcode" + common "com.snow.auto_monitor/app/http/controllers" + dingEnt "com.snow.auto_monitor/app/http/entities/dingding" + dingServ "com.snow.auto_monitor/app/services/dingding" + "github.com/gin-gonic/gin" +) + +func DingSend(c *gin.Context) { + request := new(dingEnt.DingSendReq) + err := common.GenRequest(c, request) + if err != nil { + common.Error(c, errorcode.ParamError) + return + } + + err = dingServ.DingSend(request.Title, request.Content, true) + if err != nil { + common.Error500(c) + return + } + + response := &dingEnt.DingSendResp{ + Status: "success", + } + + common.Success(c, response) +} diff --git a/app/http/entities/dingding/dingding.go b/app/http/entities/dingding/dingding.go new file mode 100644 index 0000000..21d1347 --- /dev/null +++ b/app/http/entities/dingding/dingding.go @@ -0,0 +1,10 @@ +package dingding + +type DingSendReq struct { + Title string `json:"title" validate:"required" example:"标题"` + Content string `json:"content" validate:"required" example:"内容"` +} + +type DingSendResp struct { + Status string `json:"status" example:"success"` +} diff --git a/app/http/routes/route.go b/app/http/routes/route.go index bbdaa2a..214b296 100644 --- a/app/http/routes/route.go +++ b/app/http/routes/route.go @@ -11,6 +11,7 @@ import ( "com.snow.auto_monitor/config" devCon "com.snow.auto_monitor/app/http/controllers/device" + dingCon "com.snow.auto_monitor/app/http/controllers/dingding" merCon "com.snow.auto_monitor/app/http/controllers/merchant" ordersCon "com.snow.auto_monitor/app/http/controllers/orders" proCon "com.snow.auto_monitor/app/http/controllers/product" @@ -28,7 +29,7 @@ import ( func RegisterRoute(router *gin.Engine) { //middleware: 服务错误处理 => 生成请求id => access log router.Use(middlewares.ServerRecovery(), middleware.GenRequestId, - middleware.GenContextKit, middleware.AccessLog(), middlewares.VerifyIp(), + middleware.GenContextKit, middleware.AccessLog(), //middlewares.VerifyIp(), middlewares.Cors()) if config.GetConf().PrometheusCollectEnable && config.IsEnvEqual(config.ProdEnv) { @@ -131,6 +132,7 @@ func RegisterRoute(router *gin.Engine) { temp.Use(middlewares.RequestLog()) { temp.POST("/recharge/order", zlCon.CreateOrder) + temp.POST("/ding/send", dingCon.DingSend) } router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) diff --git a/app/models/dinglist/dinglist.go b/app/models/dinglist/dinglist.go new file mode 100644 index 0000000..968524e --- /dev/null +++ b/app/models/dinglist/dinglist.go @@ -0,0 +1,126 @@ +package dinglist + +import ( + "sync" + "time" + + "github.com/qit-team/snow-core/db" +) + +var ( + once sync.Once + m *dinglistModel +) + +/** + * DingList + */ +type DingList struct { + Id int64 `xorm:"pk autoincr"` //注:使用getOne 或者ID() 需要设置主键 + DepartmentId int64 + UserId string + CreatedAt time.Time `xorm:"created"` +} + +/** + * 表名规则 + * @wiki http://gobook.io/read/github.com/go-xorm/manual-zh-CN/chapter-02/3.tags.html + */ +func (m *DingList) TableName() string { + return "dinglist" +} + +/** + * 私有化,防止被外部new + */ +type dinglistModel struct { + db.Model //组合基础Model,集成基础Model的属性和方法 +} + +// 单例模式 +func GetInstance() *dinglistModel { + once.Do(func() { + m = new(dinglistModel) + //m.DiName = "" //设置数据库实例连接,默认db.SingletonMain + }) + return m +} + +/** + * 查询主键ID的记录 + * @param id 主键ID + * @return has 是否有记录 + * @return err 错误信息 + * @return dinglist 查询结果 + */ +func (m *dinglistModel) GetById(id int64) (dinglist *DingList, has bool, err error) { + dinglist = &DingList{} + has, err = m.GetDb().ID(id).Get(dinglist) + if err != nil || !has { + dinglist = nil + } + return +} + +func (m *dinglistModel) Search(id int64, departmentId int64, userId string, startTime string, endTime string, limit int, page int) (dinglist []*DingList, err error) { + dinglist = make([]*DingList, 0) + sql := "1=1" + var args []interface{} + if id != 0 { + sql += " and id = ?" + args = append(args, id) + } + if departmentId != 0 { + sql += " and department_id = ?" + args = append(args, departmentId) + } + if userId != "" { + sql += " and user_id = ?" + args = append(args, userId) + } + if startTime != "" && endTime != "" { + sql += " and created_at >= ? and created_at <= ?" + args = append(args, startTime, endTime) + } + err = m.GetDb().Where(sql, args...).OrderBy("created_at desc").Limit(limit, page).Find(&dinglist) + return +} + +func (m *dinglistModel) CountAll(id int64, departmentId int64, userId string, startTime string, endTime string, limit int, page int) (res int64, err error) { + sql := "1=1" + var args []interface{} + if id != 0 { + sql += " and id = ?" + args = append(args, id) + } + if departmentId != 0 { + sql += " and department_id = ?" + args = append(args, departmentId) + } + if userId != "" { + sql += " and user_id = ?" + args = append(args, userId) + } + if startTime != "" && endTime != "" { + sql += " and created_at >= ? and created_at <= ?" + args = append(args, startTime, endTime) + } + res, err = m.GetDb().Table("dinglist").Where(sql, args...).Count() + return +} + +func (m *dinglistModel) Create(dinglist *DingList) (affected int64, err error) { + dinglist.CreatedAt = time.Now() + affected, err = m.GetDb().Insert(dinglist) + return +} + +func (m *dinglistModel) Update(dinglist *DingList) (affected int64, err error) { + affected, err = m.GetDb().ID(dinglist.Id).Update(dinglist) + return +} + +func (m *dinglistModel) Delete(id int64) (affected int64, err error) { + affected, err = m.GetDb().ID(id).Delete(&DingList{}) + return +} diff --git a/app/services/dingding/dingding.go b/app/services/dingding/dingding.go new file mode 100644 index 0000000..702b8cb --- /dev/null +++ b/app/services/dingding/dingding.go @@ -0,0 +1,176 @@ +package dingding + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + dingMod "com.snow.auto_monitor/app/models/dinglist" + "github.com/qit-team/snow-core/log/logger" +) + +var token string = "" + +func AccessToken(client_key string, client_secret string) { + targetUrl := "http://121.199.38.107:8000/oauth/v1/accesstoken" + data := map[string]interface{}{ + "client_key": client_key, + "client_secret": client_secret, + } + jsonData, err := json.Marshal(data) + if err != nil { + logger.Error(context.TODO(), "dingding", err) + return + } + req, err := http.NewRequest("POST", targetUrl, bytes.NewBuffer(jsonData)) + if err != nil { + logger.Error(context.TODO(), "dingding", err) + return + } + // 设置请求头,指定内容类型为JSON + req.Header.Set("Content-Type", "application/json") + + // 发送请求并获取响应 + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + logger.Error(context.TODO(), "dingding", err) + return + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + logger.Error(context.TODO(), "dingding", err) + return + } + + // fmt.Println("响应状态码:", resp.StatusCode) + // fmt.Println("响应内容:", string(body)) + + if resp.StatusCode != 200 { + logger.Error(context.TODO(), "dingding", "钉钉发送公告失败") + logger.Error(context.TODO(), "dingding", string(body)) + return + } + + // 定义结构体用于解析JSON数据 + type Data struct { + AccessToken string `json:"accessToken"` + AccessExpire int64 `json:"accessExpire"` + } + + type Response struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data Data `json:"data"` + } + // 解析JSON数据 + var res Response + err = json.Unmarshal([]byte(body), &res) + if err != nil { + fmt.Println("解析JSON失败:", err) + return + } + + // 获取并打印accessToken + accessToken := res.Data.AccessToken + // fmt.Println("accessToken:", accessToken) + token = accessToken +} + +func DingSend(title string, content string, retry bool) (err error) { + dlist, err := dingMod.GetInstance().Search(0, 0, "", "", "", 999, 0) + if err != nil { + logger.Error(context.TODO(), "dingding", err) + return + } + + deptid_list := []int64{} + userid_list := []string{} + for _, v := range dlist { + deptid_list = append(deptid_list, v.DepartmentId) + userid_list = append(userid_list, v.UserId) + } + + targetUrl := "http://121.199.38.107:8000/msg/v1/dingtalk/blackboard/send" + data := map[string]interface{}{ + "base": map[string]string{ + "server_index": "transfer_msg", + "temp_index": "transferding", + }, + "blackboard_receiver": map[string]interface{}{ + "deptid_list": deptid_list, + "userid_list": userid_list, + }, + "title": title, + "content": content, + } + jsonData, err := json.Marshal(data) + if err != nil { + logger.Error(context.TODO(), "dingding", err) + return + } + req, err := http.NewRequest("POST", targetUrl, bytes.NewBuffer(jsonData)) + if err != nil { + logger.Error(context.TODO(), "dingding", err) + return + } + // 设置请求头,指定内容类型为JSON + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", token) + + // 发送请求并获取响应 + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + logger.Error(context.TODO(), "dingding", err) + return + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + logger.Error(context.TODO(), "dingding", err) + return + } + + // fmt.Println("响应状态码:", resp.StatusCode) + // fmt.Println("响应内容:", string(body)) + + if resp.StatusCode != 200 { + logger.Error(context.TODO(), "dingding", "钉钉发送公告失败") + logger.Error(context.TODO(), "dingding", string(body)) + return + } + + // 定义结构体用于解析JSON数据 + type Data struct { + Code int64 `json:"code"` + Msg string `json:"msg"` + } + + // 解析JSON数据 + var res Data + err = json.Unmarshal([]byte(body), &res) + if err != nil { + fmt.Println("解析JSON失败:", err) + return + } + + if res.Code == 2 { + AccessToken("transfer123", "transfer321") + if retry { + DingSend(title, content, false) + } + } + return +} + +func init() { + fmt.Println("初始化钉钉接口") + AccessToken("transfer123", "transfer321") +} diff --git a/app/services/orders/orders.go b/app/services/orders/orders.go index b4dd2ba..72629ad 100644 --- a/app/services/orders/orders.go +++ b/app/services/orders/orders.go @@ -56,7 +56,7 @@ func CountAll(id int64, transfer_status int64, startTime string, endTime string) (res int64, err error) { - res, err = models.GetInstance().CountAll(id, order_no, merchant_id, product_id,device_no, out_trade_no, + res, err = models.GetInstance().CountAll(id, order_no, merchant_id, product_id, device_no, out_trade_no, recharge_account, account_type, status, transfer_status, startTime, endTime) return diff --git a/app/services/transfersys/transfersys.go b/app/services/transfersys/transfersys.go index 3e99f4b..7b1be07 100644 --- a/app/services/transfersys/transfersys.go +++ b/app/services/transfersys/transfersys.go @@ -2,11 +2,14 @@ package transfersys import ( "errors" + "fmt" "time" mermod "com.snow.auto_monitor/app/models/merchant" models "com.snow.auto_monitor/app/models/orders" promod "com.snow.auto_monitor/app/models/product" + "com.snow.auto_monitor/app/services/device" + dingServ "com.snow.auto_monitor/app/services/dingding" "com.snow.auto_monitor/app/utils/rdbdq" ) @@ -39,8 +42,38 @@ func FinishOrder(orders *models.Orders) (affected int64, err error) { if orders.TransferStatus == 1 { orders.Status = 1 } + if orders.TransferStatus == 4 || orders.TransferStatus == 5 { orders.Status = orders.TransferStatus - 1 + device, err := device.Search(0, orders.DeviceNo, "", 0, "", "", 1, 1) + if err != nil { + return 0, err + } + orderDetail, _, err := models.GetInstance().GetById(orders.Id) + if err != nil { + return 0, err + } + var deviceNumber int64 = -1 + if device != nil { + deviceNumber = device[0].Code + } + dingStr := fmt.Sprintf( + ` + - 异常设备: %d 号机; + - 异常单号: %s; + - 充值账号: %s; + - 产品号: %d; + - 失败原因: %s; + - 失败时间: %s; + `, + deviceNumber, + orderDetail.OutTradeNo, + orderDetail.RechargeAccount, + orders.ProductId, + orders.FailReason, + orderDetail.CreatedAt.Format("2006-01-02 15:04:05"), + ) + dingServ.DingSend("订单异常", dingStr, true) } affected, err = models.GetInstance().SetDealingOrder(orders) diff --git a/app/services/transfersys/transfersys_rdb.go b/app/services/transfersys/transfersys_rdb.go index 0dc63ac..f9a4ac0 100644 --- a/app/services/transfersys/transfersys_rdb.go +++ b/app/services/transfersys/transfersys_rdb.go @@ -45,6 +45,7 @@ func WriteOrder() { err := rdbmq.CreateStreamAndGroup("orders", "orders_one") if err != nil && err.Error() != "BUSYGROUP Consumer Group name already exists" { fmt.Println("分组失败") + fmt.Println(err) return } // 创建一个新的Ticker,每3秒钟触发一次 diff --git a/build/sql/db.sql b/build/sql/db.sql index 70848eb..b194b46 100644 --- a/build/sql/db.sql +++ b/build/sql/db.sql @@ -59,4 +59,11 @@ create table device ( phone varchar(255), code int, created_at timestamp default current_timestamp -); \ No newline at end of file +); + +create table ding_list ( + id int primary key auto_increment, + department_id varchar(64), + user_id varchar(64), + created_at timestamp default current_timestamp +); diff --git a/main.go b/main.go index 2609552..9c0ee97 100644 --- a/main.go +++ b/main.go @@ -68,7 +68,6 @@ func main() { } handleCmd(opts) - err := startServer(opts) if err != nil { fmt.Printf("server start error, %s\n", err) @@ -76,7 +75,7 @@ func main() { } } -//执行(status|stop|restart)命令 +// 执行(status|stop|restart)命令 func handleCmd(opts *config.Options) { if opts.Cmd != "" { pidFile := opts.GenPidFile()