diff --git a/api/consts/consts.go b/api/consts/consts.go index 04fe0472..33b879dd 100644 --- a/api/consts/consts.go +++ b/api/consts/consts.go @@ -57,6 +57,7 @@ const ( ZoneVIPConfigKey = "zone_vip_config" StreamerScoreFormulaKey = "streamer_score_formula" HvyogoSingleDistributeChargePercentageKey = "hvyogo_single_distribute_charge_percentage" + AutoResponseKey = "auto_response" ) // del_flag diff --git a/api/errcode/errcode.go b/api/errcode/errcode.go index 220b610f..dd833d5c 100644 --- a/api/errcode/errcode.go +++ b/api/errcode/errcode.go @@ -132,6 +132,7 @@ var ErrCodeMsgMap = map[ErrCode]string{ ErrCodeContactCustomerServiceSrvFail: "联系客服服务错误", ErrCodeContactCustomerServiceNotExist: "联系客服不存在", + ErrCodeAutoResponseSrvFail: "自动回复服务错误", ErrCodeImageAuditSrvFail: "图像审核服务错误", ErrCodeImageAuditNotExist: "图像审核不存在", @@ -419,6 +420,7 @@ const ( ErrCodeContactCustomerServiceSrvOk ErrCode = ErrCodeOk ErrCodeContactCustomerServiceSrvFail ErrCode = -19001 // 联系客服服务错误 ErrCodeContactCustomerServiceNotExist ErrCode = -19002 // 联系客服不存在 + ErrCodeAutoResponseSrvFail ErrCode = -19003 // 自动回复服务错误 // ImageAudit: 20xxx ErrCodeImageAuditSrvOk ErrCode = ErrCodeOk diff --git a/apollostruct/auto_response.go b/apollostruct/auto_response.go new file mode 100644 index 00000000..6703fb53 --- /dev/null +++ b/apollostruct/auto_response.go @@ -0,0 +1,7 @@ +package apollostruct + +type AutoResponseCfg struct { + StartTime string `json:"start_time"` + EndTime string `json:"end_time"` + Message string `json:"message"` +} diff --git a/app/mix/dao/mongo.go b/app/mix/dao/mongo.go index 2c327b66..001cbbe2 100644 --- a/app/mix/dao/mongo.go +++ b/app/mix/dao/mongo.go @@ -163,8 +163,9 @@ const ( COLRealNameAuthentication = "realname_authentication" COLRealNameAuthenticationHis = "realname_authentication_his" - DBContactCustomerService = "contact_customer_service" - COLContactCustomerService = "contact_customer_service" + DBContactCustomerService = "contact_customer_service" + COLContactCustomerService = "contact_customer_service" + COLAutoResponseCreateTimes = "auto_reponse_create_times" DBImageAudit = "image_audit" COLImageAudit = "image_audit" @@ -460,6 +461,11 @@ func (m *Mongo) getColContactCustomerService() *qmgo.Collection { return m.clientMix.Database(DBContactCustomerService).Collection(COLContactCustomerService) } +// 联系客服自动回复创建频次表 +func (m *Mongo) getColAutoResponseCreateTimes() *qmgo.Collection { + return m.clientMix.Database(DBContactCustomerService).Collection(COLAutoResponseCreateTimes) +} + // 图像审核表 func (m *Mongo) getColImageAudit() *qmgo.Collection { return m.clientMix.Database(DBImageAudit).Collection(COLImageAudit) @@ -3309,6 +3315,32 @@ func (m *Mongo) GetContactCustomerServiceListBySessionId(ctx *gin.Context, req * return list, err } +// 自动回复创建频次 +func (m *Mongo) GetAndUpdateAutoResponseCreateTimes(ctx *gin.Context, mid int64) (autoResponseCreateTimes *dbstruct.AutoResponseCreateTimes, err error) { + col := m.getColAutoResponseCreateTimes() + + change := qmgo.Change{ + Update: qmgo.M{"$inc": qmgo.M{"create_times": 1}}, + Upsert: true, + ReturnNew: false, + } + + autoResponseCreateTimesInstance := dbstruct.AutoResponseCreateTimes{} + if err = col.Find(ctx, qmgo.M{"_id": mid}).Apply(change, &autoResponseCreateTimesInstance); err != nil { + logger.Error("change error : %v", err) + return + } + + return &autoResponseCreateTimesInstance, err +} + +// 清空动态创建频次表 +func (m *Mongo) ClearAutoResponseCreateTimes(ctx *gin.Context) error { + col := m.getColAutoResponseCreateTimes() + _, err := col.RemoveAll(ctx, qmgo.M{}) + return err +} + // 图像审核相关 func (m *Mongo) CreateImageAudit(ctx *gin.Context, imageaudit *dbstruct.ImageAudit) error { col := m.getColImageAudit() diff --git a/app/mix/service/apiservice.go b/app/mix/service/apiservice.go index 5df27ac9..1268adea 100644 --- a/app/mix/service/apiservice.go +++ b/app/mix/service/apiservice.go @@ -1997,6 +1997,43 @@ func (s *Service) ApiCreateContactCustomerService(ctx *gin.Context, req *contact ec = errcode.ErrCodeContactCustomerServiceSessionSrvFail return } + + //获取自动信息 + cfg := &apollostruct.AutoResponseCfg{} + err = apollo.GetJson(consts.AutoResponseKey, &cfg, apollo.ApolloOpts().SetNamespace("application")) + if err != nil { + logger.Error("Apollo read failed : %v", err) + return errcode.ErrCodeApolloReadFail + } + + //如果在自动回复时间段,则创建一条自动回复信息 + now := time.Now() + st := util.GetTimestampAtThisMomentForTime(now, cfg.StartTime) + et := util.GetTimestampAtThisMomentForTime(now, cfg.EndTime) + ct := util.DerefInt64(req.ContactCustomerService.Ct) + if ct > st && ct < et { + createTimes, err := _DefaultAutoResponseCreateTimes.OpGetAndUpdate(ctx, req.BaseRequest.Mid) + if err != nil { + logger.Error("_DefaultAutoResponseCreateTimes OpGetAndUpdate fail, req: %v, err: %v", util.ToJson(req), err) + ec = errcode.ErrCodeAutoResponseSrvFail + return + } + if createTimes.CreateTimes == 0 { + err := _DefaultContactCustomerService.OpCreate(ctx, &contact_customer_service_proto.OpCreateReq{ + ContactCustomerService: &dbstruct.ContactCustomerService{ + SessionId: req.ContactCustomerService.SessionId, + Predicate: goproto.Int64(consts.ContactCustomerService_FromSupportor), + Message: goproto.String(cfg.Message), + IsRead: goproto.Int64(consts.ContactCustomerService_NotRead), + }, + }) + if err != nil { + logger.Error("OpCreate fail, req: %v, err: %v", util.ToJson(req), err) + ec = errcode.ErrCodeContactCustomerServiceSrvFail + return + } + } + } return } diff --git a/app/mix/service/cronservice.go b/app/mix/service/cronservice.go index b1c58abf..1f8bbc4b 100644 --- a/app/mix/service/cronservice.go +++ b/app/mix/service/cronservice.go @@ -85,6 +85,7 @@ func (s *CronService) Init(c any) (exec xxl.Executor, err error) { exec.RegTask("video_moderation_batch_his", s.VideoModerationBatchHis) exec.RegTask("clear_expired_btcb", s.ClearExpiredBtcb) exec.RegTask("reload_blocked_from_being_searched_list", s.ReloadBlockedFromBeingSearchedList) + exec.RegTask("clear_auto_response_create_times", s.ClearAutoResponseCreateTimes) exec.LogHandler(customLogHandle) //注册任务handler diff --git a/app/mix/service/logic/auto_response_create_times.go b/app/mix/service/logic/auto_response_create_times.go new file mode 100644 index 00000000..f56c82e6 --- /dev/null +++ b/app/mix/service/logic/auto_response_create_times.go @@ -0,0 +1,40 @@ +package logic + +import ( + "service/app/mix/dao" + "service/dbstruct" + "service/library/logger" + + "github.com/gin-gonic/gin" +) + +type AutoResponseCreateTimes struct { + store *dao.Store +} + +func NewAutoResponseCreateTimes(store *dao.Store) (a *AutoResponseCreateTimes) { + a = &AutoResponseCreateTimes{ + store: store, + } + return +} + +func (p *AutoResponseCreateTimes) OpGetAndUpdate(ctx *gin.Context, mid int64) (*dbstruct.AutoResponseCreateTimes, error) { + + vericodeSendTimes, err := p.store.GetAndUpdateAutoResponseCreateTimes(ctx, mid) + if err != nil { + logger.Error("GetAndUpdateAutoResponseCreateTimes fail, err: %v", err) + return nil, err + } + + return vericodeSendTimes, nil +} + +func (p *AutoResponseCreateTimes) OpClear(ctx *gin.Context) error { + err := p.store.ClearAutoResponseCreateTimes(ctx) + if err != nil { + logger.Error("ClearAutoResponseCreateTimes fail, err: %v", err) + return err + } + return nil +} diff --git a/app/mix/service/service.go b/app/mix/service/service.go index 97361b59..1c2592de 100644 --- a/app/mix/service/service.go +++ b/app/mix/service/service.go @@ -149,6 +149,7 @@ var ( _DefaultStreamerScore *logic.StreamerScore _DefaultWorkerId *logic.WorkerId _DefaultSingleDistributeHis *logic.SingleDistributeHis + _DefaultAutoResponseCreateTimes *logic.AutoResponseCreateTimes ) type Service struct { diff --git a/app/mix/service/xxljob_tasks.go b/app/mix/service/xxljob_tasks.go index d4ffb387..9df640b8 100644 --- a/app/mix/service/xxljob_tasks.go +++ b/app/mix/service/xxljob_tasks.go @@ -592,3 +592,14 @@ func (s *CronService) ReloadBlockedFromBeingSearchedList(ctx context.Context, pa logger.Info("Refresh blocked-from-being-searched list cached in redis accomplished...") return "Refresh blocked-from-being-searched list cached in redis accomplished" } + +func (s *CronService) ClearAutoResponseCreateTimes(ctx context.Context, param *xxl.RunReq) (msg string) { + logger.Info("task %v param: %v log_id: %v", param.ExecutorHandler, param.ExecutorParams, xxl.Int64ToStr(param.LogID)) + logger.Info("Clearing auto_response_create_times collection...") + if err := _DefaultAutoResponseCreateTimes.OpClear(&gin.Context{}); err != nil { + logger.Error("Clear auto_response_create_times collection fail: %v", err) + return fmt.Sprintf("Clear auto_response_create_times collection fail: %v", err) + } + logger.Info("auto_response_create_times collection has been cleared") + return "auto_response_create_times collection has been cleared" +} diff --git a/bizcommon/util/util.go b/bizcommon/util/util.go index 019f1716..ff51e8c3 100644 --- a/bizcommon/util/util.go +++ b/bizcommon/util/util.go @@ -180,6 +180,20 @@ func GetDayStartTimeStamp(t time.Time) int64 { return duetimecst.Unix() } +// 获取当日该时间时间戳 +func GetTimestampAtThisMomentForTime(t time.Time, layout string) int64 { + loc, err := time.LoadLocation("Asia/Shanghai") + if err != nil { + loc = time.FixedZone("CST", 8*3600) + } + timeStr := fmt.Sprintf("%02d-%02d-%02d %s", t.Year(), t.Month(), t.Day(), layout) + duetimecst, err := time.ParseInLocation("2006-1-2 15:04:05", timeStr, loc) + if err != nil { + logger.Error("parse error : %v", err) + } + return duetimecst.Unix() +} + // 随机生成字符串 func RandomString(l int) string { str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" diff --git a/dbstruct/auto_response_create_times.go b/dbstruct/auto_response_create_times.go new file mode 100644 index 00000000..056a7be1 --- /dev/null +++ b/dbstruct/auto_response_create_times.go @@ -0,0 +1,6 @@ +package dbstruct + +type AutoResponseCreateTimes struct { + Id int64 `json:"id" bson:"_id"` //id,主播的mid + CreateTimes int64 `json:"create_times" bson:"create_times"` //发送次数 +}