Ver código fonte

新增最后消息时间字段

dxc 2 anos atrás
pai
commit
c8da12c1e4

+ 3 - 22
doc/cb_customer.sql

@@ -1,26 +1,4 @@
-/*
- Navicat Premium Data Transfer
 
- Source Server         : 10.8.230.17
- Source Server Type    : MySQL
- Source Server Version : 50635
- Source Host           : 10.8.230.17:3308
- Source Schema         : wechat_cs_online
-
- Target Server Type    : MySQL
- Target Server Version : 50635
- File Encoding         : 65001
-
- Date: 02/04/2024 09:25:30
-*/
-
-SET NAMES utf8mb4;
-SET FOREIGN_KEY_CHECKS = 0;
-
-DROP TABLE IF EXISTS `cb_customer`;
 CREATE TABLE `cb_customer`  (
   `id` bigint(20) NOT NULL AUTO_INCREMENT,
   `open_kfid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客服ID',
@@ -31,7 +9,7 @@ CREATE TABLE `cb_customer`  (
   `service_state` tinyint(4) NOT NULL DEFAULT -1 COMMENT '会话状态:0未处理,1由智能助手接待,2待接入池排队中,3由人工接待,4已结束/未开始',
   `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
   `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  PRIMARY KEY (`id`) USING BTREE
+  `last_msg_time` bigint(20) NULL DEFAULT NOT NULL COMMENT '最后消息时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `open_kfid`(`open_kfid`, `external_userid`) USING BTREE
 ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '客户信息表' ROW_FORMAT = Compact;
-
-SET FOREIGN_KEY_CHECKS = 1;

+ 4 - 3
go.mod

@@ -2,14 +2,16 @@ module callback
 
 go 1.20
 
-require github.com/zeromicro/go-zero v1.6.3
+require (
+	github.com/valyala/fastjson v1.6.4
+	github.com/zeromicro/go-zero v1.6.3
+)
 
 require (
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cenkalti/backoff/v4 v4.2.1 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
-	github.com/elliotchance/pie v1.39.0 // indirect
 	github.com/fatih/color v1.16.0 // indirect
 	github.com/go-logr/logr v1.3.0 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
@@ -29,7 +31,6 @@ require (
 	github.com/prometheus/procfs v0.12.0 // indirect
 	github.com/redis/go-redis/v9 v9.4.0 // indirect
 	github.com/spaolacci/murmur3 v1.1.0 // indirect
-	github.com/valyala/fastjson v1.6.4 // indirect
 	go.opentelemetry.io/otel v1.19.0 // indirect
 	go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect

+ 0 - 11
go.sum

@@ -14,12 +14,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/elliotchance/pie v1.39.0 h1:oudoOFLPYvWwsJ/J2dFv3uHkdHdq7oSv8aNMWqUQVv8=
-github.com/elliotchance/pie v1.39.0/go.mod h1:W/nLuTGZ1dLKzRS0Z2g2N2evWzMenuDnBhk0s6Y9k54=
-github.com/elliotchance/testify-stats v1.0.0/go.mod h1:Mc25k7L4E65uf6CfW+s/pY04XcoiqQBrfIRsWQcgweA=
 github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
 github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
-github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
 github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -40,9 +36,6 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
-github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
-github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -52,9 +45,6 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
 github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA=
 github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY=
 github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
@@ -79,7 +69,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=

+ 21 - 11
internal/logic/callback/callbackmsglogic.go

@@ -224,10 +224,10 @@ func KfAccountAuthChangeHandle(svcCtx *svc.ServiceContext, ct types.EventContent
 // 消息额外处理
 func msgTypeTextHandle(svcCtx *svc.ServiceContext, msg *model.CbMsg) {
 	key := fmt.Sprintf("cb_user_state:%v", msg.ExternalUserid)
-	v, err := svcCtx.Redis.Get(key)
-	if err != nil || v == "" {
+	v, _ := svcCtx.Redis.Get(key)
+	c, err := svcCtx.CbCustomerModel.GetCustomerByExternalUserid(msg.OpenKfid, msg.ExternalUserid)
+	if err != nil || c == nil || c.Id == 0 {
 		//新增用户
-		c, err := svcCtx.CbCustomerModel.GetCustomerByExternalUserid(msg.OpenKfid, msg.ExternalUserid)
 		if err != nil || c.Id == 0 {
 			//此处因为该接口查询多个用户时,如果其中一个超过24小时不回复,会导致所有信息都不会返回,因此这里单独请求
 			err, clist := svcCtx.WxApi.GetCustomerList([]string{msg.ExternalUserid})
@@ -244,6 +244,7 @@ func msgTypeTextHandle(svcCtx *svc.ServiceContext, msg *model.CbMsg) {
 			cnow := time.Now()
 			c.CreatedAt = cnow
 			c.UpdatedAt = cnow
+			c.LastMsgTime = msg.SendTime
 			_, err = svcCtx.CbCustomerModel.Insert(nil, c)
 			if err != nil {
 				logx.Error("Insert cb_customer fail ", err)
@@ -253,7 +254,16 @@ func msgTypeTextHandle(svcCtx *svc.ServiceContext, msg *model.CbMsg) {
 				v = fmt.Sprintf("%v", c.ServiceState)
 			}
 		}
+	} else {
+		//超过2天把状态设置成0
+		if c.LastMsgTime != 0 {
+			if msg.SendTime-c.LastMsgTime > int64(48*time.Hour.Seconds()) {
+				v = "0"
+			}
+		}
+		_ = svcCtx.CbCustomerModel.UpdateCustomerLastMsgTime(c.OpenKfid, c.ExternalUserid, msg.SendTime)
 	}
+
 	if v == "-1" || v == "4" {
 		//获取会话状态
 		err, sessionState := svcCtx.WxApi.GetSessionState(msg.OpenKfid, msg.ExternalUserid)
@@ -261,9 +271,9 @@ func msgTypeTextHandle(svcCtx *svc.ServiceContext, msg *model.CbMsg) {
 			logx.Error("GetSessionState fail ", err)
 			return
 		}
-		err = svcCtx.CbCustomerModel.UpdateServiceState(msg.OpenKfid, msg.ExternalUserid, sessionState.ServiceState)
+		err = svcCtx.CbCustomerModel.UpdateCustomerState(msg.OpenKfid, msg.ExternalUserid, sessionState.ServiceState)
 		if err != nil {
-			logx.Error("UpdateServiceState fail ", err)
+			logx.Error("UpdateCustomerState fail ", err)
 			return
 		}
 		_ = svcCtx.Redis.Set(key, fmt.Sprintf("%v", sessionState.ServiceState))
@@ -281,9 +291,9 @@ func msgTypeTextHandle(svcCtx *svc.ServiceContext, msg *model.CbMsg) {
 			logx.Error("GetSessionState fail ", err)
 			return
 		}
-		err = svcCtx.CbCustomerModel.UpdateServiceState(msg.OpenKfid, msg.ExternalUserid, sessionState.ServiceState)
+		err = svcCtx.CbCustomerModel.UpdateCustomerState(msg.OpenKfid, msg.ExternalUserid, sessionState.ServiceState)
 		if err != nil {
-			logx.Error("UpdateServiceState fail ", err)
+			logx.Error("UpdateCustomerState fail ", err)
 			return
 		}
 		_ = svcCtx.Redis.Set(key, fmt.Sprintf("%v", sessionState.ServiceState))
@@ -308,9 +318,9 @@ func msgTypeEventHandle(svcCtx *svc.ServiceContext, msg *model.CbMsg) {
 			logx.Error("GetSessionState fail ", err)
 			return
 		}
-		err = svcCtx.CbCustomerModel.UpdateServiceState(msg.OpenKfid, msg.ExternalUserid, sessionState.ServiceState)
+		err = svcCtx.CbCustomerModel.UpdateCustomerState(msg.OpenKfid, msg.ExternalUserid, sessionState.ServiceState)
 		if err != nil {
-			logx.Error("UpdateServiceState fail ", err)
+			logx.Error("UpdateCustomerState fail ", err)
 			return
 		}
 		_ = svcCtx.Redis.Set(key, fmt.Sprintf("%v", sessionState.ServiceState))
@@ -346,9 +356,9 @@ func InitCustomerState(svcCtx *svc.ServiceContext) {
 					}
 					sessionState.ServiceState = 2
 				}
-				err = svcCtx.CbCustomerModel.UpdateServiceState(customer.OpenKfid, customer.ExternalUserid, sessionState.ServiceState)
+				err = svcCtx.CbCustomerModel.UpdateCustomerState(customer.OpenKfid, customer.ExternalUserid, sessionState.ServiceState)
 				if err != nil {
-					logx.Error("UpdateServiceState fail ", err)
+					logx.Error("UpdateCustomerState fail ", err)
 					continue
 				}
 				_ = svcCtx.Redis.Set(key, fmt.Sprintf("%v", sessionState.ServiceState))

+ 9 - 2
model/cbcustomermodel.go

@@ -14,7 +14,8 @@ type (
 		cbCustomerModel
 		GetCustomerByExternalUserid(openKfid, externalUserid string) (d *CbCustomer, err error)
 		GetCustomerByPage(page, size int) (list []CbCustomer, err error)
-		UpdateServiceState(openKfid, externalUserid string, state int) (err error)
+		UpdateCustomerState(openKfid, externalUserid string, state int) (err error)
+		UpdateCustomerLastMsgTime(openKfid, externalUserid string, t int64) (err error)
 	}
 
 	customCbCustomerModel struct {
@@ -37,12 +38,18 @@ func (m *customCbCustomerModel) GetCustomerByExternalUserid(openKfid, externalUs
 	return
 }
 
-func (m *customCbCustomerModel) UpdateServiceState(openKfid, externalUserid string, state int) (err error) {
+func (m *customCbCustomerModel) UpdateCustomerState(openKfid, externalUserid string, state int) (err error) {
 	query := fmt.Sprintf("update %s set `service_state` = ? where `open_kfid` = ? AND `external_userid` = ?", m.table)
 	_, err = m.conn.Exec(query, state, openKfid, externalUserid)
 	return err
 }
 
+func (m *customCbCustomerModel) UpdateCustomerLastMsgTime(openKfid, externalUserid string, t int64) (err error) {
+	query := fmt.Sprintf("update %s set `last_msg_time` = ? where `open_kfid` = ? AND `external_userid` = ?", m.table)
+	_, err = m.conn.Exec(query, t, openKfid, externalUserid)
+	return err
+}
+
 func (m *customCbCustomerModel) GetCustomerByPage(page, size int) (list []CbCustomer, err error) {
 	query := fmt.Sprintf("select * from %s where service_state != 4 limit ?,?", m.table)
 	err = m.conn.QueryRows(&list, query, (page-1)*size, size)

+ 20 - 4
model/cbcustomermodel_gen.go

@@ -26,6 +26,7 @@ type (
 	cbCustomerModel interface {
 		Insert(ctx context.Context, data *CbCustomer) (sql.Result, error)
 		FindOne(ctx context.Context, id int64) (*CbCustomer, error)
+		FindOneByOpenKfidExternalUserid(ctx context.Context, openKfid string, externalUserid string) (*CbCustomer, error)
 		Update(ctx context.Context, data *CbCustomer) error
 		Delete(ctx context.Context, id int64) error
 	}
@@ -45,6 +46,7 @@ type (
 		ServiceState   int64     `db:"service_state"`   // 会话状态:0未处理,1由智能助手接待,2待接入池排队中,3由人工接待,4已结束/未开始
 		CreatedAt      time.Time `db:"created_at"`
 		UpdatedAt      time.Time `db:"updated_at"`
+		LastMsgTime    int64     `db:"last_msg_time"` // 最后消息时间
 	}
 )
 
@@ -82,15 +84,29 @@ func (m *defaultCbCustomerModel) FindOne(ctx context.Context, id int64) (*CbCust
 	}
 }
 
+func (m *defaultCbCustomerModel) FindOneByOpenKfidExternalUserid(ctx context.Context, openKfid string, externalUserid string) (*CbCustomer, error) {
+	var resp CbCustomer
+	query := fmt.Sprintf("select %s from %s where `open_kfid` = ? and `external_userid` = ? limit 1", cbCustomerRows, m.table)
+	err := m.conn.QueryRowCtx(ctx, &resp, query, openKfid, externalUserid)
+	switch err {
+	case nil:
+		return &resp, nil
+	case sqlc.ErrNotFound:
+		return nil, ErrNotFound
+	default:
+		return nil, err
+	}
+}
+
 func (m *defaultCbCustomerModel) Insert(ctx context.Context, data *CbCustomer) (sql.Result, error) {
-	query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?)", m.table, cbCustomerRowsExpectAutoSet)
-	ret, err := m.conn.ExecCtx(ctx, query, data.OpenKfid, data.ExternalUserid, data.Nickname, data.Avatar, data.Gender, data.ServiceState)
+	query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?)", m.table, cbCustomerRowsExpectAutoSet)
+	ret, err := m.conn.ExecCtx(ctx, query, data.OpenKfid, data.ExternalUserid, data.Nickname, data.Avatar, data.Gender, data.ServiceState, data.LastMsgTime)
 	return ret, err
 }
 
-func (m *defaultCbCustomerModel) Update(ctx context.Context, data *CbCustomer) error {
+func (m *defaultCbCustomerModel) Update(ctx context.Context, newData *CbCustomer) error {
 	query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, cbCustomerRowsWithPlaceHolder)
-	_, err := m.conn.ExecCtx(ctx, query, data.OpenKfid, data.ExternalUserid, data.Nickname, data.Avatar, data.Gender, data.ServiceState, data.Id)
+	_, err := m.conn.ExecCtx(ctx, query, newData.OpenKfid, newData.ExternalUserid, newData.Nickname, newData.Avatar, newData.Gender, newData.ServiceState, newData.LastMsgTime, newData.Id)
 	return err
 }