From 76ac51bcd1759240e83d5920a9446ad962a9bf5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E5=AE=97=E6=A5=A0?= Date: Mon, 20 Mar 2023 16:18:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0uniapp=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- business/jxstore/cms/user2.go | 15 ++ business/jxutils/unipush/push.go | 289 ++++++++++++++++++++++++++----- business/model/user.go | 56 +++--- conf/app.conf | 24 +++ controllers/auth2.go | 5 + globals/api/api.go | 3 + 6 files changed, 316 insertions(+), 76 deletions(-) diff --git a/business/jxstore/cms/user2.go b/business/jxstore/cms/user2.go index b5d8e3a65..483752953 100644 --- a/business/jxstore/cms/user2.go +++ b/business/jxstore/cms/user2.go @@ -1229,6 +1229,21 @@ func UpdateUserLastInfo(ctx *jxcontext.Context, storeID, brandID int) (err error return err } +func SetUserCId(userId string, cid string) error { + var db = dao.GetDB() + userObj, err := dao.GetUserByID(db, "user_id", userId) + if err != nil { + return err + } + + if userObj.CID == "" || userObj.CID != cid { + userObj.CID = cid + _, err := dao.UpdateEntity(db, userObj, "CID") + return err + } + return nil +} + func GetUserStoreAuth(ctx *jxcontext.Context, storeID int) (outStoreID int, err error) { if permission.IsRoled(ctx) { configs, _ := dao.QueryConfigs(dao.GetDB(), "checkversion", model.ConfigTypeSys, "") diff --git a/business/jxutils/unipush/push.go b/business/jxutils/unipush/push.go index cbb5eae7e..f84fa30c1 100644 --- a/business/jxutils/unipush/push.go +++ b/business/jxutils/unipush/push.go @@ -1,10 +1,14 @@ package push import ( + "encoding/json" + "errors" "fmt" + "git.rosy.net.cn/jx-callback/business/authz/autils" + "git.rosy.net.cn/jx-callback/globals/api2" "strings" + "time" - "git.rosy.net.cn/baseapi/platformapi/unipushapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" @@ -14,52 +18,91 @@ import ( beego "github.com/astaxie/beego/server/web" ) -func pushToSingle(content, title string, storeID int) { - var ( - db = dao.GetDB() - ) - if !globals.IsProductEnv() { - return - } - if storeID == 0 { - return - } - storePushs, err := dao.GetStorePushClient(db, storeID, "") - if err != nil { - return - } - for _, v := range storePushs { - - status, err2 := api.PushAPI.PushToSingle(v.ClientID, false, &unipushapi.Notification{ - Title: title, - Body: content, - }) - if err = err2; err != nil { - continue - } - if status == unipushapi.SuccessOffLine { - _, err = api.PushAPI.PushToSingle(v.ClientID, true, &unipushapi.Notification{ - Body: content, - }) - if err != nil { - globals.SugarLogger.Debugf("NotifyNewOrder push2 error: [%v]", err) - continue - } - } - - } -} +// +//func pushToSingle(content, title string, storeID int) { +// var ( +// db = dao.GetDB() +// ) +// if !globals.IsProductEnv() { +// return +// } +// if storeID == 0 { +// return +// } +// storePushs, err := dao.GetStorePushClient(db, storeID, "") +// if err != nil { +// return +// } +// for _, v := range storePushs { +// +// status, err2 := api.PushAPI.PushToSingle(v.ClientID, false, &unipushapi.Notification{ +// Title: title, +// Body: content, +// }) +// if err = err2; err != nil { +// continue +// } +// if status == unipushapi.SuccessOffLine { +// _, err = api.PushAPI.PushToSingle(v.ClientID, true, &unipushapi.Notification{ +// Body: content, +// }) +// if err != nil { +// globals.SugarLogger.Debugf("NotifyNewOrder push2 error: [%v]", err) +// continue +// } +// } +// +// } +//} +// NotifyNewOrder 推送新订单 func NotifyNewOrder(order *model.GoodsOrder) { - if order == nil || len(order.Skus) == 0 { + //if order == nil || len(order.Skus) == 0 { + // return + //} + //sb := new(strings.Builder) + //sb.WriteString("老板,") + //sb.WriteString(order.ConsigneeName) + //sb.WriteString("购买了商品") + //sb.WriteString(getOrderDetailBrief(order)) + //pushToSingle(sb.String(), "京西菜市新订单推送", jxutils.GetSaleStoreIDFromOrder(order)) + storeId := order.StoreID + if storeId <= model.NO { + storeId = order.JxStoreID + } + msg := MsgContext{} + + storeDetail, err := dao.GetStoreDetail(dao.GetDB(), storeId, 0, "") + if err != nil || storeDetail == nil { + msg.MsgType = "新订单错误" + msg.VendorName = "错误消息通知" + msg.OrderSqs = "1" + msg.StoreTitle = "根据门店id获取门店详情错误" + msg.Context = err.Error() + context, _ := json.Marshal(msg) + pushMsgByUniApp(99999, "门店用户cid获取错误", []string{"212db7816d26e0c603518091b96d3554"}, string(context)) return } - sb := new(strings.Builder) - sb.WriteString("老板,") - sb.WriteString(order.ConsigneeName) - sb.WriteString("购买了商品") - sb.WriteString(getOrderDetailBrief(order)) - pushToSingle(sb.String(), "京西菜市新订单推送", jxutils.GetSaleStoreIDFromOrder(order)) + + cid, err := GetStoreBoosCID(storeId) + if err != nil { + msg.MsgType = "新订单错误" + msg.VendorName = "错误消息通知" + msg.OrderSqs = "1" + msg.StoreTitle = "错误日志通知" + msg.Context = err.Error() + context, _ := json.Marshal(msg) + pushMsgByUniApp(99999, "门店用户cid获取错误", []string{"212db7816d26e0c603518091b96d3554"}, string(context)) + return + } + + msg.MsgType = "新订单" + msg.VendorName = model.VendorChineseNames[order.VendorID] + msg.OrderSqs = utils.Int2Str(order.OrderSeq) + msg.StoreTitle = storeDetail.Name + msg.Context = "老板,你有新的订单了" + context, _ := json.Marshal(msg) + pushMsgByUniApp(storeDetail.ID, storeDetail.Name, cid, string(context)) } func getOrderDetailBrief(order *model.GoodsOrder) (brief string) { @@ -87,12 +130,166 @@ func getOrderDetailBrief(order *model.GoodsOrder) (brief string) { } func NotifyAfsOrder(afsOrder *model.AfsOrder) (err error) { - pushToSingle("老板,您有新的售后单,请尽快处理!", "京西菜市售后单推送", jxutils.GetSaleStoreIDFromAfsOrder(afsOrder)) + storeId := afsOrder.StoreID + if storeId <= model.NO { + storeId = afsOrder.JxStoreID + } + msg := MsgContext{} + + storeDetail, err := dao.GetStoreDetail(dao.GetDB(), storeId, 0, "") + if err != nil || storeDetail == nil { + msg.MsgType = "售后单错误" + msg.VendorName = "错误消息通知" + msg.OrderSqs = "1" + msg.StoreTitle = "根据门店id获取门店详情错误" + msg.Context = err.Error() + context, _ := json.Marshal(msg) + pushMsgByUniApp(99999, "门店用户cid获取错误", []string{"212db7816d26e0c603518091b96d3554"}, string(context)) + return + } + + cid, err := GetStoreBoosCID(storeId) + if err != nil { + msg.MsgType = "售后单错误" + msg.VendorName = "错误消息通知" + msg.OrderSqs = "1" + msg.StoreTitle = "错误日志通知" + msg.Context = err.Error() + context, _ := json.Marshal(msg) + pushMsgByUniApp(99999, "门店用户cid获取错误", []string{"212db7816d26e0c603518091b96d3554"}, string(context)) + return + } + + msg.MsgType = "售后订单" + msg.VendorName = model.VendorChineseNames[afsOrder.VendorID] + msg.OrderSqs = "0" + msg.StoreTitle = storeDetail.Name + msg.Context = "老板订单申请退款了" + context, _ := json.Marshal(msg) + pushMsgByUniApp(storeDetail.ID, storeDetail.Name, cid, string(context)) + //pushToSingle("老板,您有新的售后单,请尽快处理!", "京西菜市售后单推送", jxutils.GetSaleStoreIDFromAfsOrder(afsOrder)) return err } func NotifyOrderCanceled(order *model.GoodsOrder) (err error) { - title := fmt.Sprintf("老板,您的订单%s第%d号订单, %s被取消了!", model.VendorChineseNames[order.VendorID], order.OrderSeq, order.VendorOrderID) - pushToSingle(title, "京西菜市取消单推送", jxutils.GetSaleStoreIDFromOrder(order)) + storeId := order.StoreID + if storeId <= model.NO { + storeId = order.JxStoreID + } + msg := MsgContext{} + + storeDetail, err := dao.GetStoreDetail(dao.GetDB(), storeId, 0, "") + if err != nil || storeDetail == nil { + msg.MsgType = "取消单错误" + msg.VendorName = "错误消息通知" + msg.OrderSqs = "1" + msg.StoreTitle = "根据门店id获取门店详情错误" + msg.Context = err.Error() + context, _ := json.Marshal(msg) + pushMsgByUniApp(99999, "门店用户cid获取错误", []string{"212db7816d26e0c603518091b96d3554"}, string(context)) + return + } + + cid, err := GetStoreBoosCID(storeId) + if err != nil { + msg.MsgType = "取消单错误" + msg.VendorName = "错误消息通知" + msg.OrderSqs = "1" + msg.StoreTitle = "错误日志通知" + msg.Context = err.Error() + context, _ := json.Marshal(msg) + pushMsgByUniApp(99999, "门店用户cid获取错误", []string{"212db7816d26e0c603518091b96d3554"}, string(context)) + return + } + + msg.MsgType = "售后订单" + msg.VendorName = model.VendorChineseNames[order.VendorID] + msg.OrderSqs = "0" + msg.StoreTitle = storeDetail.Name + msg.Context = "老板订单被取消了" + context, _ := json.Marshal(msg) + pushMsgByUniApp(storeDetail.ID, storeDetail.Name, cid, string(context)) + //title := fmt.Sprintf("老板,您的订单%s第%d号订单, %s被取消了!", model.VendorChineseNames[order.VendorID], order.OrderSeq, order.VendorOrderID) + //pushToSingle(title, "京西菜市取消单推送", jxutils.GetSaleStoreIDFromOrder(order)) return err } + +// GetStoreBoosCID /************************************************************/ +func GetStoreBoosCID(storeId int) ([]string, error) { + // 根据订单获取门店的老板cid + userIDList, err2 := api2.RoleMan.GetRoleUserList(autils.NewStoreBossRole(storeId)) + if err2 != nil { + return nil, err2 + } + + userList, _, err := dao.GetUsers(dao.GetDB(), 0, "", userIDList, nil, nil, 0, 100) + if err != nil || len(userList) <= model.NO { + return nil, errors.New("门店老板信息获取异常") + } + + var cId = make([]string, 0, len(userList)) + for _, v := range userList { + if v.CID != "" { + cId = append(cId, v.CID) + } + } + + if len(cId) <= model.NO { + return nil, fmt.Errorf("门店[%d],暂无CID,无法使用UniApp推送", storeId) + } + + return cId, nil +} + +type MsgContext struct { + MsgType string `json:"msg_type"` // 订单类型[新订单/售后单/取消单] + StoreTitle string `json:"store_title"` // 门店名称 + Context string `json:"context"` // 消息文本 + VendorName string `json:"vendor_name"` // 平台名称 + OrderSqs string `json:"order_sqs"` // 订单流水号 +} + +func pushMsgByUniApp(storeId int, storeName string, cID []string, msg string) { + var errs []error + for _, v := range cID { + param := map[string]interface{}{ + "request_id": utils.Int64ToStr(time.Now().Unix()) + "_" + utils.Int2Str(storeId), + "settings": map[string]interface{}{ + "ttl": 7200000, + }, + "audience": map[string]interface{}{ + "cid": []string{v}, + }, + "push_message": map[string]interface{}{ + "transmission": msg, + }, + "push_channel": map[string]interface{}{ + "android": map[string]interface{}{ + "ups": map[string]interface{}{ + "transmission": msg, + }, + }, + "ios": map[string]interface{}{ + "type": "notify", + "payload": msg, + "aps": map[string]interface{}{ + "alert": map[string]interface{}{ + "title": storeName, + "body": msg, + }, + "content-available": 0, + "sound": "ring.mp3", + }, + "auto_badge": "+1", + }, + }, + } + + if err := api.UniAppApi.SendMsgByUinApp(param); err != nil { + errs = append(errs, err) + } + } + if len(errs) != 0 { + globals.SugarLogger.Errorf("uinapp 消息推送错误:%s", utils.Format4Output(errs, false)) + } +} diff --git a/business/model/user.go b/business/model/user.go index fea5032c3..e915c6d8a 100644 --- a/business/model/user.go +++ b/business/model/user.go @@ -40,36 +40,32 @@ type DiscountCard struct { type User struct { ModelIDCULD - UserID string `orm:"size(48);column(user_id)" json:"userID" compact:"userID"` // 内部唯一标识 - UserID2 string `orm:"size(48);column(user_id2)" json:"userID2" compact:"userID2"` // 外部唯一标识(一般用于登录) - Name string `orm:"size(48);index" json:"name" compact:"name"` // 外部显示标识(当前可以重复) - Mobile *string `orm:"size(32);null" json:"mobile" compact:"mobile"` - Email *string `orm:"size(32);null" json:"email" compact:"email"` - Avatar string `orm:"size(255)" json:"avatar" compact:"avatar"` // 头像 - Status int8 `json:"status" compact:"status"` - Type int8 `json:"type" compact:"type"` // 用户类型 - - CityCode int `orm:"default(0)" json:"cityCode"` - DistrictCode int `orm:"default(0);index" json:"districtCode"` - Address string `orm:"size(255)" json:"address"` - - IDCardNo string `orm:"size(18);column(id_card_no)" json:"idCardNo" compact:"idCardNo"` // 身份证号 - Remark string `orm:"size(255)" json:"remark"` - - LastLoginAt *time.Time `orm:"null" json:"lastLoginAt"` - LastLoginIP string `orm:"size(64);column(last_login_ip)" json:"lastLoginIP"` - LastLoginType string `orm:"size(16)" json:"lastLoginType"` - LastBrandID int `orm:"column(last_brand_id)" json:"lastBrandID"` - LastStoreID int `orm:"column(last_store_id)" json:"lastStoreID"` //上次浏览过的店铺 - - ParentMobile string `orm:"size(32)" json:"parentMobile"` - DividePercentage int `json:"dividePercentage"` - Profit int `json:"profit"` - ProfitSum int `json:"profitSum"` - Arrears int `json:"arrears"` - - BindStoreID string `orm:"column(bind_store_id)" json:"bindStoreID"` //门店老板账号用,表示绑的哪个门店,后权限用 - BindStoreUser string `json:"bindStoreUser"` //表示绑的哪个账号,密码同这个账号 + UserID string `orm:"size(48);column(user_id)" json:"userID" compact:"userID"` // 内部唯一标识 + UserID2 string `orm:"size(48);column(user_id2)" json:"userID2" compact:"userID2"` // 外部唯一标识(一般用于登录) + Name string `orm:"size(48);index" json:"name" compact:"name"` // 外部显示标识(当前可以重复) + Mobile *string `orm:"size(32);null" json:"mobile" compact:"mobile"` + Email *string `orm:"size(32);null" json:"email" compact:"email"` + Avatar string `orm:"size(255)" json:"avatar" compact:"avatar"` // 头像 + Status int8 `json:"status" compact:"status"` + Type int8 `json:"type" compact:"type"` // 用户类型 + CityCode int `orm:"default(0)" json:"cityCode"` + DistrictCode int `orm:"default(0);index" json:"districtCode"` + Address string `orm:"size(255)" json:"address"` + IDCardNo string `orm:"size(18);column(id_card_no)" json:"idCardNo" compact:"idCardNo"` // 身份证号 + Remark string `orm:"size(255)" json:"remark"` + LastLoginAt *time.Time `orm:"null" json:"lastLoginAt"` + LastLoginIP string `orm:"size(64);column(last_login_ip)" json:"lastLoginIP"` + LastLoginType string `orm:"size(16)" json:"lastLoginType"` + LastBrandID int `orm:"column(last_brand_id)" json:"lastBrandID"` + LastStoreID int `orm:"column(last_store_id)" json:"lastStoreID"` //上次浏览过的店铺 + ParentMobile string `orm:"size(32)" json:"parentMobile"` + DividePercentage int `json:"dividePercentage"` + Profit int `json:"profit"` + ProfitSum int `json:"profitSum"` + Arrears int `json:"arrears"` + BindStoreID string `orm:"column(bind_store_id)" json:"bindStoreID"` //门店老板账号用,表示绑的哪个门店,后权限用 + BindStoreUser string `json:"bindStoreUser"` //表示绑的哪个账号,密码同这个账号 + CID string `orm:"column(c_id);size(48)"json:"c_id"` } func (*User) TableUnique() [][]string { diff --git a/conf/app.conf b/conf/app.conf index b3bf8c8b2..e9f78ce43 100644 --- a/conf/app.conf +++ b/conf/app.conf @@ -209,6 +209,12 @@ fnCallbackURL = "http://callback.jxc4.com/fn/msg" kuaiShouAppId = "ks680887971696897880" kuaiShouAppSecret = "1wShCPqUzhg8W1vcb8OdvA" +# uniApp 消息推送授权 +uniAppAppKey = "Iogz63Q1HL7R4dB8F4Kbn5" +uniAppMasterSecret = "J7pU14SwCC7SoUntXJghj8" +uniAppAppId = "dqxDP9HwHc5B1dd2db4ek2" +uniAppAppSecret = "wX4n8IusDn7PfxkGmypzp5" + #uu跑腿 uuAppID="55c4542ae60e4d348edcfc93b06dd302" uuAppKey="76b362c06b1b4baa9e47bab6387a5356" @@ -356,6 +362,12 @@ fnCallbackURL = "http://callback.jxc4.com/fn/msg" kuaiShouAppId = "ks680887971696897880" kuaiShouAppSecret = "1wShCPqUzhg8W1vcb8OdvA" +# uniApp 消息推送授权 +uniAppAppKey = "Iogz63Q1HL7R4dB8F4Kbn5" +uniAppMasterSecret = "J7pU14SwCC7SoUntXJghj8" +uniAppAppId = "dqxDP9HwHc5B1dd2db4ek2" +uniAppAppSecret = "wX4n8IusDn7PfxkGmypzp5" + #uu跑腿 uuAppID="55c4542ae60e4d348edcfc93b06dd302" uuAppKey="76b362c06b1b4baa9e47bab6387a5356" @@ -474,6 +486,12 @@ fnCallbackURL = "http://callback-jxgy.jxc4.com/fn/msg" kuaiShouAppId = "ks680887971696897880" kuaiShouAppSecret = "1wShCPqUzhg8W1vcb8OdvA" +# uniApp 消息推送授权 +uniAppAppKey = "Iogz63Q1HL7R4dB8F4Kbn5" +uniAppMasterSecret = "J7pU14SwCC7SoUntXJghj8" +uniAppAppId = "dqxDP9HwHc5B1dd2db4ek2" +uniAppAppSecret = "wX4n8IusDn7PfxkGmypzp5" + #uu跑腿 uuAppID="55c4542ae60e4d348edcfc93b06dd302" uuAppKey="76b362c06b1b4baa9e47bab6387a5356" @@ -677,6 +695,12 @@ fnCallbackURL = "http://callback.jxc4.com/fn/msg" kuaiShouAppId = "ks680887971696897880" kuaiShouAppSecret = "1wShCPqUzhg8W1vcb8OdvA" +# uniApp 消息推送授权 +uniAppAppKey = "Iogz63Q1HL7R4dB8F4Kbn5" +uniAppMasterSecret = "J7pU14SwCC7SoUntXJghj8" +uniAppAppId = "dqxDP9HwHc5B1dd2db4ek2" +uniAppAppSecret = "wX4n8IusDn7PfxkGmypzp5" + #uu跑腿 uuAppID="55c4542ae60e4d348edcfc93b06dd302" uuAppKey="76b362c06b1b4baa9e47bab6387a5356" diff --git a/controllers/auth2.go b/controllers/auth2.go index 2b73a70ea..307d2543a 100644 --- a/controllers/auth2.go +++ b/controllers/auth2.go @@ -3,6 +3,7 @@ package controllers import ( "encoding/base64" "fmt" + "git.rosy.net.cn/jx-callback/business/jxstore/cms" "net/http" "strings" @@ -109,6 +110,7 @@ func (c *Auth2Controller) TiktokDecrypt() { // @Param authSecret formData string true "不同登录类型的登录秘密,如果是localpass登录类型,是md5后的值(空串不要md5)" // @Param authID formData string false "登录ID,登录类型为localpass时依赖于authIDType,其它为相应登录类型的id" // @Param authIDType formData string false "只有在登录类型为localpass时,才有意义,分别为:userid2:用户名,email,mobile" +// @Param cId formData string false "用户手机设备id,只有app登录时做消息通知才有意义!登录时更新此字段!" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult // @router /Login [post] @@ -139,6 +141,9 @@ func (c *Auth2Controller) Login() { } retVal = authInfo } + if params.CId != "" && authInfo != nil { + err = cms.SetUserCId(authInfo.UserID, params.CId) + } return retVal, "", err }) } diff --git a/globals/api/api.go b/globals/api/api.go index 9f310793c..2c7eeb391 100644 --- a/globals/api/api.go +++ b/globals/api/api.go @@ -8,6 +8,7 @@ import ( "git.rosy.net.cn/baseapi/platformapi/qywxapi" "git.rosy.net.cn/baseapi/platformapi/tiktok" tiktokShop "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api" + "git.rosy.net.cn/baseapi/platformapi/uinapp" "git.rosy.net.cn/baseapi/platformapi/uuptapi" "git.rosy.net.cn/baseapi/platformapi/xpyunapi" @@ -130,6 +131,7 @@ var ( LogisticsApi *ali_logistics_query.API // 阿里云提供获取物流订单的配送信息 KuaiShouApi *kuaishou_mini.API // 快手平台 + UniAppApi *uinapp.API // uinapp 消息通知 ) func init() { @@ -329,4 +331,5 @@ func Init() { EnterpriseChatHeadApi = enterprise.New("ww9a156bfa070e1857", "0jBdCjSmoFiOoHIXyeCK9VbGQ82fVNJZ8uMl6JNN7X4") // 通讯录 EnterpriseChatMin = enterprise.NewMin("ww9a156bfa070e1857", "JQsEmSTltHhNgdPIT320YJFphiYmRs-YZa-rCBwplss") // 小程序 KuaiShouApi = kuaishou_mini.New(beego.AppConfig.DefaultString("kuaiShouAppSecret", ""), beego.AppConfig.DefaultString("kuaiShouAppId", "")) + UniAppApi = uinapp.NewUinappApi(beego.AppConfig.DefaultString("uniAppAppId", ""), beego.AppConfig.DefaultString("uniAppAppKey", ""), beego.AppConfig.DefaultString("uniAppAppSecret", ""), beego.AppConfig.DefaultString("uniAppMasterSecret", "")) }