renjiaojiao 1 månad sedan
förälder
incheckning
6d0bf6c59b

+ 2 - 2
api/etc/biservice-api.yaml

@@ -11,7 +11,7 @@ Timeout: 100000
 GatewayRpcConf:
   Etcd:
     Hosts:
-      - 172.31.31.203:2379
+      - 172.31.31.205:2379
     Key: gatewayDemo.rpc
   Timeout: 300000
 Logx:
@@ -21,4 +21,4 @@ Logx:
   KeepDays: 10
 ResourceCenterKey: "resource.rpc" #资源中台rpc
 UserCenterKey: "usercenter.rpc" #用户中台rpc
-MessageCenterKey: message.rpc
+MessageCenterKey: "message.rpc"

+ 3 - 0
api/internal/logic/materialsavelogic.go

@@ -8,6 +8,7 @@ import (
 	"context"
 	"fmt"
 	"github.com/zeromicro/go-zero/core/logx"
+	"log"
 	"strings"
 )
 
@@ -43,11 +44,13 @@ func (l *MaterialSaveLogic) MaterialSave(req *types.MaterialSaveReq) (resp *type
 		return &types.BiResp{Error_code: res.ErrorCode, Error_msg: res.ErrorMsg}, err
 	}
 	msgId := res.MsgId
+	log.Println(msgId)
 	res1, err := l.svcCtx.MessageCenterRpc.UpdateMsgSummary(l.ctx, &messageclient.UpdateMsgSummaryReq{
 		MsgLogId: msgId,
 		GroupId:  11,
 		MsgType:  14,
 	})
+	log.Println(res1.Code, res1.Message)
 	if res1.Code < 1 {
 		return &types.BiResp{Error_code: -1, Error_msg: res1.Message}, err
 	}

+ 9 - 9
api/internal/svc/servicecontext.go

@@ -24,23 +24,23 @@ func NewServiceContext(c config.Config) *ServiceContext {
 		BiServiceRpc: biservice.NewBiService(zrpc.MustNewClient(c.BiServiceRpc)),
 		ResourceCenterRpc: resource.NewResource(zrpc.MustNewClient(zrpc.RpcClientConf{
 			Etcd: discov.EtcdConf{
-				Hosts: c.BiServiceRpc.Etcd.Hosts,
-				//Hosts: []string{"192.168.3.149:2379"},
-				Key: c.ResourceCenterKey,
+				//Hosts: c.BiServiceRpc.Etcd.Hosts,
+				Hosts: []string{"172.31.31.205:2379"},
+				Key:   c.ResourceCenterKey,
 			},
 		})),
 		UserCenterRpc: usercenter.NewUserCenter(zrpc.MustNewClient(zrpc.RpcClientConf{
 			Etcd: discov.EtcdConf{
-				Hosts: c.BiServiceRpc.Etcd.Hosts,
-				//Hosts: []string{"192.168.3.149:2379"},
-				Key: c.UserCenterKey,
+				//Hosts: c.BiServiceRpc.Etcd.Hosts,
+				Hosts: []string{"172.31.31.205:2379"},
+				Key:   c.UserCenterKey,
 			},
 		})),
 		MessageCenterRpc: messageclient.NewMessage(zrpc.MustNewClient(zrpc.RpcClientConf{
 			Etcd: discov.EtcdConf{
-				Hosts: c.BiServiceRpc.Etcd.Hosts,
-				//Hosts: []string{"192.168.3.149:2379"},
-				Key: c.MessageCenterKey,
+				//Hosts: c.BiServiceRpc.Etcd.Hosts,
+				Hosts: []string{"172.31.31.205:2379"},
+				Key:   c.MessageCenterKey,
 			},
 		})),
 	}

+ 6 - 0
go.mod

@@ -10,8 +10,12 @@ require (
 	bp.jydev.jianyu360.cn/BaseService/gateway v1.3.4
 	bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.3
 	bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.16
+	github.com/disintegration/imaging v1.6.2
+	github.com/fogleman/gg v1.3.0
 	github.com/gogf/gf/v2 v2.6.2
+	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
 	github.com/nsqio/go-nsq v1.1.0
+	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/tjfoc/gmsm v1.4.1
 	github.com/xuri/excelize/v2 v2.8.0
 	github.com/zeromicro/go-zero v1.6.1
@@ -48,6 +52,7 @@ require (
 	github.com/go-sql-driver/mysql v1.7.1 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
+	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 	github.com/golang/mock v1.6.0 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
@@ -114,6 +119,7 @@ require (
 	go.uber.org/multierr v1.9.0 // indirect
 	go.uber.org/zap v1.24.0 // indirect
 	golang.org/x/crypto v0.16.0 // indirect
+	golang.org/x/image v0.11.0 // indirect
 	golang.org/x/net v0.19.0 // indirect
 	golang.org/x/oauth2 v0.13.0 // indirect
 	golang.org/x/sync v0.5.0 // indirect

+ 11 - 0
go.sum

@@ -171,6 +171,8 @@ github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zA
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 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/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
+github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
 github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/donnie4w/go-logger v0.0.0-20170827050443-4740c51383f4/go.mod h1:L7S4x0R7vv3xoOhGuyAJyCO2MYzWOpccM4Isn8jIUgY=
@@ -198,6 +200,8 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF
 github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
 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/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
+github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
 github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
 github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
 github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
@@ -312,6 +316,8 @@ github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw
 github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -596,6 +602,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
+github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
+github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE=
 github.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY=
@@ -723,6 +731,8 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
 github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
 github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
 github.com/smartystreets/gunit v1.4.2/go.mod h1:ZjM1ozSIMJlAz/ay4SG8PeKF00ckUp+zMHZXV9/bvak=
@@ -932,6 +942,7 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
 golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=

+ 1 - 0
rpc/biService.proto

@@ -279,6 +279,7 @@ message MaterialSaveResp {
   int64 error_code = 1;
   string error_msg = 2;
   int64 msg_id =3;
+  int64 Material_id = 5;
   repeated string userIdArr = 4;
 }
 

+ 2 - 4
rpc/biservice.go

@@ -9,10 +9,8 @@ import (
 	"bp.jydev.jianyu360.cn/BaseService/biService/rpc/internal/server"
 	"bp.jydev.jianyu360.cn/BaseService/biService/rpc/internal/svc"
 	"bp.jydev.jianyu360.cn/BaseService/biService/rpc/pb"
-	"bp.jydev.jianyu360.cn/BaseService/fileCenter/rpc/filecenter"
 	"flag"
 	"fmt"
-	"github.com/nsqio/go-nsq"
 	"github.com/zeromicro/go-zero/core/conf"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/zrpc"
@@ -43,7 +41,7 @@ func main() {
 	entity.GetHlyj(IC.IC.Hlyj.Appid, IC.IC.Hlyj.Account, IC.IC.Hlyj.Secret, IC.IC.Hlyj.TokenUrl, IC.IC.Hlyj.CallUrl, IC.IC.Hlyj.Integratedid, IC.IC.Hlyj.CallFlag)
 	entity.InitMiddleground(IC.IC.RpcServerConf.Etcd.Hosts, IC.IC.ResourceCenterKey)
 
-	entity.FileCenterRpc = filecenter.NewFileCenter(zrpc.MustNewClient(IC.IC.FileCenterRpc))
+	/*entity.FileCenterRpc = filecenter.NewFileCenter(zrpc.MustNewClient(IC.IC.FileCenterRpc))
 	entity.OssBucketName = IC.IC.OssBucketName
 	entity.OssUrl = IC.IC.OssUrl
 	//nsq
@@ -56,7 +54,7 @@ func main() {
 	err = consumer.ConnectToNSQLookupd(IC.IC.NsqUrl)
 	if err != nil {
 		fmt.Println(err)
-	}
+	}*/
 	s := zrpc.MustNewServer(IC.IC.RpcServerConf, func(grpcServer *grpc.Server) {
 		pb.RegisterBiServiceServer(grpcServer, srv)
 	})

+ 1 - 1
rpc/etc/biservice.yaml

@@ -138,7 +138,7 @@ ResourceCenterKey: resource.rpc
 FileCenterRpc:
   Etcd:
     Hosts:
-      - 127.0.0.1:2379
+      - 172.31.31.205:2379
     Key: filecenter.rpc
 ossBucketName: jytest2022
 ossUrl: https://jytest2022.oss-cn-beijing.aliyuncs.com

+ 51 - 20
rpc/internal/logic/materialsavelogic.go

@@ -1,13 +1,19 @@
 package logic
 
 import (
+	"bp.jydev.jianyu360.cn/BaseService/biService/entity"
 	IC "bp.jydev.jianyu360.cn/BaseService/biService/rpc/internal/config"
 	"bp.jydev.jianyu360.cn/BaseService/biService/rpc/internal/svc"
 	"bp.jydev.jianyu360.cn/BaseService/biService/rpc/pb"
 	"bp.jydev.jianyu360.cn/BaseService/biService/service"
+	fpb "bp.jydev.jianyu360.cn/BaseService/fileCenter/rpc/pb"
 	"context"
 	"fmt"
+	"github.com/gogf/gf/v2/util/gconv"
 	"github.com/zeromicro/go-zero/core/logx"
+	"log"
+	"path"
+	"strings"
 )
 
 type MaterialSaveLogic struct {
@@ -27,7 +33,7 @@ func NewMaterialSaveLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Mate
 func (l *MaterialSaveLogic) MaterialSave(in *pb.MaterialSaveReq) (*pb.MaterialSaveResp, error) {
 	// todo: add your logic here and delete this line
 	//先插入消息记录表
-	msgId, err := service.MaterialSave(in, IC.IC.MaterialMsg.Title, fmt.Sprintf(IC.IC.MaterialMsg.Title, in.CreateUser))
+	msgId, mid, err := service.MaterialSave(in, IC.IC.MaterialMsg.Title, fmt.Sprintf(IC.IC.MaterialMsg.Content, in.CreateUser))
 	if msgId == 0 || err != nil {
 		return &pb.MaterialSaveResp{
 			ErrorCode: -1,
@@ -35,28 +41,53 @@ func (l *MaterialSaveLogic) MaterialSave(in *pb.MaterialSaveReq) (*pb.MaterialSa
 			MsgId:     msgId,
 		}, nil
 	}
+
 	//获取分发人的userid
 	userIdArr := service.GetSendUserId(in.ReceiveUserId, in.EntId)
+	log.Println("分发给:", userIdArr)
+
+	if len(strings.Split(in.FileUrl, ",")) > 0 {
+		positionArr := strings.Split(in.ReceiveUserId, ",")
+		for k, v := range strings.Split(in.ReceiveUserName, ",") {
+			for _, val := range strings.Split(in.FileUrl, ",") {
+				imgByte, err := service.PersonImgSaveComposite(val, in.QrcodeUrl, v)
+				if err != nil {
+					return &pb.MaterialSaveResp{
+						ErrorCode: -1,
+						ErrorMsg:  "",
+					}, nil
+				}
+				up, err := entity.FileCenterRpc.Upload(l.ctx, &fpb.UploadReq{
+					File:           imgByte,
+					OssBucketName:  entity.OssBucketName,
+					OssUrl:         entity.OssUrl,
+					Name:           path.Base(in.FileUrl),
+					NeedEncryption: false,
+				})
+				if up == nil || up.Url == "" {
+					return &pb.MaterialSaveResp{
+						ErrorCode: -1,
+						ErrorMsg:  "",
+					}, nil
+				}
+				//key := up.Key
+				ok := service.PersonImageSave(fmt.Sprintf("%s/%s", entity.OssUrl, up.Url), msgId, gconv.Int64(positionArr[k]), mid)
+				if !ok {
+					return &pb.MaterialSaveResp{
+						ErrorCode: -1,
+						ErrorMsg:  "",
+					}, nil
+				}
+			}
+		}
+	}
+
 	return &pb.MaterialSaveResp{
-		ErrorCode: 1,
-		ErrorMsg:  "",
-		MsgId:     msgId,
-		UserIdArr: userIdArr,
+		ErrorCode:  1,
+		ErrorMsg:   "",
+		MsgId:      msgId,
+		MaterialId: mid,
+		UserIdArr:  userIdArr,
 	}, nil
 
-	/*//调用消息中台
-	userResp, err := l.svcCtx.MessageCenterRpc.NewUserMsg(l.ctx, &messageclient.NewUserInsertMsgReq{
-		UserIds:    strings.Join(userIdArr, ","),
-		Title:      IC.IC.MaterialMsg.Title,
-		Content:    fmt.Sprintf(IC.IC.MaterialMsg.Title, in.CreateUser),
-		MsgType:    14,
-		Link:       "",
-		Appid:      "10000",
-		Row4:       "",
-		Identity:   "",
-		AppPushUrl:,
-		WxPushUrl:,
-		IosPushUrl:,
-	})*/
-
 }

+ 91 - 81
rpc/pb/biService.pb.go

@@ -2873,10 +2873,11 @@ type MaterialSaveResp struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	ErrorCode int64    `protobuf:"varint,1,opt,name=error_code,json=errorCode,proto3" json:"error_code,omitempty"`
-	ErrorMsg  string   `protobuf:"bytes,2,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"`
-	MsgId     int64    `protobuf:"varint,3,opt,name=msg_id,json=msgId,proto3" json:"msg_id,omitempty"`
-	UserIdArr []string `protobuf:"bytes,4,rep,name=userIdArr,proto3" json:"userIdArr,omitempty"`
+	ErrorCode  int64    `protobuf:"varint,1,opt,name=error_code,json=errorCode,proto3" json:"error_code,omitempty"`
+	ErrorMsg   string   `protobuf:"bytes,2,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"`
+	MsgId      int64    `protobuf:"varint,3,opt,name=msg_id,json=msgId,proto3" json:"msg_id,omitempty"`
+	MaterialId int64    `protobuf:"varint,5,opt,name=Material_id,json=MaterialId,proto3" json:"Material_id,omitempty"`
+	UserIdArr  []string `protobuf:"bytes,4,rep,name=userIdArr,proto3" json:"userIdArr,omitempty"`
 }
 
 func (x *MaterialSaveResp) Reset() {
@@ -2932,6 +2933,13 @@ func (x *MaterialSaveResp) GetMsgId() int64 {
 	return 0
 }
 
+func (x *MaterialSaveResp) GetMaterialId() int64 {
+	if x != nil {
+		return x.MaterialId
+	}
+	return 0
+}
+
 func (x *MaterialSaveResp) GetUserIdArr() []string {
 	if x != nil {
 		return x.UserIdArr
@@ -3281,89 +3289,91 @@ var file_biService_proto_rawDesc = []byte{
 	0x61, 0x74, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
 	0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6d,
 	0x67, 0x5f, 0x77, 0x65, 0x62, 0x70, 0x61, 0x67, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0a, 0x69, 0x6d, 0x67, 0x57, 0x65, 0x62, 0x70, 0x61, 0x67, 0x65, 0x22, 0x83, 0x01, 0x0a, 0x10,
+	0x0a, 0x69, 0x6d, 0x67, 0x57, 0x65, 0x62, 0x70, 0x61, 0x67, 0x65, 0x22, 0xa4, 0x01, 0x0a, 0x10,
 	0x4d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70,
 	0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01,
 	0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12,
 	0x1b, 0x0a, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01,
 	0x28, 0x09, 0x52, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x15, 0x0a, 0x06,
 	0x6d, 0x73, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6d, 0x73,
-	0x67, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x41, 0x72, 0x72,
-	0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x41, 0x72,
-	0x72, 0x32, 0x89, 0x09, 0x0a, 0x09, 0x42, 0x69, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
-	0x30, 0x0a, 0x0b, 0x6d, 0x79, 0x44, 0x61, 0x74, 0x61, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x0f,
-	0x2e, 0x4d, 0x79, 0x44, 0x61, 0x74, 0x61, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a,
-	0x10, 0x2e, 0x4d, 0x79, 0x44, 0x61, 0x74, 0x61, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73,
-	0x70, 0x12, 0x2d, 0x0a, 0x0a, 0x61, 0x64, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12,
-	0x0e, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x1a,
-	0x0f, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70,
-	0x12, 0x2b, 0x0a, 0x09, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x49, 0x64, 0x12, 0x0e, 0x2e,
-	0x41, 0x64, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0e, 0x2e,
-	0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x29, 0x0a,
-	0x08, 0x64, 0x72, 0x61, 0x77, 0x43, 0x6c, 0x75, 0x65, 0x12, 0x0c, 0x2e, 0x44, 0x72, 0x61, 0x77,
-	0x43, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x72, 0x6f,
-	0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x19, 0x0a, 0x04, 0x43, 0x61, 0x6c, 0x6c,
-	0x12, 0x08, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x07, 0x2e, 0x42, 0x69, 0x52,
-	0x65, 0x73, 0x70, 0x12, 0x35, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
-	0x65, 0x43, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75,
-	0x74, 0x65, 0x43, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x41, 0x64, 0x64, 0x50,
-	0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2d, 0x0a, 0x0a, 0x63, 0x6c,
-	0x75, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x65, 0x49,
-	0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x43, 0x6c, 0x75, 0x65, 0x49,
-	0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x27, 0x0a, 0x07, 0x63, 0x6c, 0x75,
-	0x65, 0x41, 0x64, 0x64, 0x12, 0x0b, 0x2e, 0x43, 0x6c, 0x75, 0x65, 0x41, 0x64, 0x64, 0x52, 0x65,
-	0x71, 0x1a, 0x0f, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65,
-	0x73, 0x70, 0x12, 0x2f, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74,
-	0x54, 0x74, 0x12, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52,
-	0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52,
-	0x65, 0x73, 0x70, 0x12, 0x27, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x46, 0x6f, 0x6c, 0x6c, 0x6f,
-	0x77, 0x12, 0x08, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x43, 0x6c,
-	0x75, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x24, 0x0a, 0x09,
-	0x73, 0x71, 0x6c, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x12, 0x0d, 0x2e, 0x53, 0x71, 0x6c, 0x4d,
-	0x61, 0x6e, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70,
-	0x6c, 0x79, 0x12, 0x1e, 0x0a, 0x06, 0x6d, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0a, 0x2e, 0x4d,
-	0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70,
-	0x6c, 0x79, 0x12, 0x25, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x78, 0x70,
-	0x6f, 0x72, 0x74, 0x12, 0x0a, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a,
-	0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x61, 0x6c, 0x6c,
-	0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0a, 0x2e,
-	0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65,
-	0x70, 0x6c, 0x79, 0x12, 0x24, 0x0a, 0x0b, 0x69, 0x6e, 0x66, 0x6f, 0x4f, 0x70, 0x65, 0x72, 0x61,
-	0x74, 0x65, 0x12, 0x0b, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a,
-	0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2b, 0x0a, 0x0e, 0x67, 0x65, 0x74,
-	0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x2e, 0x43, 0x6f,
-	0x6d, 0x70, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61,
-	0x6e, 0x79, 0x52, 0x65, 0x73, 0x70, 0x12, 0x45, 0x0a, 0x12, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69,
-	0x62, 0x75, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x65, 0x53, 0x68, 0x6f, 0x77, 0x12, 0x16, 0x2e, 0x44,
-	0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x65, 0x53, 0x68, 0x6f,
-	0x77, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
-	0x65, 0x43, 0x6c, 0x75, 0x65, 0x53, 0x68, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x12, 0x24, 0x0a,
-	0x08, 0x73, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x69, 0x6c, 0x12, 0x0e, 0x2e, 0x45, 0x78, 0x70, 0x6f,
-	0x72, 0x74, 0x42, 0x79, 0x44, 0x62, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65,
-	0x70, 0x6c, 0x79, 0x12, 0x1e, 0x0a, 0x06, 0x75, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x0a, 0x2e,
-	0x55, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65,
-	0x70, 0x6c, 0x79, 0x12, 0x28, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
-	0x6e, 0x4d, 0x61, 0x69, 0x6c, 0x12, 0x0c, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x69, 0x6c,
-	0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x30, 0x0a,
-	0x0d, 0x61, 0x64, 0x64, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x0e,
-	0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x0f,
-	0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12,
-	0x2d, 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x65, 0x42, 0x79, 0x50,
-	0x68, 0x6f, 0x6e, 0x65, 0x12, 0x0e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x75, 0x6c,
-	0x65, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x31,
-	0x0a, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x65, 0x42, 0x79,
-	0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x10, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72,
-	0x43, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c,
-	0x79, 0x12, 0x2a, 0x0a, 0x0c, 0x66, 0x69, 0x6e, 0x64, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x66,
-	0x6f, 0x12, 0x10, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x66, 0x6f,
-	0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x29, 0x0a,
-	0x0f, 0x67, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x4c, 0x69, 0x73, 0x74,
-	0x12, 0x0c, 0x2e, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x08,
-	0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x33, 0x0a, 0x0c, 0x4d, 0x61, 0x74, 0x65,
-	0x72, 0x69, 0x61, 0x6c, 0x53, 0x61, 0x76, 0x65, 0x12, 0x10, 0x2e, 0x4d, 0x61, 0x74, 0x65, 0x72,
-	0x69, 0x61, 0x6c, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x4d, 0x61, 0x74,
-	0x65, 0x72, 0x69, 0x61, 0x6c, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x42, 0x06, 0x5a,
-	0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x67, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x4d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f,
+	0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x4d, 0x61, 0x74, 0x65, 0x72, 0x69,
+	0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x41, 0x72,
+	0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x41,
+	0x72, 0x72, 0x32, 0x89, 0x09, 0x0a, 0x09, 0x42, 0x69, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+	0x12, 0x30, 0x0a, 0x0b, 0x6d, 0x79, 0x44, 0x61, 0x74, 0x61, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12,
+	0x0f, 0x2e, 0x4d, 0x79, 0x44, 0x61, 0x74, 0x61, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71,
+	0x1a, 0x10, 0x2e, 0x4d, 0x79, 0x44, 0x61, 0x74, 0x61, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65,
+	0x73, 0x70, 0x12, 0x2d, 0x0a, 0x0a, 0x61, 0x64, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+	0x12, 0x0e, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71,
+	0x1a, 0x0f, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73,
+	0x70, 0x12, 0x2b, 0x0a, 0x09, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x49, 0x64, 0x12, 0x0e,
+	0x2e, 0x41, 0x64, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0e,
+	0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x29,
+	0x0a, 0x08, 0x64, 0x72, 0x61, 0x77, 0x43, 0x6c, 0x75, 0x65, 0x12, 0x0c, 0x2e, 0x44, 0x72, 0x61,
+	0x77, 0x43, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x72,
+	0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x19, 0x0a, 0x04, 0x43, 0x61, 0x6c,
+	0x6c, 0x12, 0x08, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x07, 0x2e, 0x42, 0x69,
+	0x52, 0x65, 0x73, 0x70, 0x12, 0x35, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75,
+	0x74, 0x65, 0x43, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62,
+	0x75, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x41, 0x64, 0x64,
+	0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2d, 0x0a, 0x0a, 0x63,
+	0x6c, 0x75, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x65,
+	0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x43, 0x6c, 0x75, 0x65,
+	0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x27, 0x0a, 0x07, 0x63, 0x6c,
+	0x75, 0x65, 0x41, 0x64, 0x64, 0x12, 0x0b, 0x2e, 0x43, 0x6c, 0x75, 0x65, 0x41, 0x64, 0x64, 0x52,
+	0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52,
+	0x65, 0x73, 0x70, 0x12, 0x2f, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72,
+	0x74, 0x54, 0x74, 0x12, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74,
+	0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74,
+	0x52, 0x65, 0x73, 0x70, 0x12, 0x27, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x46, 0x6f, 0x6c, 0x6c,
+	0x6f, 0x77, 0x12, 0x08, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x43,
+	0x6c, 0x75, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x24, 0x0a,
+	0x09, 0x73, 0x71, 0x6c, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x12, 0x0d, 0x2e, 0x53, 0x71, 0x6c,
+	0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65,
+	0x70, 0x6c, 0x79, 0x12, 0x1e, 0x0a, 0x06, 0x6d, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0a, 0x2e,
+	0x4d, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65,
+	0x70, 0x6c, 0x79, 0x12, 0x25, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x78,
+	0x70, 0x6f, 0x72, 0x74, 0x12, 0x0a, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71,
+	0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x61, 0x6c,
+	0x6c, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0a,
+	0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52,
+	0x65, 0x70, 0x6c, 0x79, 0x12, 0x24, 0x0a, 0x0b, 0x69, 0x6e, 0x66, 0x6f, 0x4f, 0x70, 0x65, 0x72,
+	0x61, 0x74, 0x65, 0x12, 0x0b, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71,
+	0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2b, 0x0a, 0x0e, 0x67, 0x65,
+	0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x2e, 0x43,
+	0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x43, 0x6f, 0x6d, 0x70,
+	0x61, 0x6e, 0x79, 0x52, 0x65, 0x73, 0x70, 0x12, 0x45, 0x0a, 0x12, 0x64, 0x69, 0x73, 0x74, 0x72,
+	0x69, 0x62, 0x75, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x65, 0x53, 0x68, 0x6f, 0x77, 0x12, 0x16, 0x2e,
+	0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x65, 0x53, 0x68,
+	0x6f, 0x77, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75,
+	0x74, 0x65, 0x43, 0x6c, 0x75, 0x65, 0x53, 0x68, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x12, 0x24,
+	0x0a, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x69, 0x6c, 0x12, 0x0e, 0x2e, 0x45, 0x78, 0x70,
+	0x6f, 0x72, 0x74, 0x42, 0x79, 0x44, 0x62, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52,
+	0x65, 0x70, 0x6c, 0x79, 0x12, 0x1e, 0x0a, 0x06, 0x75, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x0a,
+	0x2e, 0x55, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52,
+	0x65, 0x70, 0x6c, 0x79, 0x12, 0x28, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x6d, 0x6d,
+	0x6f, 0x6e, 0x4d, 0x61, 0x69, 0x6c, 0x12, 0x0c, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x69,
+	0x6c, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x30,
+	0x0a, 0x0d, 0x61, 0x64, 0x64, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12,
+	0x0e, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x1a,
+	0x0f, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70,
+	0x12, 0x2d, 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x65, 0x42, 0x79,
+	0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x0e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x75,
+	0x6c, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,
+	0x31, 0x0a, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x65, 0x42,
+	0x79, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x10, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65,
+	0x72, 0x43, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70,
+	0x6c, 0x79, 0x12, 0x2a, 0x0a, 0x0c, 0x66, 0x69, 0x6e, 0x64, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6e,
+	0x66, 0x6f, 0x12, 0x10, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x66,
+	0x6f, 0x52, 0x65, 0x71, 0x1a, 0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x29,
+	0x0a, 0x0f, 0x67, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x4c, 0x69, 0x73,
+	0x74, 0x12, 0x0c, 0x2e, 0x43, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a,
+	0x08, 0x2e, 0x42, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x33, 0x0a, 0x0c, 0x4d, 0x61, 0x74,
+	0x65, 0x72, 0x69, 0x61, 0x6c, 0x53, 0x61, 0x76, 0x65, 0x12, 0x10, 0x2e, 0x4d, 0x61, 0x74, 0x65,
+	0x72, 0x69, 0x61, 0x6c, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x4d, 0x61,
+	0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x42, 0x06,
+	0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (

+ 190 - 0
service/compositeImages.go

@@ -0,0 +1,190 @@
+package service
+
+import (
+	"bytes"
+	"fmt"
+	"github.com/disintegration/imaging"
+	"github.com/fogleman/gg"
+	"github.com/gogf/gf/v2/util/gconv"
+	"github.com/nfnt/resize"
+	"github.com/skip2/go-qrcode"
+	"image"
+	"image/color"
+	"image/draw"
+	"image/jpeg"
+	"image/png"
+	"net/http"
+)
+
+func compositeImage(backgroundURL, qrContent string) (err error, imgByte []byte) {
+	// 配置参数
+	//backgroundURL := "https://images.unsplash.com/photo-1501854140801-50d01698950b" // 示例背景图片
+	//qrContent := "https://github.com/zeromicro/go-zero"                           // 二维码内容
+	//outputPath := "output.jpg" // 输出文件路径
+	margin := 20         // 二维码距边缘的边距
+	qrSize := 200        // 二维码原始大小(像素)
+	cornerRadius := 15.0 // 二维码圆角半径
+	borderSize := 5      // 二维码白色边框大小
+	shadowBlur := 8.0    // 阴影模糊度
+	shadowOpacity := 0.3 // 阴影透明度
+
+	// 创建带效果的二维码并合成到背景右下角
+	imgByte, err = createQRComposite(backgroundURL, qrContent, margin, qrSize, cornerRadius, gconv.Float64(borderSize), shadowBlur, shadowOpacity)
+	if err != nil {
+		return err, nil
+	}
+	return nil, imgByte
+}
+
+// 创建二维码合成图片
+func createQRComposite(backgroundURL, qrContent string, margin, qrSize int, cornerRadius, borderSize, shadowBlur, shadowOpacity float64) ([]byte, error) {
+	// 1. 下载背景图片
+	bgImg, imgType, err := downloadImage(backgroundURL)
+	if err != nil {
+		return nil, err
+	}
+
+	// 2. 生成带效果的二维码
+	qrImg, err := generateStyledQRCode(qrContent, qrSize, color.Black, color.White, cornerRadius, borderSize, shadowBlur, shadowOpacity)
+	if err != nil {
+		return nil, err
+	}
+
+	// 3. 计算二维码在右下角的位置
+	bgBounds := bgImg.Bounds()
+	qrBounds := qrImg.Bounds()
+	pos := image.Point{
+		X: bgBounds.Dx() - qrBounds.Dx() - margin,
+		Y: bgBounds.Dy() - qrBounds.Dy() - margin,
+	}
+
+	// 4. 调整二维码大小(如果需要)
+	finalQR := qrImg
+	if bgBounds.Dx() < 800 {
+		// 背景图较小,缩小二维码
+		targetWidth := bgBounds.Dx() / 4
+		finalQR = resize.Resize(uint(targetWidth), 0, qrImg, resize.Lanczos3)
+		// 重新计算位置
+		pos = image.Point{
+			X: bgBounds.Dx() - finalQR.Bounds().Dx() - margin,
+			Y: bgBounds.Dy() - finalQR.Bounds().Dy() - margin,
+		}
+	}
+
+	// 5. 合成图片
+	resultImg := image.NewRGBA(bgBounds)
+	draw.Draw(resultImg, bgBounds, bgImg, image.Point{}, draw.Src)
+	draw.Draw(resultImg, finalQR.Bounds().Add(pos), finalQR, image.Point{}, draw.Over)
+
+	// 6. 保存结果
+	//return saveImage(outputPath, resultImg, 95)
+	imgByte, err := encodeImageToBytes(resultImg, imgType, 90)
+	if err != nil {
+		return nil, err
+	}
+	return imgByte, nil
+}
+
+// 下载图片
+func downloadImage(url string) (image.Image, string, error) {
+	resp, err := http.Get(url)
+	if err != nil {
+		return nil, "", err
+	}
+	defer resp.Body.Close()
+
+	img, imgType, err := image.Decode(resp.Body)
+	if err != nil {
+		return nil, "", err
+	}
+
+	return img, imgType, nil
+}
+
+// 生成带样式的二维码
+func generateStyledQRCode(content string, size int, fgColor, bgColor color.Color, cornerRadius, borderSize, shadowBlur, shadowOpacity float64) (image.Image, error) {
+	// 生成基本二维码
+	qr, err := qrcode.New(content, qrcode.Highest)
+	if err != nil {
+		return nil, err
+	}
+	qr.ForegroundColor = fgColor
+	qr.BackgroundColor = bgColor
+	qr.DisableBorder = true
+
+	// 创建基本二维码图片
+	baseImg := qr.Image(size)
+
+	// 创建带透明背景的画布
+	dc := gg.NewContext(size, size)
+	dc.SetColor(color.Transparent)
+	dc.Clear()
+
+	// 绘制圆角矩形作为蒙版
+	if cornerRadius > 0 {
+		dc.DrawRoundedRectangle(0, 0, float64(size), float64(size), cornerRadius)
+		dc.Clip()
+	}
+
+	// 绘制二维码
+	dc.DrawImage(baseImg, 0, 0)
+
+	// 添加白色边框
+	if borderSize > 0 {
+		dc.ResetClip()
+		dc.SetColor(color.White)
+		dc.SetLineWidth(borderSize)
+		dc.DrawRoundedRectangle(0, 0, float64(size), float64(size), cornerRadius)
+		dc.Stroke()
+	}
+
+	// 添加阴影效果
+	if shadowBlur > 0 && shadowOpacity > 0 {
+		shadowImg := addShadow(dc.Image(), shadowBlur, shadowOpacity)
+		return shadowImg, nil
+	}
+
+	return dc.Image(), nil
+}
+
+// 添加阴影效果
+func addShadow(img image.Image, blur, opacity float64) image.Image {
+	bounds := img.Bounds()
+	dc := gg.NewContext(bounds.Dx()+int(blur*2), bounds.Dy()+int(blur*2))
+
+	// 绘制阴影
+	dc.SetRGBA(0, 0, 0, opacity)
+	dc.DrawRectangle(blur, blur, float64(bounds.Dx()), float64(bounds.Dy()))
+	dc.Fill()
+
+	// 应用高斯模糊
+	shadow := dc.Image()
+	blurred := imaging.Blur(shadow, blur)
+
+	// 创建新画布绘制二维码和阴影
+	dc = gg.NewContext(bounds.Dx()+int(blur*2), bounds.Dy()+int(blur*2))
+	dc.DrawImage(blurred, 0, 0)
+	dc.DrawImage(img, int(blur), int(blur))
+
+	return dc.Image()
+}
+
+// 编码图片为字节流
+func encodeImageToBytes(img image.Image, format string, quality int) ([]byte, error) {
+	buf := new(bytes.Buffer)
+
+	switch format {
+	case "png":
+		if err := png.Encode(buf, img); err != nil {
+			return nil, err
+		}
+	case "jpg", "jpeg":
+		if err := jpeg.Encode(buf, img, &jpeg.Options{Quality: quality}); err != nil {
+			return nil, err
+		}
+	default:
+		return nil, fmt.Errorf("不支持的图片格式: %s", format)
+	}
+
+	return buf.Bytes(), nil
+}

+ 97 - 7
service/material.go

@@ -4,15 +4,19 @@ import (
 	"app.yhyue.com/moapp/jybase/date"
 	entity "bp.jydev.jianyu360.cn/BaseService/biService/entity"
 	"bp.jydev.jianyu360.cn/BaseService/biService/rpc/pb"
+	"crypto/rand"
+	"encoding/binary"
 	"errors"
+	"fmt"
 	"github.com/gogf/gf/v2/util/gconv"
+	"net/url"
 	"strings"
 	"time"
 )
 
-func MaterialSave(in *pb.MaterialSaveReq, title, content string) (msgId int64, err error) {
+func MaterialSave(in *pb.MaterialSaveReq, title, content string) (msgId, mId int64, err error) {
 	if len(strings.Split(in.ReceiveUserId, ",")) < 1 {
-		return 0, errors.New("物料发送人员为空")
+		return 0, 0, errors.New("物料发送人员为空")
 	}
 	//先插入message_log
 	saveMsg := map[string]interface{}{
@@ -32,7 +36,7 @@ func MaterialSave(in *pb.MaterialSaveReq, title, content string) (msgId int64, e
 	}
 	msgId = entity.JyMysql.Insert("message_send_log", saveMsg)
 	if msgId < 0 {
-		return 0, errors.New("插入消息表message_send_log出错")
+		return 0, 0, errors.New("插入消息表message_send_log出错")
 	}
 	saveMap := map[string]interface{}{
 		"task_name":           in.TaskName,
@@ -47,11 +51,11 @@ func MaterialSave(in *pb.MaterialSaveReq, title, content string) (msgId int64, e
 		"msg_id":              msgId,
 		"img_webpage":         in.ImgWebpage,
 	}
-	ins := entity.BiService.Insert("operating_materials", saveMap)
-	if ins < 0 {
-		return 0, errors.New("插入物料表operating_materials出错")
+	mId = entity.BiService.Insert("operating_materials", saveMap)
+	if mId < 0 {
+		return 0, 0, errors.New("插入物料表operating_materials出错")
 	}
-	return msgId, nil
+	return msgId, mId, nil
 }
 
 func GetSendUserId(positionIds string, entId int64) []string {
@@ -65,3 +69,89 @@ func GetSendUserId(positionIds string, entId int64) []string {
 	}
 	return userIdArr
 }
+
+func PersonImageSave(imgUrl string, msgId, positionId, materialsId int64) bool {
+	saveMap := map[string]interface{}{
+		"file_url":     imgUrl,
+		"msg_id":       msgId,
+		"position_id":  positionId,
+		"materials_id": materialsId,
+		"createtime":   time.Now().Format(date.Date_Full_Layout),
+	}
+	return entity.BiService.Insert("operating_materials_attachment", saveMap) > 0
+}
+
+func PersonImgSaveComposite(fileUrl, qrcodeUrl, name string) ([]byte, error) {
+	//根据职位id获取到对应的渠道码
+	code := ""
+	data := entity.JyBiTidb.FindOne("dwd_d_userbase_belongto_rulecode", map[string]interface{}{"name": name}, "code", "")
+	if data != nil && len(*data) > 0 {
+		code = gconv.String((*data)["code"])
+	} else {
+		//没有code,生成一个
+		code = GenerateUniqueRandomString(6)
+		entity.JyBiTidb.Insert("dwd_d_userbase_belongto_rulecode", map[string]interface{}{
+			"code":     code,
+			"pcode":    "04",
+			"level":    "2",
+			"name":     name,
+			"remark":   "人员渠道码",
+			"SZ_LEVEL": 1,
+			"SZ_LEAF":  1,
+			"SZ_PID0":  "04",
+			"SZ_PID1":  code,
+		})
+	}
+	//合成图片
+	ok, err := hasAnyParameters(qrcodeUrl)
+	if err != nil {
+		return nil, err
+	}
+	if ok {
+		qrcodeUrl = fmt.Sprintf("%s&personnelChannel=%s", qrcodeUrl, code)
+	} else {
+		qrcodeUrl = fmt.Sprintf("%s?personnelChannel=%s", qrcodeUrl, code)
+	}
+	err, imgByte := compositeImage(fileUrl, qrcodeUrl)
+	return imgByte, err
+}
+
+func GenerateUniqueRandomString(length int) string {
+	// 获取当前时间(纳秒级)
+	now := time.Now().UnixNano()
+
+	// 生成随机数
+	var randNum uint64
+	if err := binary.Read(rand.Reader, binary.BigEndian, &randNum); err != nil {
+		randNum = uint64(now)
+	}
+
+	// 组合时间和随机数
+	uniqueValue := now ^ int64(randNum)
+
+	// 转换为base36字符串(0-9a-z)
+	charset := "0123456789abcdefghijklmnopqrstuvwxyz"
+	result := make([]byte, length)
+	for i := range result {
+		// 使用模运算选择字符
+		result[i] = charset[uniqueValue%36]
+		uniqueValue /= 36
+
+		// 如果值耗尽,重新生成
+		if uniqueValue == 0 {
+			uniqueValue = time.Now().UnixNano()
+		}
+	}
+
+	return string(result)
+}
+
+func hasAnyParameters(rawURL string) (bool, error) {
+	parsedURL, err := url.Parse(rawURL)
+	if err != nil {
+		return false, err
+	}
+
+	// 检查查询参数或片段标识符中的参数
+	return parsedURL.RawQuery != "" || (parsedURL.Fragment != "" && strings.Contains(parsedURL.Fragment, "=")), nil
+}