From a38fff4917b4eb312a86da48a57eddbafebbf3d2 Mon Sep 17 00:00:00 2001 From: zzw <1464003642@qq.com> Date: Mon, 10 Aug 2026 11:40:06 +0800 Subject: [PATCH 1/3] feat: test product manager --- bff/etc/product.pb | Bin 16463 -> 16450 bytes product/etc/product.yaml | 22 +++++++++++----------- product/internal/dao/product.go | 16 ++++++++-------- product/product/product.pb.go | 10 +++++----- product/proto/admin/product.proto | 2 +- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/bff/etc/product.pb b/bff/etc/product.pb index be7cd820f90bc2f84fa66b44c4649535ded64be2..3c80fbed558dbd4866ef95b9c46304c4bb637654 100644 GIT binary patch delta 104 zcmX@#z<8*Eaf6d7(?8M8E~Y;@c;7K|u?H08r<5j_2>DL-vNMp9X}bJmGLx8+pnhUX jZf2f-nX!HWM8V|Qb|H-3lRwz$!4wH$D%xykFUSZ0x9ud} delta 80 zcmV-W0I&bTfC0~d0kA?f0*e;2L^b&c4f_KM2T*cvWOZY75>%5)J}?L)g45)a0v#fg m!9NoQV{&C-bY+v2K2!lwlj%M#lVm>|1!;6;ZF93RKM?_skQ^}p diff --git a/product/etc/product.yaml b/product/etc/product.yaml index fad8e92..0b2fe32 100644 --- a/product/etc/product.yaml +++ b/product/etc/product.yaml @@ -22,22 +22,22 @@ Nacos: RegisterIP: product Mysql: - # Host: mysql - # Port: 3306 - # User: root - # Password: "123123" - # Database: dms-product - # Charset: utf8mb4 - # Prefix: - - Host: "39.106.171.204" - Port: 33066 + Host: mysql + Port: 3306 User: root - Password: "MOLXRZNOU4Y4" + Password: "123123" Database: dms-product Charset: utf8mb4 Prefix: + # Host: "39.106.171.204" + # Port: 33066 + # User: root + # Password: "MOLXRZNOU4Y4" + # Database: dms-product + # Charset: utf8mb4 + # Prefix: + # ReadHost: mysql-slave # ReadPort: 3306 # ReadUser: root diff --git a/product/internal/dao/product.go b/product/internal/dao/product.go index d020610..c3fea9b 100644 --- a/product/internal/dao/product.go +++ b/product/internal/dao/product.go @@ -194,15 +194,15 @@ type ProductNames struct { } type ProductStatusUpdate struct { - Status uint8 `gorm:"column:status"` - Reason string `gorm:"column:reason"` - AdminName string `gorm:"column:admin_name"` - AdminId int `gorm:"column:admin_id"` + Status uint8 `gorm:"column:status" json:"status"` + Reason string `gorm:"column:reason" json:"reason"` + AdminName string `gorm:"column:admin_name" json:"admin_name"` + AdminId int `gorm:"column:admin_id" json:"admin_id"` } type ProductSort struct { - Id int `gorm:"column:id"` - Sort uint16 `gorm:"column:sort"` - AdminName string `gorm:"column:admin_name"` - AdminId int `gorm:"column:admin_id"` + Id int `gorm:"column:id" json:"id"` + Sort uint16 `gorm:"column:sort" json:"sort"` + AdminName string `gorm:"column:admin_name" json:"admin_name"` + AdminId int `gorm:"column:admin_id" json:"admin_id"` } diff --git a/product/product/product.pb.go b/product/product/product.pb.go index 156c1fa..0c6d0b1 100644 --- a/product/product/product.pb.go +++ b/product/product/product.pb.go @@ -1122,11 +1122,11 @@ const file_proto_admin_product_proto_rawDesc = "" + "\x06reason\x18\" \x01(\tR\x06reason\x12\x1d\n" + "\n" + "admin_name\x18# \x01(\tR\tadminName\x12\x12\n" + - "\x04edit\x18$ \x01(\rR\x04edit2\xfb\x03\n" + - "\aProduct\x12T\n" + - "\x06Create\x12\x12.product.CreateReq\x1a\x11.product.Response\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\"\x18/admin/v3/product/create\x12N\n" + - "\x04Info\x12\x10.product.InfoReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x12\x16/admin/v3/product/info\x12Q\n" + - "\x05Items\x12\x11.product.ItemsReq\x1a\x11.product.Response\"\"\x82\xd3\xe4\x93\x02\x1c:\x01*\x12\x17/admin/v3/product/items\x12Q\n" + + "\x04edit\x18$ \x01(\rR\x04edit2\xee\x03\n" + + "\aProduct\x12M\n" + + "\x06Create\x12\x12.product.CreateReq\x1a\x11.product.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/admin/v3/product\x12N\n" + + "\x04Info\x12\x10.product.InfoReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x12\x16/admin/v3/product/info\x12K\n" + + "\x05Items\x12\x11.product.ItemsReq\x1a\x11.product.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\x12\x11/admin/v3/product\x12Q\n" + "\x05Names\x12\x11.product.NamesReq\x1a\x11.product.Response\"\"\x82\xd3\xe4\x93\x02\x1c:\x01*\x12\x17/admin/v3/product/names\x12T\n" + "\x06Status\x12\x12.product.StatusReq\x1a\x11.product.Response\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\x1a\x18/admin/v3/product/status\x12N\n" + "\x04Sort\x12\x10.product.SortReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x1a\x16/admin/v3/product/sortB\vZ\t./productb\x06proto3" diff --git a/product/proto/admin/product.proto b/product/proto/admin/product.proto index e06ab6c..304a1e6 100644 --- a/product/proto/admin/product.proto +++ b/product/proto/admin/product.proto @@ -8,7 +8,7 @@ import "google/api/annotations.proto"; service Product { rpc Create(CreateReq) returns (Response) { option (google.api.http) = { - post: "/admin/v3/product/create" + post: "/admin/v3/product" body: "*" }; } From bdc582ad5ff364df0df2de8c1715641a069d6419 Mon Sep 17 00:00:00 2001 From: zzw <1464003642@qq.com> Date: Tue, 11 Aug 2026 09:30:38 +0800 Subject: [PATCH 2/3] feat: test product --- bff/etc/product.pb | Bin 16450 -> 18729 bytes product/internal/apply/apply.go | 211 ++++ product/internal/dao/edit.go | 34 + product/internal/dao/product.go | 105 +- product/internal/dao/verify.go | 53 + product/internal/logic/editapplylogic.go | 105 ++ product/internal/logic/editbaselogic.go | 122 +++ product/internal/logic/editlog_helper.go | 27 + .../internal/logic/editsusceptiblelogic.go | 130 +++ product/internal/logic/infologic.go | 7 + product/internal/logic/itemslogic.go | 6 + product/internal/logic/verifylogic.go | 151 +++ product/internal/logic/verifystatuslogic.go | 194 ++++ .../internal/model/action_apply_log_model.go | 24 + product/internal/model/edit_log_model.go | 24 + product/internal/server/productserver.go | 35 + product/internal/wecom/notify.go | 26 + product/product/product.pb.go | 943 +++++++++++++++++- product/product/product_grpc.pb.go | 292 +++++- product/productclient/product.go | 71 +- product/proto/admin/product.proto | 132 +++ product/validator/validator.go | 113 +++ 22 files changed, 2730 insertions(+), 75 deletions(-) create mode 100644 product/internal/apply/apply.go create mode 100644 product/internal/dao/edit.go create mode 100644 product/internal/logic/editapplylogic.go create mode 100644 product/internal/logic/editbaselogic.go create mode 100644 product/internal/logic/editlog_helper.go create mode 100644 product/internal/logic/editsusceptiblelogic.go create mode 100644 product/internal/logic/verifylogic.go create mode 100644 product/internal/logic/verifystatuslogic.go create mode 100644 product/internal/model/action_apply_log_model.go create mode 100644 product/internal/model/edit_log_model.go create mode 100644 product/internal/wecom/notify.go diff --git a/bff/etc/product.pb b/bff/etc/product.pb index 3c80fbed558dbd4866ef95b9c46304c4bb637654..8d99a51f58cd393fdd963e552a8a6c5eb400d442 100644 GIT binary patch delta 1421 zcmb7Ezi-n(7?qtLjn7Ggt|@gBLQ}V;EkccGX=p-3N(4xOf{Ljs1QL-QUt0@1HaVwl z1_WYbgj-oykl2tqupz<53L7&FFz^Q;2JX&n`U{X)PIuqE_wIY&cX#g}39p_BudB1- z*YT~3vtD>~2}sMRWvz5HbRQlCQS9q}8!JLim`G^bEAn%0TDk#}0g#+4UWpe#{E}(; z7d+4IkPF3u(H7FN+f+o#leB2CQdMxIi(1q%nJ=ai>Ms$oN`2&3X?9Ej zJsWz*uxwk2aG9MY%WDH!t82azC6%)SrJmrFM%&O=5!AaThzBb;4w4?V=9=|& z-L~k79YrD!%41o;VY1gYYzwa~Sq_3J5V3Uw*@{f`xufYgMI^L{g{$oj90V~7*R7_B zHkAZma zZ$eru2-HlK2mtIRPfjQM9}WST)eqNs?fIolXuPEO8tVqV8lfiIP(oBnp6)+TgTSrE z5De(rrV{=qkRsG65WB8Bh}92n#Y(eb@ujp?IsZe*z$Fk3@`LceNzW<+v6080z7R1B z$-7G5WMHZ!oP-F-0qL^U!ah_EFv;^u_Ua_3j--$0biFrhlTFT}%sDCimKUY}R&gWMO*8ygAS19phvXPf-9GT@A1R diff --git a/product/internal/apply/apply.go b/product/internal/apply/apply.go new file mode 100644 index 0000000..c171e91 --- /dev/null +++ b/product/internal/apply/apply.go @@ -0,0 +1,211 @@ +package apply + +import ( + "context" + "encoding/json" + "strconv" + "time" + + "product/internal/dao" + "product/internal/model" + "product/internal/wecom" + + "pkg.local/log" + "pkg.local/redis" + "pkg.local/utils" +) + +const ( + applyProductEditKey = "apply:edit:product:" + applyEditTimeOut = 60 * 24 // 分钟 + applyMd5Key = "keys:" +) + +// Data Redis 中的编辑申请状态 +type Data struct { + Uid int `json:"uid"` + Id int `json:"id"` + Reason string `json:"reason"` + Status uint8 `json:"status"` // 9待审 1通过 2驳回 0未申请 + Time string `json:"time"` + Type uint8 `json:"type"` +} + +func redisKey(uId, objId int) string { + return applyProductEditKey + strconv.Itoa(uId) + "_" + strconv.Itoa(objId) +} + +func md5MapKey(md5 string) string { + return applyProductEditKey + applyMd5Key + md5 +} + +// Get 读取申请状态 +func Get(ctx context.Context, uId, objId int) (Data, error) { + var data Data + if redis.Client == nil { + return data, nil + } + result, err := redis.Client.Get(ctx, redisKey(uId, objId)).Result() + if err == redis.Nil { + return data, nil + } + if err != nil { + return data, err + } + if len(result) < utils.NumberFive { + return data, nil + } + if err = json.Unmarshal([]byte(result), &data); err != nil { + return data, err + } + return data, nil +} + +// Del 删除申请缓存(编辑成功后清除) +func Del(ctx context.Context, uId, objId int) error { + if redis.Client == nil { + return nil + } + return redis.Client.Del(ctx, redisKey(uId, objId)).Err() +} + +// Set 发起编辑申请:写 Redis + action_apply_log,企微消息预留 +func Set(ctx context.Context, uId, objId int, reason string) error { + data := Data{ + Uid: uId, + Id: objId, + Reason: reason, + Status: dao.ApplyStatusWaitPass, + Type: dao.EditLogTypeProduct, + Time: time.Now().Format(time.DateTime), + } + + md5, err := saveRedis(ctx, &data) + if err != nil { + return err + } + + add := dao.ActionApplyLogCreate{ + AdminId: uId, + ObjId: objId, + Type: dao.EditLogTypeProduct, + Reason: reason, + Status: dao.ApplyStatusWaitPass, + } + err = model.ActionApplyLogModel{}.Init().Create(&add) + if err != nil { + _ = Del(ctx, uId, objId) + log.Errorf("action apply log create: %v", err) + return err + } + + wecom.NotifyProduct(wecom.NotifyJob{ + ObjId: objId, + ObjType: dao.EditLogTypeProduct, + Type: wecom.ProductApplyReview, + Reason: reason, + Key: md5, + }) + return nil +} + +func saveRedis(ctx context.Context, data *Data) (string, error) { + if redis.Client == nil { + return "", nil + } + key := redisKey(data.Uid, data.Id) + md5 := utils.MD5Encrypt(strconv.Itoa(data.Uid) + strconv.Itoa(data.Id) + data.Time) + payload, err := json.Marshal(data) + if err != nil { + return md5, err + } + expire := time.Duration(applyEditTimeOut) * time.Minute + if err = redis.Client.Set(ctx, key, string(payload), expire).Err(); err != nil { + return md5, err + } + if data.Status == dao.ApplyStatusWaitPass { + if err = redis.Client.Set(ctx, md5MapKey(md5), key, expire).Err(); err != nil { + return md5, err + } + } + return md5, nil +} + +// CanEdit 是否已获编辑权限(申请通过) +func CanEdit(ctx context.Context, uId, objId int) bool { + data, err := Get(ctx, uId, objId) + if err != nil { + log.Errorf("apply get: %v", err) + return false + } + return data.Status == dao.ApplyStatusDone +} + +// Pass 临时:将编辑申请置为通过(企微审批对接后删除) +func Pass(ctx context.Context, uId, objId int) error { + data, err := Get(ctx, uId, objId) + if err != nil { + return err + } + if data.Status == dao.ApplyStatusDone { + return nil + } + if data.Status != dao.ApplyStatusWaitPass && data.Status != 0 { + return errAlreadyHandled + } + + reason := data.Reason + if data.Status == 0 { + data = Data{ + Uid: uId, + Id: objId, + Reason: "临时通过", + Type: dao.EditLogTypeProduct, + Time: time.Now().Format(time.DateTime), + } + reason = data.Reason + } + data.Status = dao.ApplyStatusDone + if data.Time == "" { + data.Time = time.Now().Format(time.DateTime) + } + + if _, err = saveRedis(ctx, &data); err != nil { + return err + } + + add := dao.ActionApplyLogCreate{ + AdminId: uId, + ObjId: objId, + Type: dao.EditLogTypeProduct, + Reason: reason, + Status: dao.ApplyStatusDone, + } + err = model.ActionApplyLogModel{}.Init().Create(&add) + if err != nil { + log.Errorf("action apply log pass: %v", err) + return err + } + + wecom.NotifyProduct(wecom.NotifyJob{ + ObjId: objId, + ObjType: dao.EditLogTypeProduct, + Type: wecom.ProductNeedReview, + Action: dao.ApplyStatusDone, + Reason: reason, + }) + return nil +} + +// errAlreadyHandled 申请已驳回等不可再通过 +var errAlreadyHandled = errApply("申请状态不可通过") + +type errApply string + +func (e errApply) Error() string { return string(e) } + +// IsAlreadyHandled 是否为「状态不可通过」 +func IsAlreadyHandled(err error) bool { + _, ok := err.(errApply) + return ok +} diff --git a/product/internal/dao/edit.go b/product/internal/dao/edit.go new file mode 100644 index 0000000..31d296c --- /dev/null +++ b/product/internal/dao/edit.go @@ -0,0 +1,34 @@ +package dao + +// 编辑日志对象类型 +const ( + EditLogTypeProduct uint8 = 1 // 产品 + EditLogTypeStore uint8 = 2 // 门店 + EditLogTypeAddress uint8 = 3 // 地址 + EditLogTypeSales uint8 = 4 // 销售 +) + +// 编辑申请状态(Redis / action_apply_log) +const ( + ApplyStatusDone uint8 = 1 // 通过,可编辑 + ApplyStatusNotPass uint8 = 2 // 驳回 + ApplyStatusWaitPass uint8 = 9 // 待审核 +) + +type EditLogCreate struct { + Id int `gorm:"column:id;primaryKey;autoIncrement"` + ObjId int `gorm:"column:obj_id"` + ObjType uint8 `gorm:"column:obj_type"` + Content string `gorm:"column:content"` + AdminId int `gorm:"column:admin_id"` + AdminName string `gorm:"column:admin_name"` +} + +type ActionApplyLogCreate struct { + Id int `gorm:"column:id;primaryKey;autoIncrement"` + AdminId int `gorm:"column:admin_id"` + ObjId int `gorm:"column:obj_id"` + Type uint8 `gorm:"column:type"` + Reason string `gorm:"column:reason"` + Status uint8 `gorm:"column:status"` +} diff --git a/product/internal/dao/product.go b/product/internal/dao/product.go index c3fea9b..15f6053 100644 --- a/product/internal/dao/product.go +++ b/product/internal/dao/product.go @@ -130,22 +130,44 @@ type ProductVerify struct { } type ProductEditBase struct { - Id int `gorm:"column:id;primaryKey"` - Name string `gorm:"column:name"` - Subhead string `gorm:"column:subhead"` - Content string `gorm:"column:content"` - Images string `gorm:"column:images"` - Weight float32 `gorm:"column:weight"` - Cubage string `gorm:"column:cubage"` - Waybill string `gorm:"column:waybill"` - Label string `gorm:"column:label"` - IsIndex uint8 `gorm:"column:is_index"` - IndexImage string `gorm:"column:index_image"` - PeriodValidity int16 `gorm:"column:period_validity"` - IsBuy uint8 `gorm:"column:is_buy"` - PublishTime time.Time `gorm:"column:publish_time"` - AdminName string `gorm:"column:admin_name"` - AdminId int `gorm:"column:admin_id"` + Id int `gorm:"column:id;primaryKey" json:"id"` + Name string `gorm:"column:name" json:"name"` + Subhead string `gorm:"column:subhead" json:"subhead"` + Content string `gorm:"column:content" json:"content"` + Images string `gorm:"column:images" json:"images"` + Weight float32 `gorm:"column:weight" json:"weight"` + Cubage string `gorm:"column:cubage" json:"cubage"` + Waybill string `gorm:"column:waybill" json:"waybill"` + Label string `gorm:"column:label" json:"label"` + IsIndex uint8 `gorm:"column:is_index" json:"is_index"` + IndexImage string `gorm:"column:index_image" json:"index_image"` + PeriodValidity int16 `gorm:"column:period_validity" json:"period_validity"` + IsBuy uint8 `gorm:"column:is_buy" json:"is_buy"` + PublishTime time.Time `gorm:"column:publish_time" json:"publish_time"` + AdminName string `gorm:"column:admin_name" json:"admin_name"` + AdminId int `gorm:"column:admin_id" json:"admin_id"` +} + +// ProductEditSusceptible 敏感字段(查询旧值 / 写入 verify 快照) +type ProductEditSusceptible struct { + Id int `gorm:"column:id" json:"id"` + ModelCode string `gorm:"column:model_code" json:"model_code"` + Price float32 `gorm:"column:price" json:"price"` + StorePrice float32 `gorm:"column:store_price" json:"store_price"` + SalePrice float32 `gorm:"column:sale_price" json:"sale_price"` + SharePrice float32 `gorm:"column:share_price" json:"share_price"` + AgentPrice float32 `gorm:"column:agent_price" json:"agent_price"` + SaleReward string `gorm:"column:sale_reward" json:"sale_reward"` + BoxNumber float64 `gorm:"column:box_number" json:"box_number"` + Type uint8 `gorm:"column:type" json:"type"` + NormsNumber uint8 `gorm:"column:norms_number" json:"norms_number"` + AdminName string `gorm:"column:admin_name" json:"admin_name"` + AdminId int `gorm:"column:admin_id" json:"admin_id"` +} + +// ProductVerifyFirstEditStatus 敏感编辑提交后置为一审中 +type ProductVerifyFirstEditStatus struct { + VerifyStatus uint8 `gorm:"column:verify_status"` } // ProductInfo 列表/详情查询投影 @@ -206,3 +228,54 @@ type ProductSort struct { AdminName string `gorm:"column:admin_name" json:"admin_name"` AdminId int `gorm:"column:admin_id" json:"admin_id"` } + +// ProductVerifyListRow 审核列表产品侧字段 +type ProductVerifyListRow struct { + Id int `gorm:"column:id"` + Name string `gorm:"column:name"` + ModelCode string `gorm:"column:model_code"` + Price float32 `gorm:"column:price"` + StorePrice float32 `gorm:"column:store_price"` + SalePrice float32 `gorm:"column:sale_price"` + SharePrice float32 `gorm:"column:share_price"` + AgentPrice float32 `gorm:"column:agent_price"` + SaleReward string `gorm:"column:sale_reward"` + SalesModel uint8 `gorm:"column:sales_model"` + Type uint8 `gorm:"column:type"` + NormsNumber uint8 `gorm:"column:norms_number"` + BoxNumber float64 `gorm:"column:box_number"` +} + +// ProductVerifyFirstStatus 一审后回写产品审核状态 +type ProductVerifyFirstStatus struct { + VerifyStatus uint8 `gorm:"column:verify_status"` + VerifyId int `gorm:"column:verify_id"` + VerifyName string `gorm:"column:verify_name"` + Reason string `gorm:"column:reason"` +} + +// ProductVerifySecondStatus 二审驳回回写 +type ProductVerifySecondStatus struct { + VerifyStatus uint8 `gorm:"column:verify_status"` + VerifySecondId int `gorm:"column:verify_second_id"` + VerifySecondName string `gorm:"column:verify_second_name"` + Reason string `gorm:"column:reason"` +} + +// ProductVerifySecondOkStatus 二审通过:应用快照并回写审核人 +type ProductVerifySecondOkStatus struct { + ModelCode string `gorm:"column:model_code"` + Price float32 `gorm:"column:price"` + StorePrice float32 `gorm:"column:store_price"` + SalePrice float32 `gorm:"column:sale_price"` + SharePrice float32 `gorm:"column:share_price"` + AgentPrice float32 `gorm:"column:agent_price"` + SaleReward string `gorm:"column:sale_reward"` + Type uint8 `gorm:"column:type"` + NormsNumber uint8 `gorm:"column:norms_number"` + BoxNumber float64 `gorm:"column:box_number"` + VerifyStatus uint8 `gorm:"column:verify_status"` + VerifySecondId int `gorm:"column:verify_second_id"` + VerifySecondName string `gorm:"column:verify_second_name"` + Reason string `gorm:"column:reason"` +} diff --git a/product/internal/dao/verify.go b/product/internal/dao/verify.go index 8b5ff32..b6f9aa0 100644 --- a/product/internal/dao/verify.go +++ b/product/internal/dao/verify.go @@ -11,6 +11,18 @@ const ( VerifyTypeRefund uint8 = 5 // 退款 ) +// 审核操作结果(请求 status) +const ( + VerifyActionPass uint8 = 1 // 通过 + VerifyActionReject uint8 = 2 // 驳回 +) + +// 审核列表筛选(请求 status) +const ( + VerifyListFirst uint8 = 1 // 一审列表 + VerifyListSecond uint8 = 2 // 二审列表 +) + // Verify 审核表完整字段映射 type Verify struct { Id int `gorm:"column:id;primaryKey;autoIncrement"` @@ -33,3 +45,44 @@ type VerifyCreate struct { Content string `gorm:"column:content"` Type uint8 `gorm:"column:type"` } + +// VerifyInfo 审核列表关联查询 +type VerifyInfo struct { + Id int `gorm:"column:id"` + VerifyId string `gorm:"column:verify_id"` + Content string `gorm:"column:content"` + VerifyStatus uint8 `gorm:"column:verify_status"` + Type uint8 `gorm:"column:type"` +} + +// VerifyStatusRow 审核操作加载行 +type VerifyStatusRow struct { + Id int `gorm:"column:id"` + VerifyId string `gorm:"column:verify_id"` + AdminId int `gorm:"column:admin_id"` + AdminName string `gorm:"column:admin_name"` + AdminSecondId int `gorm:"column:admin_second_id"` + AdminSecondName string `gorm:"column:admin_second_name"` + Content string `gorm:"column:content"` + VerifyStatus uint8 `gorm:"column:verify_status"` + VerifyReason string `gorm:"column:verify_reason"` + VerifyTime time.Time `gorm:"column:verify_time"` +} + +// VerifyFirstUpdate 一审回写审核表 +type VerifyFirstUpdate struct { + AdminId int `gorm:"column:admin_id"` + AdminName string `gorm:"column:admin_name"` + VerifyStatus uint8 `gorm:"column:verify_status"` + VerifyReason string `gorm:"column:verify_reason"` + VerifyTime time.Time `gorm:"column:verify_time"` +} + +// VerifySecondUpdate 二审回写审核表 +type VerifySecondUpdate struct { + AdminSecondId int `gorm:"column:admin_second_id"` + AdminSecondName string `gorm:"column:admin_second_name"` + VerifyStatus uint8 `gorm:"column:verify_status"` + VerifyReason string `gorm:"column:verify_reason"` + VerifyTime time.Time `gorm:"column:verify_time"` +} diff --git a/product/internal/logic/editapplylogic.go b/product/internal/logic/editapplylogic.go new file mode 100644 index 0000000..515041a --- /dev/null +++ b/product/internal/logic/editapplylogic.go @@ -0,0 +1,105 @@ +package logic + +import ( + "context" + "strconv" + + "product/internal/apply" + "product/internal/dao" + "product/internal/model" + "product/internal/svc" + "product/product" + "product/validator" + + "pkg.local/log" + "pkg.local/modelbase" + "pkg.local/utils" + validateService "pkg.local/validate" + + "github.com/zeromicro/go-zero/core/logx" +) + +type EditApplyLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewEditApplyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *EditApplyLogic { + return &EditApplyLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *EditApplyLogic) EditApply(in *product.EditApplyReq) (*product.Response, error) { + var req validator.ProductEditApplyValidator + if msg := validateService.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + var exist dao.ProductCheckExist + err := model.ProductModel{}.Init().GetOne(modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)}, + }, &exist) + if err != nil { + log.Errorf("edit apply product get: %v", err) + return failResponse(utils.Fail), nil + } + if exist.Id < 1 { + return failResponse(utils.ErrorNotFund), nil + } + + // 管理员信息后续从 ctx / metadata 取 + adminId := 0 + + info, err := apply.Get(l.ctx, adminId, int(req.Id)) + if err != nil { + log.Errorf("edit apply get: %v", err) + return failResponse(utils.Fail), nil + } + if info.Status == dao.ApplyStatusWaitPass || info.Status == dao.ApplyStatusDone { + return outResponse(utils.Fail, "已经申请过"), nil + } + + if err = apply.Set(l.ctx, adminId, int(req.Id), req.Reason); err != nil { + log.Errorf("edit apply set: %v", err) + return failResponse(utils.Fail), nil + } + + return okResponse(utils.StringEmpty), nil +} + +// EditApplyPass TODO: 临时接口,企微编辑申请审批对接后删除 +func (l *EditApplyLogic) EditApplyPass(in *product.EditApplyPassReq) (*product.Response, error) { + var req validator.ProductEditApplyPassValidator + if msg := validateService.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + var exist dao.ProductCheckExist + err := model.ProductModel{}.Init().GetOne(modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)}, + }, &exist) + if err != nil { + log.Errorf("edit apply pass product get: %v", err) + return failResponse(utils.Fail), nil + } + if exist.Id < 1 { + return failResponse(utils.ErrorNotFund), nil + } + + // 管理员信息后续从 ctx / metadata 取 + adminId := 0 + + if err = apply.Pass(l.ctx, adminId, int(req.Id)); err != nil { + if apply.IsAlreadyHandled(err) { + return outResponse(utils.Fail, err.Error()), nil + } + log.Errorf("edit apply pass: %v", err) + return failResponse(utils.Fail), nil + } + + return okResponse(utils.StringEmpty), nil +} diff --git a/product/internal/logic/editbaselogic.go b/product/internal/logic/editbaselogic.go new file mode 100644 index 0000000..2511673 --- /dev/null +++ b/product/internal/logic/editbaselogic.go @@ -0,0 +1,122 @@ +package logic + +import ( + "context" + "strconv" + "time" + + "product/internal/apply" + "product/internal/dao" + "product/internal/model" + "product/internal/svc" + "product/internal/wecom" + "product/product" + "product/validator" + + "pkg.local/log" + "pkg.local/modelbase" + "pkg.local/utils" + validateService "pkg.local/validate" + + "github.com/zeromicro/go-zero/core/logx" +) + +type EditBaseLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewEditBaseLogic(ctx context.Context, svcCtx *svc.ServiceContext) *EditBaseLogic { + return &EditBaseLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *EditBaseLogic) EditBase(in *product.EditBaseReq) (*product.Response, error) { + var req validator.ProductEditBaseValidator + if msg := validateService.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + // 管理员信息后续从 ctx / metadata 取 + adminId := 0 + adminName := "" + + if !apply.CanEdit(l.ctx, adminId, int(req.Id)) { + return failErr(utils.ErrorAuthority), nil + } + + w := modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)}} + var old dao.ProductEditBase + m := model.ProductModel{}.Init() + err := m.GetOne(w, &old) + if err != nil { + log.Errorf("edit base get: %v", err) + return failResponse(utils.Fail), nil + } + if old.Id < 1 { + return failResponse(utils.ErrorNotFund), nil + } + + var nameCheck dao.ProductCheckExist + err = m.GetOne(modelbase.Params{Eq: map[string]string{"name": req.Name}}, &nameCheck) + if err != nil { + log.Errorf("edit base name check: %v", err) + return failResponse(utils.Fail), nil + } + if nameCheck.Id > 0 && nameCheck.Id != int(req.Id) { + return failErr(utils.ErrorDataIsExist), nil + } + + publishTime := time.Now() + if len(req.PublishTime) > 1 { + t, err := parsePublishTime(req.PublishTime) + if err != nil { + return outResponse(utils.ErrorParams, "时间错误"), nil + } + publishTime = t + } + + data := dao.ProductEditBase{ + Id: old.Id, + Name: req.Name, + Subhead: req.Subhead, + Content: req.Content, + Images: req.Images, + PeriodValidity: int16(req.PeriodValidity), + Waybill: req.Waybill, + Weight: float32(req.Weight), + Cubage: req.Cubage, + IsIndex: uint8(req.IsIndex), + IndexImage: req.IndexImage, + Label: req.Label, + PublishTime: publishTime, + AdminName: adminName, + AdminId: adminId, + IsBuy: uint8(req.IsBuy), + } + if data.IsIndex == 0 { + data.IsIndex = 2 + } + if data.IsBuy == 0 { + data.IsBuy = 2 + } + + if _, err = m.Edit(w, &data); err != nil { + log.Errorf("edit base: %v", err) + return failResponse(utils.Fail), nil + } + + addEditLog(int(req.Id), dao.EditLogTypeProduct, adminId, adminName, data, old) + wecom.NotifyProduct(wecom.NotifyJob{ + ObjId: int(req.Id), + ObjType: dao.EditLogTypeProduct, + Type: wecom.ProductOrdinaryReview, + }) + _ = apply.Del(l.ctx, adminId, int(req.Id)) + + return okResponse(utils.StringEmpty), nil +} diff --git a/product/internal/logic/editlog_helper.go b/product/internal/logic/editlog_helper.go new file mode 100644 index 0000000..4e7fb4c --- /dev/null +++ b/product/internal/logic/editlog_helper.go @@ -0,0 +1,27 @@ +package logic + +import ( + "product/internal/dao" + "product/internal/model" + + "pkg.local/log" + "pkg.local/utils" +) + +func addEditLog(objId int, objType uint8, adminId int, adminName string, data, oldData interface{}) { + content := map[string]interface{}{ + "new": data, + "old": oldData, + } + add := dao.EditLogCreate{ + ObjId: objId, + ObjType: objType, + Content: utils.StructToJson(content), + AdminId: adminId, + AdminName: adminName, + } + err := model.EditLogModel{}.Init().Create(&add) + if err != nil { + log.Errorf("edit log create: %v", err) + } +} diff --git a/product/internal/logic/editsusceptiblelogic.go b/product/internal/logic/editsusceptiblelogic.go new file mode 100644 index 0000000..89273c7 --- /dev/null +++ b/product/internal/logic/editsusceptiblelogic.go @@ -0,0 +1,130 @@ +package logic + +import ( + "context" + "encoding/json" + "strconv" + + "product/internal/apply" + "product/internal/dao" + "product/internal/model" + "product/internal/svc" + "product/internal/wecom" + "product/product" + "product/validator" + + "pkg.local/log" + "pkg.local/modelbase" + "pkg.local/utils" + validateService "pkg.local/validate" + + "github.com/zeromicro/go-zero/core/logx" + "gorm.io/gorm" +) + +type EditSusceptibleLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewEditSusceptibleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *EditSusceptibleLogic { + return &EditSusceptibleLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *EditSusceptibleLogic) EditSusceptible(in *product.EditSusceptibleReq) (*product.Response, error) { + var req validator.ProductEditSusceptibleValidator + if msg := validateService.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + if req.Type == dao.ProductTypeNormal { + if req.AgentPrice == 0 || req.StorePrice == 0 || + req.SalePrice == 0 || req.SharePrice == 0 || + req.SaleReward == "" { + return outResponse(utils.ErrorParams, "缺少相关价格"), nil + } + } + + // 管理员信息后续从 ctx / metadata 取 + adminId := 0 + adminName := "" + + if !apply.CanEdit(l.ctx, adminId, int(req.Id)) { + return failErr(utils.ErrorAuthority), nil + } + + w := modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)}, + In: map[string][]string{ + "verify_status": { + strconv.Itoa(int(dao.VerifyStatusPass)), + strconv.Itoa(int(dao.VerifyStatusRefuse)), + }, + }, + } + var old dao.ProductEditSusceptible + err := model.ProductModel{}.Init().GetOne(w, &old) + if err != nil { + log.Errorf("edit susceptible get: %v", err) + return failResponse(utils.Fail), nil + } + if old.Id < 1 { + return failResponse(utils.ErrorNotFund), nil + } + + data := dao.ProductEditSusceptible{ + Id: int(req.Id), + ModelCode: req.ModelCode, + Price: float32(req.Price), + StorePrice: float32(req.StorePrice), + SalePrice: float32(req.SalePrice), + SharePrice: float32(req.SharePrice), + AgentPrice: float32(req.AgentPrice), + SaleReward: req.SaleReward, + BoxNumber: req.BoxNumber, + Type: uint8(req.Type), + NormsNumber: uint8(req.NormsNumber), + AdminName: adminName, + AdminId: adminId, + } + + contentBytes, err := json.Marshal(data) + if err != nil { + log.Errorf("edit susceptible marshal: %v", err) + return failResponse(utils.Fail), nil + } + + err = l.svcCtx.DB.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error { + pm := model.ProductModel{}.Init().WithTX(tx) + if _, err := pm.Edit(w, &dao.ProductVerifyFirstEditStatus{ + VerifyStatus: dao.VerifyStatusChecking, + }); err != nil { + return err + } + verify := dao.VerifyCreate{ + VerifyId: strconv.FormatInt(req.Id, 10), + Content: string(contentBytes), + Type: dao.VerifyTypeProduct, + } + return model.VerifyModel{}.Init().WithTX(tx).Create(&verify) + }) + if err != nil { + log.Errorf("edit susceptible tx: %v", err) + return failResponse(utils.Fail), nil + } + + addEditLog(int(req.Id), dao.EditLogTypeProduct, adminId, adminName, data, old) + wecom.NotifyProduct(wecom.NotifyJob{ + ObjId: int(req.Id), + ObjType: dao.EditLogTypeProduct, + Type: wecom.ProductSubmitReview, + }) + _ = apply.Del(l.ctx, adminId, int(req.Id)) + + return okResponse(utils.StringEmpty), nil +} diff --git a/product/internal/logic/infologic.go b/product/internal/logic/infologic.go index 72815e8..26f1bc4 100644 --- a/product/internal/logic/infologic.go +++ b/product/internal/logic/infologic.go @@ -4,6 +4,7 @@ import ( "context" "strconv" + "product/internal/apply" "product/internal/dao" "product/internal/model" "product/internal/svc" @@ -50,5 +51,11 @@ func (l *InfoLogic) Info(in *product.InfoReq) (*product.Response, error) { return failResponse(utils.ErrorNotFund), nil } + // 管理员信息后续从 ctx / metadata 取 + adminId := 0 + if applyData, err := apply.Get(l.ctx, adminId, info.Id); err == nil { + info.Edit = applyData.Status + } + return okResponse(utils.StructToJson(toProductItem(info))), nil } diff --git a/product/internal/logic/itemslogic.go b/product/internal/logic/itemslogic.go index 4f5be60..b374a46 100644 --- a/product/internal/logic/itemslogic.go +++ b/product/internal/logic/itemslogic.go @@ -3,6 +3,7 @@ package logic import ( "context" + "product/internal/apply" "product/internal/dao" "product/internal/model" "product/internal/svc" @@ -65,7 +66,12 @@ func (l *ItemsLogic) Items(in *product.ItemsReq) (*product.Response, error) { } items := make([]*product.Item, 0, len(info)) + // 管理员信息后续从 ctx / metadata 取 + adminId := 0 for _, row := range info { + if applyData, err := apply.Get(l.ctx, adminId, row.Id); err == nil { + row.Edit = applyData.Status + } items = append(items, toProductItem(row)) } diff --git a/product/internal/logic/verifylogic.go b/product/internal/logic/verifylogic.go new file mode 100644 index 0000000..9d42ce3 --- /dev/null +++ b/product/internal/logic/verifylogic.go @@ -0,0 +1,151 @@ +package logic + +import ( + "context" + "encoding/json" + "strconv" + + "product/internal/dao" + "product/internal/model" + "product/internal/svc" + "product/product" + "product/validator" + + "pkg.local/log" + "pkg.local/modelbase" + "pkg.local/utils" + validateService "pkg.local/validate" + + "github.com/zeromicro/go-zero/core/logx" +) + +type VerifyLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewVerifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *VerifyLogic { + return &VerifyLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *VerifyLogic) Verify(in *product.VerifyReq) (*product.Response, error) { + var req validator.ProductVerifyItemsValidator + if msg := validateService.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + verifyStatus := dao.VerifyStatusChecking + if req.Status == uint32(dao.VerifyListSecond) { + verifyStatus = dao.VerifyStatusSecond + } + + page := int(req.Page) + size := int(req.PageSize) + if page < modelbase.DefaultPage { + page = modelbase.DefaultPage + } + if size < modelbase.DefaultPage { + size = modelbase.DefaultSize + } + + w := modelbase.Params{ + Eq: map[string]string{"verify_status": strconv.Itoa(int(verifyStatus))}, + Page: page, + Size: size, + Order: "id desc", + } + + var rows []dao.ProductVerifyListRow + result, err := model.ProductModel{}.Init().Page(w, &rows) + if err != nil { + log.Errorf("product verify list: %v", err) + return failResponse(utils.Fail), nil + } + + items := make([]*product.VerifyItem, 0) + if len(rows) == 0 { + return okResponse(utils.StructToJson(&product.VerifyItemsData{ + Count: result.Count, + Items: items, + })), nil + } + + ids := make([]string, 0, len(rows)) + for _, row := range rows { + ids = append(ids, strconv.Itoa(row.Id)) + } + + ww := modelbase.Params{ + Eq: map[string]string{ + "verify_status": strconv.Itoa(int(verifyStatus)), + "type": strconv.Itoa(int(dao.VerifyTypeProduct)), + }, + In: map[string][]string{"verify_id": ids}, + } + var verifies []dao.VerifyInfo + err = model.VerifyModel{}.Init().Items(ww, &verifies) + if err != nil { + log.Errorf("verify info items: %v", err) + return failResponse(utils.Fail), nil + } + + verifyByProduct := make(map[string]dao.VerifyInfo, len(verifies)) + for _, v := range verifies { + verifyByProduct[v.VerifyId] = v + } + + for _, row := range rows { + v, ok := verifyByProduct[strconv.Itoa(row.Id)] + if !ok || len(v.Content) <= utils.NumberTen { + continue + } + var content dao.ProductVerify + err = json.Unmarshal([]byte(v.Content), &content) + if err != nil { + log.Errorf("product verify content json: %v", err) + return failErr(utils.ErrorFormatDataError), nil + } + items = append(items, &product.VerifyItem{ + Name: row.Name, + SalesModel: uint32(row.SalesModel), + New: &product.VerifyParams{ + Id: int64(row.Id), + ModelCode: content.ModelCode, + Price: float64(content.Price), + StorePrice: float64(content.StorePrice), + SalePrice: float64(content.SalePrice), + SharePrice: float64(content.SharePrice), + AgentPrice: float64(content.AgentPrice), + SaleReward: content.SaleReward, + Type: uint32(content.Type), + NormsNumber: uint32(content.NormsNumber), + BoxNumber: content.BoxNumber, + VerifyId: int64(v.Id), + }, + Old: &product.VerifyParams{ + Id: int64(row.Id), + ModelCode: row.ModelCode, + Price: float64(row.Price), + StorePrice: float64(row.StorePrice), + SalePrice: float64(row.SalePrice), + SharePrice: float64(row.SharePrice), + AgentPrice: float64(row.AgentPrice), + SaleReward: row.SaleReward, + Type: uint32(row.Type), + NormsNumber: uint32(row.NormsNumber), + BoxNumber: row.BoxNumber, + VerifyId: int64(v.Id), + }, + }) + } + + return okResponse(utils.StructToJson(&product.VerifyItemsData{ + Count: result.Count, + Items: items, + })), nil +} diff --git a/product/internal/logic/verifystatuslogic.go b/product/internal/logic/verifystatuslogic.go new file mode 100644 index 0000000..e15360a --- /dev/null +++ b/product/internal/logic/verifystatuslogic.go @@ -0,0 +1,194 @@ +package logic + +import ( + "context" + "encoding/json" + "strconv" + "time" + + "product/internal/dao" + "product/internal/model" + "product/internal/svc" + "product/internal/wecom" + "product/product" + "product/validator" + + "pkg.local/log" + "pkg.local/modelbase" + "pkg.local/utils" + validateService "pkg.local/validate" + + "github.com/zeromicro/go-zero/core/logx" + "gorm.io/gorm" +) + +type VerifyStatusLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewVerifyStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *VerifyStatusLogic { + return &VerifyStatusLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *VerifyStatusLogic) VerifyFirst(in *product.VerifyStatusReq) (*product.Response, error) { + return l.verifyStatus(dao.VerifyStatusChecking, in) +} + +func (l *VerifyStatusLogic) VerifySecond(in *product.VerifyStatusReq) (*product.Response, error) { + return l.verifyStatus(dao.VerifyStatusSecond, in) +} + +func (l *VerifyStatusLogic) verifyStatus(expectStatus uint8, in *product.VerifyStatusReq) (*product.Response, error) { + var req validator.ProductVerifyStatusValidator + if msg := validateService.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + if req.Status == uint32(dao.VerifyActionReject) && len(req.Reason) < 1 { + return failErr(utils.ErrorReasonParams), nil + } + + var info dao.VerifyStatusRow + w := modelbase.Params{ + Eq: map[string]string{ + "id": strconv.FormatInt(req.Id, 10), + "verify_status": strconv.Itoa(int(expectStatus)), + }, + } + err := model.VerifyModel{}.Init().GetOne(w, &info) + if err != nil { + log.Errorf("verify status get: %v", err) + return failResponse(utils.Fail), nil + } + if info.Id < 1 { + return failResponse(utils.ErrorNotFund), nil + } + + // 管理员信息后续从 ctx / metadata 取 + adminId := 0 + adminName := "" + + nextStatus := dao.VerifyStatusPass + reason := req.Reason + if req.Status == uint32(dao.VerifyActionReject) { + nextStatus = dao.VerifyStatusRefuse + } else if expectStatus == dao.VerifyStatusChecking { + nextStatus = dao.VerifyStatusSecond + } + + productWhere := modelbase.Params{Eq: map[string]string{"id": info.VerifyId}} + var productExist dao.ProductCheckExist + err = model.ProductModel{}.Init().GetOne(productWhere, &productExist) + if err != nil { + log.Errorf("verify product get: %v", err) + return failResponse(utils.Fail), nil + } + if productExist.Id < 1 { + return outResponse(utils.ErrorNotFund, "没有找到产品信息"), nil + } + + err = l.svcCtx.DB.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error { + vm := model.VerifyModel{}.Init().WithTX(tx) + pm := model.ProductModel{}.Init().WithTX(tx) + now := time.Now() + + if expectStatus == dao.VerifyStatusChecking { + if _, err := vm.Edit(w, &dao.VerifyFirstUpdate{ + AdminId: adminId, + AdminName: adminName, + VerifyStatus: nextStatus, + VerifyReason: reason, + VerifyTime: now, + }); err != nil { + return err + } + _, err := pm.Edit(productWhere, &dao.ProductVerifyFirstStatus{ + VerifyStatus: nextStatus, + VerifyId: adminId, + VerifyName: adminName, + Reason: reason, + }) + return err + } + + if _, err := vm.Edit(w, &dao.VerifySecondUpdate{ + AdminSecondId: adminId, + AdminSecondName: adminName, + VerifyStatus: nextStatus, + VerifyReason: reason, + VerifyTime: now, + }); err != nil { + return err + } + + if nextStatus == dao.VerifyStatusPass { + var content dao.ProductVerify + if err := json.Unmarshal([]byte(info.Content), &content); err != nil { + log.Errorf("product verify content json: %v content=%s", err, info.Content) + return err + } + _, err := pm.Edit(productWhere, &dao.ProductVerifySecondOkStatus{ + ModelCode: content.ModelCode, + Price: content.Price, + StorePrice: content.StorePrice, + SalePrice: content.SalePrice, + SharePrice: content.SharePrice, + AgentPrice: content.AgentPrice, + SaleReward: content.SaleReward, + Type: content.Type, + NormsNumber: content.NormsNumber, + BoxNumber: content.BoxNumber, + VerifyStatus: nextStatus, + VerifySecondId: adminId, + VerifySecondName: adminName, + Reason: reason, + }) + return err + } + + _, err := pm.Edit(productWhere, &dao.ProductVerifySecondStatus{ + VerifyStatus: nextStatus, + VerifySecondId: adminId, + VerifySecondName: adminName, + Reason: reason, + }) + return err + }) + if err != nil { + log.Errorf("verify status tx: %v", err) + if isJSONError(err) { + return failErr(utils.ErrorFormatDataError), nil + } + return failResponse(utils.Fail), nil + } + + notifyType := wecom.ProductFirstReview + if expectStatus == dao.VerifyStatusSecond { + notifyType = wecom.ProductSecondReview + } + objID, _ := strconv.Atoi(info.VerifyId) + wecom.NotifyProduct(wecom.NotifyJob{ + ObjId: objID, + ObjType: dao.VerifyTypeProduct, + Type: notifyType, + Action: uint8(req.Status), + Reason: reason, + }) + + return okResponse(utils.StringEmpty), nil +} + +func isJSONError(err error) bool { + switch err.(type) { + case *json.SyntaxError, *json.UnmarshalTypeError: + return true + default: + return false + } +} diff --git a/product/internal/model/action_apply_log_model.go b/product/internal/model/action_apply_log_model.go new file mode 100644 index 0000000..d15e194 --- /dev/null +++ b/product/internal/model/action_apply_log_model.go @@ -0,0 +1,24 @@ +package model + +import ( + "product/internal/dao" + + "pkg.local/modelbase" +) + +type ActionApplyLogModel struct { + modelbase.Base +} + +func (m ActionApplyLogModel) TableName() string { + return modelbase.Prefix() + "action_apply_log" +} + +func (m ActionApplyLogModel) Init() ActionApplyLogModel { + m.Table = m.TableName() + return m +} + +func (m ActionApplyLogModel) Create(data *dao.ActionApplyLogCreate) error { + return m.Base.Create(data) +} diff --git a/product/internal/model/edit_log_model.go b/product/internal/model/edit_log_model.go new file mode 100644 index 0000000..11ab3d8 --- /dev/null +++ b/product/internal/model/edit_log_model.go @@ -0,0 +1,24 @@ +package model + +import ( + "product/internal/dao" + + "pkg.local/modelbase" +) + +type EditLogModel struct { + modelbase.Base +} + +func (m EditLogModel) TableName() string { + return modelbase.Prefix() + "edit_log" +} + +func (m EditLogModel) Init() EditLogModel { + m.Table = m.TableName() + return m +} + +func (m EditLogModel) Create(data *dao.EditLogCreate) error { + return m.Base.Create(data) +} diff --git a/product/internal/server/productserver.go b/product/internal/server/productserver.go index ea2324d..875432b 100644 --- a/product/internal/server/productserver.go +++ b/product/internal/server/productserver.go @@ -51,3 +51,38 @@ func (s *ProductServer) Sort(ctx context.Context, in *product.SortReq) (*product l := logic.NewSortLogic(ctx, s.svcCtx) return l.Sort(in) } + +func (s *ProductServer) Verify(ctx context.Context, in *product.VerifyReq) (*product.Response, error) { + l := logic.NewVerifyLogic(ctx, s.svcCtx) + return l.Verify(in) +} + +func (s *ProductServer) VerifyFirst(ctx context.Context, in *product.VerifyStatusReq) (*product.Response, error) { + l := logic.NewVerifyStatusLogic(ctx, s.svcCtx) + return l.VerifyFirst(in) +} + +func (s *ProductServer) VerifySecond(ctx context.Context, in *product.VerifyStatusReq) (*product.Response, error) { + l := logic.NewVerifyStatusLogic(ctx, s.svcCtx) + return l.VerifySecond(in) +} + +func (s *ProductServer) EditApply(ctx context.Context, in *product.EditApplyReq) (*product.Response, error) { + l := logic.NewEditApplyLogic(ctx, s.svcCtx) + return l.EditApply(in) +} + +func (s *ProductServer) EditApplyPass(ctx context.Context, in *product.EditApplyPassReq) (*product.Response, error) { + l := logic.NewEditApplyLogic(ctx, s.svcCtx) + return l.EditApplyPass(in) +} + +func (s *ProductServer) EditBase(ctx context.Context, in *product.EditBaseReq) (*product.Response, error) { + l := logic.NewEditBaseLogic(ctx, s.svcCtx) + return l.EditBase(in) +} + +func (s *ProductServer) EditSusceptible(ctx context.Context, in *product.EditSusceptibleReq) (*product.Response, error) { + l := logic.NewEditSusceptibleLogic(ctx, s.svcCtx) + return l.EditSusceptible(in) +} diff --git a/product/internal/wecom/notify.go b/product/internal/wecom/notify.go new file mode 100644 index 0000000..15ef1cc --- /dev/null +++ b/product/internal/wecom/notify.go @@ -0,0 +1,26 @@ +package wecom + +import "pkg.local/log" + +const ( + ProductApplyReview uint8 = 1 // 编辑申请按钮卡片 + ProductNeedReview uint8 = 2 // 编辑申请结果通知申请人 + ProductSubmitReview uint8 = 3 // 提交敏感字段变更 → 通知一审 + ProductFirstReview uint8 = 4 // 一审结果通知 + ProductSecondReview uint8 = 5 // 二审结果通知 + ProductOrdinaryReview uint8 = 6 // 基础信息变更 diff 通知 +) + +type NotifyJob struct { + ObjId int + ObjType uint8 + Type uint8 + Action uint8 // 1: 通过, 2: 驳回 + Reason string + Key string // 编辑申请 Redis MD5 key,企微回调用 +} + +func NotifyProduct(job NotifyJob) { + log.Infof("wecom stub skip: type=%d objId=%d action=%d reason=%s key=%s", + job.Type, job.ObjId, job.Action, job.Reason, job.Key) +} diff --git a/product/product/product.pb.go b/product/product/product.pb.go index 0c6d0b1..91f1c4b 100644 --- a/product/product/product.pb.go +++ b/product/product/product.pb.go @@ -578,6 +578,497 @@ func (x *SortReq) GetSort() uint32 { return 0 } +// status: 1: 一审列表, 2: 二审列表 +type VerifyReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Status uint32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"` + Page uint32 `protobuf:"varint,2,opt,name=page,proto3" json:"page,omitempty"` + PageSize uint32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VerifyReq) Reset() { + *x = VerifyReq{} + mi := &file_proto_admin_product_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VerifyReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyReq) ProtoMessage() {} + +func (x *VerifyReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_admin_product_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyReq.ProtoReflect.Descriptor instead. +func (*VerifyReq) Descriptor() ([]byte, []int) { + return file_proto_admin_product_proto_rawDescGZIP(), []int{7} +} + +func (x *VerifyReq) GetStatus() uint32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *VerifyReq) GetPage() uint32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *VerifyReq) GetPageSize() uint32 { + if x != nil { + return x.PageSize + } + return 0 +} + +// id 为 verify 表主键;status: 1: 通过, 2: 驳回 +type VerifyStatusReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Status uint32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"` + Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VerifyStatusReq) Reset() { + *x = VerifyStatusReq{} + mi := &file_proto_admin_product_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VerifyStatusReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyStatusReq) ProtoMessage() {} + +func (x *VerifyStatusReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_admin_product_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyStatusReq.ProtoReflect.Descriptor instead. +func (*VerifyStatusReq) Descriptor() ([]byte, []int) { + return file_proto_admin_product_proto_rawDescGZIP(), []int{8} +} + +func (x *VerifyStatusReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *VerifyStatusReq) GetStatus() uint32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *VerifyStatusReq) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +type EditApplyReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EditApplyReq) Reset() { + *x = EditApplyReq{} + mi := &file_proto_admin_product_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EditApplyReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EditApplyReq) ProtoMessage() {} + +func (x *EditApplyReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_admin_product_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EditApplyReq.ProtoReflect.Descriptor instead. +func (*EditApplyReq) Descriptor() ([]byte, []int) { + return file_proto_admin_product_proto_rawDescGZIP(), []int{9} +} + +func (x *EditApplyReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *EditApplyReq) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +// TODO: 临时,企微对接后删除 +type EditApplyPassReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EditApplyPassReq) Reset() { + *x = EditApplyPassReq{} + mi := &file_proto_admin_product_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EditApplyPassReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EditApplyPassReq) ProtoMessage() {} + +func (x *EditApplyPassReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_admin_product_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EditApplyPassReq.ProtoReflect.Descriptor instead. +func (*EditApplyPassReq) Descriptor() ([]byte, []int) { + return file_proto_admin_product_proto_rawDescGZIP(), []int{10} +} + +func (x *EditApplyPassReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +type EditBaseReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Subhead string `protobuf:"bytes,3,opt,name=subhead,proto3" json:"subhead,omitempty"` + Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"` + Waybill string `protobuf:"bytes,5,opt,name=waybill,proto3" json:"waybill,omitempty"` + Weight float64 `protobuf:"fixed64,6,opt,name=weight,proto3" json:"weight,omitempty"` + Cubage string `protobuf:"bytes,7,opt,name=cubage,proto3" json:"cubage,omitempty"` + Images string `protobuf:"bytes,8,opt,name=images,proto3" json:"images,omitempty"` + PeriodValidity int32 `protobuf:"varint,9,opt,name=period_validity,json=periodValidity,proto3" json:"period_validity,omitempty"` + PublishTime string `protobuf:"bytes,10,opt,name=publish_time,json=publishTime,proto3" json:"publish_time,omitempty"` + Label string `protobuf:"bytes,11,opt,name=label,proto3" json:"label,omitempty"` + IsBuy uint32 `protobuf:"varint,12,opt,name=is_buy,json=isBuy,proto3" json:"is_buy,omitempty"` + IsIndex uint32 `protobuf:"varint,13,opt,name=is_index,json=isIndex,proto3" json:"is_index,omitempty"` + IndexImage string `protobuf:"bytes,14,opt,name=index_image,json=indexImage,proto3" json:"index_image,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EditBaseReq) Reset() { + *x = EditBaseReq{} + mi := &file_proto_admin_product_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EditBaseReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EditBaseReq) ProtoMessage() {} + +func (x *EditBaseReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_admin_product_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EditBaseReq.ProtoReflect.Descriptor instead. +func (*EditBaseReq) Descriptor() ([]byte, []int) { + return file_proto_admin_product_proto_rawDescGZIP(), []int{11} +} + +func (x *EditBaseReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *EditBaseReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *EditBaseReq) GetSubhead() string { + if x != nil { + return x.Subhead + } + return "" +} + +func (x *EditBaseReq) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *EditBaseReq) GetWaybill() string { + if x != nil { + return x.Waybill + } + return "" +} + +func (x *EditBaseReq) GetWeight() float64 { + if x != nil { + return x.Weight + } + return 0 +} + +func (x *EditBaseReq) GetCubage() string { + if x != nil { + return x.Cubage + } + return "" +} + +func (x *EditBaseReq) GetImages() string { + if x != nil { + return x.Images + } + return "" +} + +func (x *EditBaseReq) GetPeriodValidity() int32 { + if x != nil { + return x.PeriodValidity + } + return 0 +} + +func (x *EditBaseReq) GetPublishTime() string { + if x != nil { + return x.PublishTime + } + return "" +} + +func (x *EditBaseReq) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +func (x *EditBaseReq) GetIsBuy() uint32 { + if x != nil { + return x.IsBuy + } + return 0 +} + +func (x *EditBaseReq) GetIsIndex() uint32 { + if x != nil { + return x.IsIndex + } + return 0 +} + +func (x *EditBaseReq) GetIndexImage() string { + if x != nil { + return x.IndexImage + } + return "" +} + +type EditSusceptibleReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + ModelCode string `protobuf:"bytes,2,opt,name=model_code,json=modelCode,proto3" json:"model_code,omitempty"` + Price float64 `protobuf:"fixed64,3,opt,name=price,proto3" json:"price,omitempty"` + StorePrice float64 `protobuf:"fixed64,4,opt,name=store_price,json=storePrice,proto3" json:"store_price,omitempty"` + SalePrice float64 `protobuf:"fixed64,5,opt,name=sale_price,json=salePrice,proto3" json:"sale_price,omitempty"` + SharePrice float64 `protobuf:"fixed64,6,opt,name=share_price,json=sharePrice,proto3" json:"share_price,omitempty"` + AgentPrice float64 `protobuf:"fixed64,7,opt,name=agent_price,json=agentPrice,proto3" json:"agent_price,omitempty"` + SaleReward string `protobuf:"bytes,8,opt,name=sale_reward,json=saleReward,proto3" json:"sale_reward,omitempty"` + NormsNumber uint32 `protobuf:"varint,9,opt,name=norms_number,json=normsNumber,proto3" json:"norms_number,omitempty"` + BoxNumber float64 `protobuf:"fixed64,10,opt,name=box_number,json=boxNumber,proto3" json:"box_number,omitempty"` + Type uint32 `protobuf:"varint,11,opt,name=type,proto3" json:"type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EditSusceptibleReq) Reset() { + *x = EditSusceptibleReq{} + mi := &file_proto_admin_product_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EditSusceptibleReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EditSusceptibleReq) ProtoMessage() {} + +func (x *EditSusceptibleReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_admin_product_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EditSusceptibleReq.ProtoReflect.Descriptor instead. +func (*EditSusceptibleReq) Descriptor() ([]byte, []int) { + return file_proto_admin_product_proto_rawDescGZIP(), []int{12} +} + +func (x *EditSusceptibleReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *EditSusceptibleReq) GetModelCode() string { + if x != nil { + return x.ModelCode + } + return "" +} + +func (x *EditSusceptibleReq) GetPrice() float64 { + if x != nil { + return x.Price + } + return 0 +} + +func (x *EditSusceptibleReq) GetStorePrice() float64 { + if x != nil { + return x.StorePrice + } + return 0 +} + +func (x *EditSusceptibleReq) GetSalePrice() float64 { + if x != nil { + return x.SalePrice + } + return 0 +} + +func (x *EditSusceptibleReq) GetSharePrice() float64 { + if x != nil { + return x.SharePrice + } + return 0 +} + +func (x *EditSusceptibleReq) GetAgentPrice() float64 { + if x != nil { + return x.AgentPrice + } + return 0 +} + +func (x *EditSusceptibleReq) GetSaleReward() string { + if x != nil { + return x.SaleReward + } + return "" +} + +func (x *EditSusceptibleReq) GetNormsNumber() uint32 { + if x != nil { + return x.NormsNumber + } + return 0 +} + +func (x *EditSusceptibleReq) GetBoxNumber() float64 { + if x != nil { + return x.BoxNumber + } + return 0 +} + +func (x *EditSusceptibleReq) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + type ItemsData struct { state protoimpl.MessageState `protogen:"open.v1"` Count int64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` @@ -588,7 +1079,7 @@ type ItemsData struct { func (x *ItemsData) Reset() { *x = ItemsData{} - mi := &file_proto_admin_product_proto_msgTypes[7] + mi := &file_proto_admin_product_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -600,7 +1091,7 @@ func (x *ItemsData) String() string { func (*ItemsData) ProtoMessage() {} func (x *ItemsData) ProtoReflect() protoreflect.Message { - mi := &file_proto_admin_product_proto_msgTypes[7] + mi := &file_proto_admin_product_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -613,7 +1104,7 @@ func (x *ItemsData) ProtoReflect() protoreflect.Message { // Deprecated: Use ItemsData.ProtoReflect.Descriptor instead. func (*ItemsData) Descriptor() ([]byte, []int) { - return file_proto_admin_product_proto_rawDescGZIP(), []int{7} + return file_proto_admin_product_proto_rawDescGZIP(), []int{13} } func (x *ItemsData) GetCount() int64 { @@ -630,6 +1121,258 @@ func (x *ItemsData) GetItems() []*Item { return nil } +type VerifyItemsData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Count int64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` + Items []*VerifyItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VerifyItemsData) Reset() { + *x = VerifyItemsData{} + mi := &file_proto_admin_product_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VerifyItemsData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyItemsData) ProtoMessage() {} + +func (x *VerifyItemsData) ProtoReflect() protoreflect.Message { + mi := &file_proto_admin_product_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyItemsData.ProtoReflect.Descriptor instead. +func (*VerifyItemsData) Descriptor() ([]byte, []int) { + return file_proto_admin_product_proto_rawDescGZIP(), []int{14} +} + +func (x *VerifyItemsData) GetCount() int64 { + if x != nil { + return x.Count + } + return 0 +} + +func (x *VerifyItemsData) GetItems() []*VerifyItem { + if x != nil { + return x.Items + } + return nil +} + +type VerifyParams struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + ModelCode string `protobuf:"bytes,2,opt,name=model_code,json=modelCode,proto3" json:"model_code,omitempty"` + Price float64 `protobuf:"fixed64,3,opt,name=price,proto3" json:"price,omitempty"` + StorePrice float64 `protobuf:"fixed64,4,opt,name=store_price,json=storePrice,proto3" json:"store_price,omitempty"` + SalePrice float64 `protobuf:"fixed64,5,opt,name=sale_price,json=salePrice,proto3" json:"sale_price,omitempty"` + SharePrice float64 `protobuf:"fixed64,6,opt,name=share_price,json=sharePrice,proto3" json:"share_price,omitempty"` + AgentPrice float64 `protobuf:"fixed64,7,opt,name=agent_price,json=agentPrice,proto3" json:"agent_price,omitempty"` + SaleReward string `protobuf:"bytes,8,opt,name=sale_reward,json=saleReward,proto3" json:"sale_reward,omitempty"` + Type uint32 `protobuf:"varint,9,opt,name=type,proto3" json:"type,omitempty"` + NormsNumber uint32 `protobuf:"varint,10,opt,name=norms_number,json=normsNumber,proto3" json:"norms_number,omitempty"` + BoxNumber float64 `protobuf:"fixed64,11,opt,name=box_number,json=boxNumber,proto3" json:"box_number,omitempty"` + VerifyId int64 `protobuf:"varint,12,opt,name=verify_id,json=verifyId,proto3" json:"verify_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VerifyParams) Reset() { + *x = VerifyParams{} + mi := &file_proto_admin_product_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VerifyParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyParams) ProtoMessage() {} + +func (x *VerifyParams) ProtoReflect() protoreflect.Message { + mi := &file_proto_admin_product_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyParams.ProtoReflect.Descriptor instead. +func (*VerifyParams) Descriptor() ([]byte, []int) { + return file_proto_admin_product_proto_rawDescGZIP(), []int{15} +} + +func (x *VerifyParams) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *VerifyParams) GetModelCode() string { + if x != nil { + return x.ModelCode + } + return "" +} + +func (x *VerifyParams) GetPrice() float64 { + if x != nil { + return x.Price + } + return 0 +} + +func (x *VerifyParams) GetStorePrice() float64 { + if x != nil { + return x.StorePrice + } + return 0 +} + +func (x *VerifyParams) GetSalePrice() float64 { + if x != nil { + return x.SalePrice + } + return 0 +} + +func (x *VerifyParams) GetSharePrice() float64 { + if x != nil { + return x.SharePrice + } + return 0 +} + +func (x *VerifyParams) GetAgentPrice() float64 { + if x != nil { + return x.AgentPrice + } + return 0 +} + +func (x *VerifyParams) GetSaleReward() string { + if x != nil { + return x.SaleReward + } + return "" +} + +func (x *VerifyParams) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *VerifyParams) GetNormsNumber() uint32 { + if x != nil { + return x.NormsNumber + } + return 0 +} + +func (x *VerifyParams) GetBoxNumber() float64 { + if x != nil { + return x.BoxNumber + } + return 0 +} + +func (x *VerifyParams) GetVerifyId() int64 { + if x != nil { + return x.VerifyId + } + return 0 +} + +type VerifyItem struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + SalesModel uint32 `protobuf:"varint,2,opt,name=sales_model,json=salesModel,proto3" json:"sales_model,omitempty"` + New *VerifyParams `protobuf:"bytes,3,opt,name=new,proto3" json:"new,omitempty"` + Old *VerifyParams `protobuf:"bytes,4,opt,name=old,proto3" json:"old,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VerifyItem) Reset() { + *x = VerifyItem{} + mi := &file_proto_admin_product_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VerifyItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyItem) ProtoMessage() {} + +func (x *VerifyItem) ProtoReflect() protoreflect.Message { + mi := &file_proto_admin_product_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyItem.ProtoReflect.Descriptor instead. +func (*VerifyItem) Descriptor() ([]byte, []int) { + return file_proto_admin_product_proto_rawDescGZIP(), []int{16} +} + +func (x *VerifyItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *VerifyItem) GetSalesModel() uint32 { + if x != nil { + return x.SalesModel + } + return 0 +} + +func (x *VerifyItem) GetNew() *VerifyParams { + if x != nil { + return x.New + } + return nil +} + +func (x *VerifyItem) GetOld() *VerifyParams { + if x != nil { + return x.Old + } + return nil +} + type NameItem struct { state protoimpl.MessageState `protogen:"open.v1"` Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` @@ -640,7 +1383,7 @@ type NameItem struct { func (x *NameItem) Reset() { *x = NameItem{} - mi := &file_proto_admin_product_proto_msgTypes[8] + mi := &file_proto_admin_product_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -652,7 +1395,7 @@ func (x *NameItem) String() string { func (*NameItem) ProtoMessage() {} func (x *NameItem) ProtoReflect() protoreflect.Message { - mi := &file_proto_admin_product_proto_msgTypes[8] + mi := &file_proto_admin_product_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -665,7 +1408,7 @@ func (x *NameItem) ProtoReflect() protoreflect.Message { // Deprecated: Use NameItem.ProtoReflect.Descriptor instead. func (*NameItem) Descriptor() ([]byte, []int) { - return file_proto_admin_product_proto_rawDescGZIP(), []int{8} + return file_proto_admin_product_proto_rawDescGZIP(), []int{17} } func (x *NameItem) GetId() int64 { @@ -726,7 +1469,7 @@ type Item struct { func (x *Item) Reset() { *x = Item{} - mi := &file_proto_admin_product_proto_msgTypes[9] + mi := &file_proto_admin_product_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -738,7 +1481,7 @@ func (x *Item) String() string { func (*Item) ProtoMessage() {} func (x *Item) ProtoReflect() protoreflect.Message { - mi := &file_proto_admin_product_proto_msgTypes[9] + mi := &file_proto_admin_product_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -751,7 +1494,7 @@ func (x *Item) ProtoReflect() protoreflect.Message { // Deprecated: Use Item.ProtoReflect.Descriptor instead. func (*Item) Descriptor() ([]byte, []int) { - return file_proto_admin_product_proto_rawDescGZIP(), []int{9} + return file_proto_admin_product_proto_rawDescGZIP(), []int{18} } func (x *Item) GetId() int64 { @@ -1067,10 +1810,91 @@ const file_proto_admin_product_proto_rawDesc = "" + "\x06reason\x18\x03 \x01(\tR\x06reason\"-\n" + "\aSortReq\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + - "\x04sort\x18\x02 \x01(\rR\x04sort\"F\n" + + "\x04sort\x18\x02 \x01(\rR\x04sort\"T\n" + + "\tVerifyReq\x12\x16\n" + + "\x06status\x18\x01 \x01(\rR\x06status\x12\x12\n" + + "\x04page\x18\x02 \x01(\rR\x04page\x12\x1b\n" + + "\tpage_size\x18\x03 \x01(\rR\bpageSize\"Q\n" + + "\x0fVerifyStatusReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" + + "\x06status\x18\x02 \x01(\rR\x06status\x12\x16\n" + + "\x06reason\x18\x03 \x01(\tR\x06reason\"6\n" + + "\fEditApplyReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" + + "\x06reason\x18\x02 \x01(\tR\x06reason\"\"\n" + + "\x10EditApplyPassReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\"\xfc\x02\n" + + "\vEditBaseReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x18\n" + + "\asubhead\x18\x03 \x01(\tR\asubhead\x12\x18\n" + + "\acontent\x18\x04 \x01(\tR\acontent\x12\x18\n" + + "\awaybill\x18\x05 \x01(\tR\awaybill\x12\x16\n" + + "\x06weight\x18\x06 \x01(\x01R\x06weight\x12\x16\n" + + "\x06cubage\x18\a \x01(\tR\x06cubage\x12\x16\n" + + "\x06images\x18\b \x01(\tR\x06images\x12'\n" + + "\x0fperiod_validity\x18\t \x01(\x05R\x0eperiodValidity\x12!\n" + + "\fpublish_time\x18\n" + + " \x01(\tR\vpublishTime\x12\x14\n" + + "\x05label\x18\v \x01(\tR\x05label\x12\x15\n" + + "\x06is_buy\x18\f \x01(\rR\x05isBuy\x12\x19\n" + + "\bis_index\x18\r \x01(\rR\aisIndex\x12\x1f\n" + + "\vindex_image\x18\x0e \x01(\tR\n" + + "indexImage\"\xd2\x02\n" + + "\x12EditSusceptibleReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x1d\n" + + "\n" + + "model_code\x18\x02 \x01(\tR\tmodelCode\x12\x14\n" + + "\x05price\x18\x03 \x01(\x01R\x05price\x12\x1f\n" + + "\vstore_price\x18\x04 \x01(\x01R\n" + + "storePrice\x12\x1d\n" + + "\n" + + "sale_price\x18\x05 \x01(\x01R\tsalePrice\x12\x1f\n" + + "\vshare_price\x18\x06 \x01(\x01R\n" + + "sharePrice\x12\x1f\n" + + "\vagent_price\x18\a \x01(\x01R\n" + + "agentPrice\x12\x1f\n" + + "\vsale_reward\x18\b \x01(\tR\n" + + "saleReward\x12!\n" + + "\fnorms_number\x18\t \x01(\rR\vnormsNumber\x12\x1d\n" + + "\n" + + "box_number\x18\n" + + " \x01(\x01R\tboxNumber\x12\x12\n" + + "\x04type\x18\v \x01(\rR\x04type\"F\n" + "\tItemsData\x12\x14\n" + "\x05count\x18\x01 \x01(\x03R\x05count\x12#\n" + - "\x05items\x18\x02 \x03(\v2\r.product.ItemR\x05items\".\n" + + "\x05items\x18\x02 \x03(\v2\r.product.ItemR\x05items\"R\n" + + "\x0fVerifyItemsData\x12\x14\n" + + "\x05count\x18\x01 \x01(\x03R\x05count\x12)\n" + + "\x05items\x18\x02 \x03(\v2\x13.product.VerifyItemR\x05items\"\xe9\x02\n" + + "\fVerifyParams\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x1d\n" + + "\n" + + "model_code\x18\x02 \x01(\tR\tmodelCode\x12\x14\n" + + "\x05price\x18\x03 \x01(\x01R\x05price\x12\x1f\n" + + "\vstore_price\x18\x04 \x01(\x01R\n" + + "storePrice\x12\x1d\n" + + "\n" + + "sale_price\x18\x05 \x01(\x01R\tsalePrice\x12\x1f\n" + + "\vshare_price\x18\x06 \x01(\x01R\n" + + "sharePrice\x12\x1f\n" + + "\vagent_price\x18\a \x01(\x01R\n" + + "agentPrice\x12\x1f\n" + + "\vsale_reward\x18\b \x01(\tR\n" + + "saleReward\x12\x12\n" + + "\x04type\x18\t \x01(\rR\x04type\x12!\n" + + "\fnorms_number\x18\n" + + " \x01(\rR\vnormsNumber\x12\x1d\n" + + "\n" + + "box_number\x18\v \x01(\x01R\tboxNumber\x12\x1b\n" + + "\tverify_id\x18\f \x01(\x03R\bverifyId\"\x93\x01\n" + + "\n" + + "VerifyItem\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1f\n" + + "\vsales_model\x18\x02 \x01(\rR\n" + + "salesModel\x12'\n" + + "\x03new\x18\x03 \x01(\v2\x15.product.VerifyParamsR\x03new\x12'\n" + + "\x03old\x18\x04 \x01(\v2\x15.product.VerifyParamsR\x03old\".\n" + "\bNameItem\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\"\x8e\b\n" + @@ -1122,14 +1946,21 @@ const file_proto_admin_product_proto_rawDesc = "" + "\x06reason\x18\" \x01(\tR\x06reason\x12\x1d\n" + "\n" + "admin_name\x18# \x01(\tR\tadminName\x12\x12\n" + - "\x04edit\x18$ \x01(\rR\x04edit2\xee\x03\n" + + "\x04edit\x18$ \x01(\rR\x04edit2\xa6\t\n" + "\aProduct\x12M\n" + "\x06Create\x12\x12.product.CreateReq\x1a\x11.product.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/admin/v3/product\x12N\n" + "\x04Info\x12\x10.product.InfoReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x12\x16/admin/v3/product/info\x12K\n" + "\x05Items\x12\x11.product.ItemsReq\x1a\x11.product.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\x12\x11/admin/v3/product\x12Q\n" + "\x05Names\x12\x11.product.NamesReq\x1a\x11.product.Response\"\"\x82\xd3\xe4\x93\x02\x1c:\x01*\x12\x17/admin/v3/product/names\x12T\n" + "\x06Status\x12\x12.product.StatusReq\x1a\x11.product.Response\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\x1a\x18/admin/v3/product/status\x12N\n" + - "\x04Sort\x12\x10.product.SortReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x1a\x16/admin/v3/product/sortB\vZ\t./productb\x06proto3" + "\x04Sort\x12\x10.product.SortReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x1a\x16/admin/v3/product/sort\x12T\n" + + "\x06Verify\x12\x12.product.VerifyReq\x1a\x11.product.Response\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\x12\x18/admin/v3/product/verify\x12e\n" + + "\vVerifyFirst\x12\x18.product.VerifyStatusReq\x1a\x11.product.Response\")\x82\xd3\xe4\x93\x02#:\x01*\x1a\x1e/admin/v3/product/verify/first\x12g\n" + + "\fVerifySecond\x12\x18.product.VerifyStatusReq\x1a\x11.product.Response\"*\x82\xd3\xe4\x93\x02$:\x01*\x1a\x1f/admin/v3/product/verify/second\x12^\n" + + "\tEditApply\x12\x15.product.EditApplyReq\x1a\x11.product.Response\"'\x82\xd3\xe4\x93\x02!:\x01*\"\x1c/admin/v3/product/edit/apply\x12k\n" + + "\rEditApplyPass\x12\x19.product.EditApplyPassReq\x1a\x11.product.Response\",\x82\xd3\xe4\x93\x02&:\x01*\x1a!/admin/v3/product/edit/apply/pass\x12V\n" + + "\bEditBase\x12\x14.product.EditBaseReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x1a\x16/admin/v3/product/base\x12k\n" + + "\x0fEditSusceptible\x12\x1b.product.EditSusceptibleReq\x1a\x11.product.Response\"(\x82\xd3\xe4\x93\x02\":\x01*\x1a\x1d/admin/v3/product/susceptibleB\vZ\t./productb\x06proto3" var ( file_proto_admin_product_proto_rawDescOnce sync.Once @@ -1143,38 +1974,64 @@ func file_proto_admin_product_proto_rawDescGZIP() []byte { return file_proto_admin_product_proto_rawDescData } -var file_proto_admin_product_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_proto_admin_product_proto_msgTypes = make([]protoimpl.MessageInfo, 19) var file_proto_admin_product_proto_goTypes = []any{ - (*Response)(nil), // 0: product.Response - (*CreateReq)(nil), // 1: product.CreateReq - (*InfoReq)(nil), // 2: product.InfoReq - (*ItemsReq)(nil), // 3: product.ItemsReq - (*NamesReq)(nil), // 4: product.NamesReq - (*StatusReq)(nil), // 5: product.StatusReq - (*SortReq)(nil), // 6: product.SortReq - (*ItemsData)(nil), // 7: product.ItemsData - (*NameItem)(nil), // 8: product.NameItem - (*Item)(nil), // 9: product.Item + (*Response)(nil), // 0: product.Response + (*CreateReq)(nil), // 1: product.CreateReq + (*InfoReq)(nil), // 2: product.InfoReq + (*ItemsReq)(nil), // 3: product.ItemsReq + (*NamesReq)(nil), // 4: product.NamesReq + (*StatusReq)(nil), // 5: product.StatusReq + (*SortReq)(nil), // 6: product.SortReq + (*VerifyReq)(nil), // 7: product.VerifyReq + (*VerifyStatusReq)(nil), // 8: product.VerifyStatusReq + (*EditApplyReq)(nil), // 9: product.EditApplyReq + (*EditApplyPassReq)(nil), // 10: product.EditApplyPassReq + (*EditBaseReq)(nil), // 11: product.EditBaseReq + (*EditSusceptibleReq)(nil), // 12: product.EditSusceptibleReq + (*ItemsData)(nil), // 13: product.ItemsData + (*VerifyItemsData)(nil), // 14: product.VerifyItemsData + (*VerifyParams)(nil), // 15: product.VerifyParams + (*VerifyItem)(nil), // 16: product.VerifyItem + (*NameItem)(nil), // 17: product.NameItem + (*Item)(nil), // 18: product.Item } var file_proto_admin_product_proto_depIdxs = []int32{ - 9, // 0: product.ItemsData.items:type_name -> product.Item - 1, // 1: product.Product.Create:input_type -> product.CreateReq - 2, // 2: product.Product.Info:input_type -> product.InfoReq - 3, // 3: product.Product.Items:input_type -> product.ItemsReq - 4, // 4: product.Product.Names:input_type -> product.NamesReq - 5, // 5: product.Product.Status:input_type -> product.StatusReq - 6, // 6: product.Product.Sort:input_type -> product.SortReq - 0, // 7: product.Product.Create:output_type -> product.Response - 0, // 8: product.Product.Info:output_type -> product.Response - 0, // 9: product.Product.Items:output_type -> product.Response - 0, // 10: product.Product.Names:output_type -> product.Response - 0, // 11: product.Product.Status:output_type -> product.Response - 0, // 12: product.Product.Sort:output_type -> product.Response - 7, // [7:13] is the sub-list for method output_type - 1, // [1:7] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 18, // 0: product.ItemsData.items:type_name -> product.Item + 16, // 1: product.VerifyItemsData.items:type_name -> product.VerifyItem + 15, // 2: product.VerifyItem.new:type_name -> product.VerifyParams + 15, // 3: product.VerifyItem.old:type_name -> product.VerifyParams + 1, // 4: product.Product.Create:input_type -> product.CreateReq + 2, // 5: product.Product.Info:input_type -> product.InfoReq + 3, // 6: product.Product.Items:input_type -> product.ItemsReq + 4, // 7: product.Product.Names:input_type -> product.NamesReq + 5, // 8: product.Product.Status:input_type -> product.StatusReq + 6, // 9: product.Product.Sort:input_type -> product.SortReq + 7, // 10: product.Product.Verify:input_type -> product.VerifyReq + 8, // 11: product.Product.VerifyFirst:input_type -> product.VerifyStatusReq + 8, // 12: product.Product.VerifySecond:input_type -> product.VerifyStatusReq + 9, // 13: product.Product.EditApply:input_type -> product.EditApplyReq + 10, // 14: product.Product.EditApplyPass:input_type -> product.EditApplyPassReq + 11, // 15: product.Product.EditBase:input_type -> product.EditBaseReq + 12, // 16: product.Product.EditSusceptible:input_type -> product.EditSusceptibleReq + 0, // 17: product.Product.Create:output_type -> product.Response + 0, // 18: product.Product.Info:output_type -> product.Response + 0, // 19: product.Product.Items:output_type -> product.Response + 0, // 20: product.Product.Names:output_type -> product.Response + 0, // 21: product.Product.Status:output_type -> product.Response + 0, // 22: product.Product.Sort:output_type -> product.Response + 0, // 23: product.Product.Verify:output_type -> product.Response + 0, // 24: product.Product.VerifyFirst:output_type -> product.Response + 0, // 25: product.Product.VerifySecond:output_type -> product.Response + 0, // 26: product.Product.EditApply:output_type -> product.Response + 0, // 27: product.Product.EditApplyPass:output_type -> product.Response + 0, // 28: product.Product.EditBase:output_type -> product.Response + 0, // 29: product.Product.EditSusceptible:output_type -> product.Response + 17, // [17:30] is the sub-list for method output_type + 4, // [4:17] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_proto_admin_product_proto_init() } @@ -1188,7 +2045,7 @@ func file_proto_admin_product_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_admin_product_proto_rawDesc), len(file_proto_admin_product_proto_rawDesc)), NumEnums: 0, - NumMessages: 10, + NumMessages: 19, NumExtensions: 0, NumServices: 1, }, diff --git a/product/product/product_grpc.pb.go b/product/product/product_grpc.pb.go index 9dc8bbc..bd9b23f 100644 --- a/product/product/product_grpc.pb.go +++ b/product/product/product_grpc.pb.go @@ -19,12 +19,19 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - Product_Create_FullMethodName = "/product.Product/Create" - Product_Info_FullMethodName = "/product.Product/Info" - Product_Items_FullMethodName = "/product.Product/Items" - Product_Names_FullMethodName = "/product.Product/Names" - Product_Status_FullMethodName = "/product.Product/Status" - Product_Sort_FullMethodName = "/product.Product/Sort" + Product_Create_FullMethodName = "/product.Product/Create" + Product_Info_FullMethodName = "/product.Product/Info" + Product_Items_FullMethodName = "/product.Product/Items" + Product_Names_FullMethodName = "/product.Product/Names" + Product_Status_FullMethodName = "/product.Product/Status" + Product_Sort_FullMethodName = "/product.Product/Sort" + Product_Verify_FullMethodName = "/product.Product/Verify" + Product_VerifyFirst_FullMethodName = "/product.Product/VerifyFirst" + Product_VerifySecond_FullMethodName = "/product.Product/VerifySecond" + Product_EditApply_FullMethodName = "/product.Product/EditApply" + Product_EditApplyPass_FullMethodName = "/product.Product/EditApplyPass" + Product_EditBase_FullMethodName = "/product.Product/EditBase" + Product_EditSusceptible_FullMethodName = "/product.Product/EditSusceptible" ) // ProductClient is the client API for Product service. @@ -37,6 +44,20 @@ type ProductClient interface { Names(ctx context.Context, in *NamesReq, opts ...grpc.CallOption) (*Response, error) Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) Sort(ctx context.Context, in *SortReq, opts ...grpc.CallOption) (*Response, error) + // 审核列表: status: 1: 一审, 2: 二审 + Verify(ctx context.Context, in *VerifyReq, opts ...grpc.CallOption) (*Response, error) + // 一审通过/驳回 + VerifyFirst(ctx context.Context, in *VerifyStatusReq, opts ...grpc.CallOption) (*Response, error) + // 二审通过/驳回 + VerifySecond(ctx context.Context, in *VerifyStatusReq, opts ...grpc.CallOption) (*Response, error) + // 编辑申请(解锁编辑权限) + EditApply(ctx context.Context, in *EditApplyReq, opts ...grpc.CallOption) (*Response, error) + // TODO: 临时接口,企微编辑申请审批对接后删除 + EditApplyPass(ctx context.Context, in *EditApplyPassReq, opts ...grpc.CallOption) (*Response, error) + // 编辑基础信息 + EditBase(ctx context.Context, in *EditBaseReq, opts ...grpc.CallOption) (*Response, error) + // 编辑敏感信息(进入一审) + EditSusceptible(ctx context.Context, in *EditSusceptibleReq, opts ...grpc.CallOption) (*Response, error) } type productClient struct { @@ -107,6 +128,76 @@ func (c *productClient) Sort(ctx context.Context, in *SortReq, opts ...grpc.Call return out, nil } +func (c *productClient) Verify(ctx context.Context, in *VerifyReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Product_Verify_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *productClient) VerifyFirst(ctx context.Context, in *VerifyStatusReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Product_VerifyFirst_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *productClient) VerifySecond(ctx context.Context, in *VerifyStatusReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Product_VerifySecond_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *productClient) EditApply(ctx context.Context, in *EditApplyReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Product_EditApply_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *productClient) EditApplyPass(ctx context.Context, in *EditApplyPassReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Product_EditApplyPass_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *productClient) EditBase(ctx context.Context, in *EditBaseReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Product_EditBase_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *productClient) EditSusceptible(ctx context.Context, in *EditSusceptibleReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Product_EditSusceptible_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // ProductServer is the server API for Product service. // All implementations must embed UnimplementedProductServer // for forward compatibility. @@ -117,6 +208,20 @@ type ProductServer interface { Names(context.Context, *NamesReq) (*Response, error) Status(context.Context, *StatusReq) (*Response, error) Sort(context.Context, *SortReq) (*Response, error) + // 审核列表: status: 1: 一审, 2: 二审 + Verify(context.Context, *VerifyReq) (*Response, error) + // 一审通过/驳回 + VerifyFirst(context.Context, *VerifyStatusReq) (*Response, error) + // 二审通过/驳回 + VerifySecond(context.Context, *VerifyStatusReq) (*Response, error) + // 编辑申请(解锁编辑权限) + EditApply(context.Context, *EditApplyReq) (*Response, error) + // TODO: 临时接口,企微编辑申请审批对接后删除 + EditApplyPass(context.Context, *EditApplyPassReq) (*Response, error) + // 编辑基础信息 + EditBase(context.Context, *EditBaseReq) (*Response, error) + // 编辑敏感信息(进入一审) + EditSusceptible(context.Context, *EditSusceptibleReq) (*Response, error) mustEmbedUnimplementedProductServer() } @@ -145,6 +250,27 @@ func (UnimplementedProductServer) Status(context.Context, *StatusReq) (*Response func (UnimplementedProductServer) Sort(context.Context, *SortReq) (*Response, error) { return nil, status.Error(codes.Unimplemented, "method Sort not implemented") } +func (UnimplementedProductServer) Verify(context.Context, *VerifyReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Verify not implemented") +} +func (UnimplementedProductServer) VerifyFirst(context.Context, *VerifyStatusReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method VerifyFirst not implemented") +} +func (UnimplementedProductServer) VerifySecond(context.Context, *VerifyStatusReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method VerifySecond not implemented") +} +func (UnimplementedProductServer) EditApply(context.Context, *EditApplyReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method EditApply not implemented") +} +func (UnimplementedProductServer) EditApplyPass(context.Context, *EditApplyPassReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method EditApplyPass not implemented") +} +func (UnimplementedProductServer) EditBase(context.Context, *EditBaseReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method EditBase not implemented") +} +func (UnimplementedProductServer) EditSusceptible(context.Context, *EditSusceptibleReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method EditSusceptible not implemented") +} func (UnimplementedProductServer) mustEmbedUnimplementedProductServer() {} func (UnimplementedProductServer) testEmbeddedByValue() {} @@ -274,6 +400,132 @@ func _Product_Sort_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _Product_Verify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VerifyReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).Verify(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_Verify_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).Verify(ctx, req.(*VerifyReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Product_VerifyFirst_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VerifyStatusReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).VerifyFirst(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_VerifyFirst_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).VerifyFirst(ctx, req.(*VerifyStatusReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Product_VerifySecond_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VerifyStatusReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).VerifySecond(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_VerifySecond_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).VerifySecond(ctx, req.(*VerifyStatusReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Product_EditApply_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EditApplyReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).EditApply(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_EditApply_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).EditApply(ctx, req.(*EditApplyReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Product_EditApplyPass_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EditApplyPassReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).EditApplyPass(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_EditApplyPass_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).EditApplyPass(ctx, req.(*EditApplyPassReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Product_EditBase_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EditBaseReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).EditBase(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_EditBase_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).EditBase(ctx, req.(*EditBaseReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Product_EditSusceptible_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EditSusceptibleReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).EditSusceptible(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_EditSusceptible_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).EditSusceptible(ctx, req.(*EditSusceptibleReq)) + } + return interceptor(ctx, in, info, handler) +} + // Product_ServiceDesc is the grpc.ServiceDesc for Product service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -305,6 +557,34 @@ var Product_ServiceDesc = grpc.ServiceDesc{ MethodName: "Sort", Handler: _Product_Sort_Handler, }, + { + MethodName: "Verify", + Handler: _Product_Verify_Handler, + }, + { + MethodName: "VerifyFirst", + Handler: _Product_VerifyFirst_Handler, + }, + { + MethodName: "VerifySecond", + Handler: _Product_VerifySecond_Handler, + }, + { + MethodName: "EditApply", + Handler: _Product_EditApply_Handler, + }, + { + MethodName: "EditApplyPass", + Handler: _Product_EditApplyPass_Handler, + }, + { + MethodName: "EditBase", + Handler: _Product_EditBase_Handler, + }, + { + MethodName: "EditSusceptible", + Handler: _Product_EditSusceptible_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "proto/admin/product.proto", diff --git a/product/productclient/product.go b/product/productclient/product.go index 61e7616..d98e5b2 100644 --- a/product/productclient/product.go +++ b/product/productclient/product.go @@ -13,16 +13,25 @@ import ( ) type ( - CreateReq = product.CreateReq - InfoReq = product.InfoReq - ItemsReq = product.ItemsReq - NamesReq = product.NamesReq - StatusReq = product.StatusReq - SortReq = product.SortReq - ItemsData = product.ItemsData - NameItem = product.NameItem - Item = product.Item - Response = product.Response + CreateReq = product.CreateReq + InfoReq = product.InfoReq + ItemsReq = product.ItemsReq + NamesReq = product.NamesReq + StatusReq = product.StatusReq + SortReq = product.SortReq + VerifyReq = product.VerifyReq + VerifyStatusReq = product.VerifyStatusReq + EditApplyReq = product.EditApplyReq + EditApplyPassReq = product.EditApplyPassReq + EditBaseReq = product.EditBaseReq + EditSusceptibleReq = product.EditSusceptibleReq + ItemsData = product.ItemsData + VerifyItemsData = product.VerifyItemsData + VerifyParams = product.VerifyParams + VerifyItem = product.VerifyItem + NameItem = product.NameItem + Item = product.Item + Response = product.Response Product interface { Create(ctx context.Context, in *CreateReq, opts ...grpc.CallOption) (*Response, error) @@ -31,6 +40,13 @@ type ( Names(ctx context.Context, in *NamesReq, opts ...grpc.CallOption) (*Response, error) Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) Sort(ctx context.Context, in *SortReq, opts ...grpc.CallOption) (*Response, error) + Verify(ctx context.Context, in *VerifyReq, opts ...grpc.CallOption) (*Response, error) + VerifyFirst(ctx context.Context, in *VerifyStatusReq, opts ...grpc.CallOption) (*Response, error) + VerifySecond(ctx context.Context, in *VerifyStatusReq, opts ...grpc.CallOption) (*Response, error) + EditApply(ctx context.Context, in *EditApplyReq, opts ...grpc.CallOption) (*Response, error) + EditApplyPass(ctx context.Context, in *EditApplyPassReq, opts ...grpc.CallOption) (*Response, error) + EditBase(ctx context.Context, in *EditBaseReq, opts ...grpc.CallOption) (*Response, error) + EditSusceptible(ctx context.Context, in *EditSusceptibleReq, opts ...grpc.CallOption) (*Response, error) } defaultProduct struct { @@ -73,3 +89,38 @@ func (m *defaultProduct) Sort(ctx context.Context, in *SortReq, opts ...grpc.Cal client := product.NewProductClient(m.cli.Conn()) return client.Sort(ctx, in, opts...) } + +func (m *defaultProduct) Verify(ctx context.Context, in *VerifyReq, opts ...grpc.CallOption) (*Response, error) { + client := product.NewProductClient(m.cli.Conn()) + return client.Verify(ctx, in, opts...) +} + +func (m *defaultProduct) VerifyFirst(ctx context.Context, in *VerifyStatusReq, opts ...grpc.CallOption) (*Response, error) { + client := product.NewProductClient(m.cli.Conn()) + return client.VerifyFirst(ctx, in, opts...) +} + +func (m *defaultProduct) VerifySecond(ctx context.Context, in *VerifyStatusReq, opts ...grpc.CallOption) (*Response, error) { + client := product.NewProductClient(m.cli.Conn()) + return client.VerifySecond(ctx, in, opts...) +} + +func (m *defaultProduct) EditApply(ctx context.Context, in *EditApplyReq, opts ...grpc.CallOption) (*Response, error) { + client := product.NewProductClient(m.cli.Conn()) + return client.EditApply(ctx, in, opts...) +} + +func (m *defaultProduct) EditApplyPass(ctx context.Context, in *EditApplyPassReq, opts ...grpc.CallOption) (*Response, error) { + client := product.NewProductClient(m.cli.Conn()) + return client.EditApplyPass(ctx, in, opts...) +} + +func (m *defaultProduct) EditBase(ctx context.Context, in *EditBaseReq, opts ...grpc.CallOption) (*Response, error) { + client := product.NewProductClient(m.cli.Conn()) + return client.EditBase(ctx, in, opts...) +} + +func (m *defaultProduct) EditSusceptible(ctx context.Context, in *EditSusceptibleReq, opts ...grpc.CallOption) (*Response, error) { + client := product.NewProductClient(m.cli.Conn()) + return client.EditSusceptible(ctx, in, opts...) +} diff --git a/product/proto/admin/product.proto b/product/proto/admin/product.proto index 304a1e6..9abea73 100644 --- a/product/proto/admin/product.proto +++ b/product/proto/admin/product.proto @@ -42,6 +42,56 @@ service Product { body: "*" }; } + // 审核列表: status: 1: 一审, 2: 二审 + rpc Verify(VerifyReq) returns (Response) { + option (google.api.http) = { + get: "/admin/v3/product/verify" + body: "*" + }; + } + // 一审通过/驳回 + rpc VerifyFirst(VerifyStatusReq) returns (Response) { + option (google.api.http) = { + put: "/admin/v3/product/verify/first" + body: "*" + }; + } + // 二审通过/驳回 + rpc VerifySecond(VerifyStatusReq) returns (Response) { + option (google.api.http) = { + put: "/admin/v3/product/verify/second" + body: "*" + }; + } + // 编辑申请(解锁编辑权限) + rpc EditApply(EditApplyReq) returns (Response) { + option (google.api.http) = { + post: "/admin/v3/product/edit/apply" + body: "*" + }; + } + // 编辑基础信息 + rpc EditBase(EditBaseReq) returns (Response) { + option (google.api.http) = { + put: "/admin/v3/product/base" + body: "*" + }; + } + // 编辑敏感信息(进入一审) + rpc EditSusceptible(EditSusceptibleReq) returns (Response) { + option (google.api.http) = { + put: "/admin/v3/product/susceptible" + body: "*" + }; + } + + // TODO: 临时接口,企微编辑申请审批对接后删除 + rpc EditApplyPass(EditApplyPassReq) returns (Response) { + option (google.api.http) = { + put: "/admin/v3/product/edit/apply/pass" + body: "*" + }; + } } message Response { @@ -102,11 +152,93 @@ message SortReq { uint32 sort = 2; } +// status: 1: 一审列表, 2: 二审列表 +message VerifyReq { + uint32 status = 1; + uint32 page = 2; + uint32 page_size = 3; +} + +// id 为 verify 表主键;status: 1: 通过, 2: 驳回 +message VerifyStatusReq { + int64 id = 1; + uint32 status = 2; + string reason = 3; +} + +message EditApplyReq { + int64 id = 1; + string reason = 2; +} + +// TODO: 临时,企微对接后删除 +message EditApplyPassReq { + int64 id = 1; +} + +message EditBaseReq { + int64 id = 1; + string name = 2; + string subhead = 3; + string content = 4; + string waybill = 5; + double weight = 6; + string cubage = 7; + string images = 8; + int32 period_validity = 9; + string publish_time = 10; + string label = 11; + uint32 is_buy = 12; + uint32 is_index = 13; + string index_image = 14; +} + +message EditSusceptibleReq { + int64 id = 1; + string model_code = 2; + double price = 3; + double store_price = 4; + double sale_price = 5; + double share_price = 6; + double agent_price = 7; + string sale_reward = 8; + uint32 norms_number = 9; + double box_number = 10; + uint32 type = 11; +} + message ItemsData { int64 count = 1; repeated Item items = 2; } +message VerifyItemsData { + int64 count = 1; + repeated VerifyItem items = 2; +} + +message VerifyParams { + int64 id = 1; + string model_code = 2; + double price = 3; + double store_price = 4; + double sale_price = 5; + double share_price = 6; + double agent_price = 7; + string sale_reward = 8; + uint32 type = 9; + uint32 norms_number = 10; + double box_number = 11; + int64 verify_id = 12; +} + +message VerifyItem { + string name = 1; + uint32 sales_model = 2; + VerifyParams new = 3; + VerifyParams old = 4; +} + message NameItem { int64 id = 1; string name = 2; diff --git a/product/validator/validator.go b/product/validator/validator.go index 4f05953..242b148 100644 --- a/product/validator/validator.go +++ b/product/validator/validator.go @@ -107,3 +107,116 @@ func (p ProductSortValidator) GetMessage() validate.ValidatorMessages { "Sort.required": "排序不能为空", } } + +type ProductVerifyItemsValidator struct { + Status uint32 `validate:"required,oneof=1 2"` + Page uint32 `validate:"omitempty,min=1"` + PageSize uint32 `validate:"omitempty,min=1,max=100"` +} + +func (p ProductVerifyItemsValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Status.required": "状态不能为空", + "Status.oneof": "状态不对", + "Page.min": "页码最小为1", + "PageSize.min": "每页数量最小为1", + "PageSize.max": "每页数量最大为100", + } +} + +type ProductVerifyStatusValidator struct { + Id int64 `validate:"required,gt=0"` + Status uint32 `validate:"required,oneof=1 2"` + Reason string `validate:"max=255"` +} + +func (p ProductVerifyStatusValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + "Status.required": "状态不能为空", + "Status.oneof": "状态不对", + } +} + +type ProductEditApplyValidator struct { + Id int64 `validate:"required,gt=0"` + Reason string `validate:"required,max=255"` +} + +func (p ProductEditApplyValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + "Reason.required": "原因不能为空", + } +} + +type ProductEditApplyPassValidator struct { + Id int64 `validate:"required,gt=0"` +} + +func (p ProductEditApplyPassValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + } +} + +type ProductEditBaseValidator struct { + Id int64 `validate:"required,gt=0"` + Name string `validate:"required,max=256"` + Subhead string `validate:"required,max=255"` + Content string `validate:"required"` + Waybill string `validate:"required,max=255"` + Weight float64 `validate:"required"` + Cubage string `validate:"required,max=255"` + Images string `validate:"required,max=512"` + PeriodValidity int32 `validate:"required"` + PublishTime string `validate:"max=32"` + Label string `validate:"max=255"` + IsBuy uint32 `validate:"omitempty,oneof=1 2"` + IsIndex uint32 `validate:"omitempty,oneof=1 2"` + IndexImage string `validate:"max=255"` +} + +func (p ProductEditBaseValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + "Name.required": "产品名不能为空", + "Subhead.required": "副标题不能为空", + "Content.required": "内容不能为空", + "Images.required": "图片不能为空", + "PeriodValidity.required": "有效期不能为空", + "Waybill.required": "运货单图片不能为空", + "Weight.required": "重量不能为空", + "Cubage.required": "体积不能为空", + } +} + +type ProductEditSusceptibleValidator struct { + Id int64 `validate:"required,gt=0"` + ModelCode string `validate:"required,max=255"` + Price float64 `validate:"required"` + StorePrice float64 + SalePrice float64 + SharePrice float64 + AgentPrice float64 + SaleReward string `validate:"max=255"` + NormsNumber uint32 `validate:"required,min=1"` + BoxNumber float64 + Type uint32 `validate:"required,oneof=1 2 3"` +} + +func (p ProductEditSusceptibleValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + "ModelCode.required": "请输入机器码", + "Price.required": "价格不能为空", + "NormsNumber.required": "缺少一份中有几个", + "Type.required": "请选择类型", + "Type.oneof": "类型不对", + } +} From 424e67acdc87f622079e26d7e8f269e1add38bb0 Mon Sep 17 00:00:00 2001 From: zzw <1464003642@qq.com> Date: Tue, 11 Aug 2026 17:12:37 +0800 Subject: [PATCH 3/3] feat: test ci cd --- .dockerignore | 9 +++ .gitea/workflows/cd-test.yml | 33 ++++++++ .gitea/workflows/ci.yml | 41 ++++++++-- .gitignore | 3 +- README.md | 81 +++++++++++++++++-- admin/Dockerfile | 34 ++++++++ bff/Dockerfile | 35 +++++++- deploy/docker-compose.mysql.yml | 16 ---- deploy/docker-compose.redis.yml | 14 ---- deploy/docker-compose.yml | 2 +- pkg/utils/status.go | 14 +++- product/Dockerfile | 34 ++++++++ product/internal/logic/createlogic.go | 16 ++-- product/internal/logic/editapplylogic.go | 14 +++- product/internal/logic/editbaselogic.go | 13 +-- .../internal/logic/editsusceptiblelogic.go | 11 ++- product/internal/logic/infologic.go | 7 +- product/internal/logic/itemslogic.go | 8 +- product/internal/logic/response.go | 8 -- product/internal/logic/sortlogic.go | 10 ++- product/internal/logic/statuslogic.go | 12 ++- product/internal/logic/verifylogic.go | 2 +- product/internal/logic/verifystatuslogic.go | 13 +-- product/validator/validator.go | 4 +- 24 files changed, 340 insertions(+), 94 deletions(-) create mode 100644 .dockerignore create mode 100644 .gitea/workflows/cd-test.yml create mode 100644 admin/Dockerfile delete mode 100644 deploy/docker-compose.mysql.yml delete mode 100644 deploy/docker-compose.redis.yml create mode 100644 product/Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b73ac10 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +**/.git +**/logs +**/*.log +**/tmp +**/.idea +**/.vscode +**/node_modules +deploy/mysql/data +deploy/rnacos/data diff --git a/.gitea/workflows/cd-test.yml b/.gitea/workflows/cd-test.yml new file mode 100644 index 0000000..83c80b8 --- /dev/null +++ b/.gitea/workflows/cd-test.yml @@ -0,0 +1,33 @@ +name: CD Test + +on: + workflow_run: + workflows: + - CI + types: + - completed + workflow_dispatch: + +jobs: + deploy: + if: ${{ gitea.event_name == 'workflow_dispatch' || gitea.event.workflow_run.conclusion == 'success' }} + runs-on: runner + + defaults: + run: + shell: sh + + steps: + - name: Login Registry + run: | + echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ vars.REGISTRY }} \ + -u "${{ vars.REGISTRY_USERNAME }}" \ + --password-stdin + + - name: Pull and Deploy + working-directory: /data/www/server/deploy + run: | + docker pull ${{ vars.REGISTRY }}/lone/bff:latest + docker pull ${{ vars.REGISTRY }}/lone/product:latest + docker pull ${{ vars.REGISTRY }}/lone/admin:latest + docker compose up -d diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 89058a6..c957c9b 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -7,6 +7,7 @@ on: paths: - "bff/**" - "product/**" + - "admin/**" - "pkg/**" - ".gitea/workflows/ci.yml" workflow_dispatch: @@ -17,6 +18,7 @@ jobs: outputs: bff: ${{ steps.filter.outputs.bff }} product: ${{ steps.filter.outputs.product }} + admin: ${{ steps.filter.outputs.admin }} steps: - name: Checkout uses: https://git.ailuowan.com/deploy/checkout@v4 @@ -28,10 +30,12 @@ jobs: run: | bff=false product=false + admin=false if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then bff=true product=true + admin=true else before="${{ github.event.before }}" if [ -z "$before" ] || [ "$before" = "0000000000000000000000000000000000000000" ]; then @@ -45,11 +49,13 @@ jobs: echo "$changed" | grep -qE '^(bff|pkg)/|^\.gitea/workflows/ci\.yml$' && bff=true || true echo "$changed" | grep -qE '^(product|pkg)/|^\.gitea/workflows/ci\.yml$' && product=true || true + echo "$changed" | grep -qE '^(admin|pkg)/|^\.gitea/workflows/ci\.yml$' && admin=true || true fi echo "bff=$bff" >> "$GITHUB_OUTPUT" echo "product=$product" >> "$GITHUB_OUTPUT" - echo "bff=$bff product=$product" + echo "admin=$admin" >> "$GITHUB_OUTPUT" + echo "bff=$bff product=$product admin=$admin" docker-bff: needs: changes @@ -57,7 +63,6 @@ jobs: runs-on: runner env: NAME: lone/bff - CONTEXT: ./bff steps: - name: Checkout uses: https://git.ailuowan.com/deploy/checkout@v4 @@ -69,8 +74,9 @@ jobs: - name: Docker build run: | docker build \ + -f bff/Dockerfile \ -t ${{ vars.REGISTRY }}/$NAME:latest \ - $CONTEXT + . - name: Docker push run: | @@ -82,7 +88,6 @@ jobs: runs-on: runner env: NAME: lone/product - CONTEXT: ./product steps: - name: Checkout uses: https://git.ailuowan.com/deploy/checkout@v4 @@ -94,8 +99,34 @@ jobs: - name: Docker build run: | docker build \ + -f product/Dockerfile \ -t ${{ vars.REGISTRY }}/$NAME:latest \ - $CONTEXT + . + + - name: Docker push + run: | + docker push ${{ vars.REGISTRY }}/$NAME:latest + + docker-admin: + needs: changes + if: needs.changes.outputs.admin == 'true' + runs-on: runner + env: + NAME: lone/admin + steps: + - name: Checkout + uses: https://git.ailuowan.com/deploy/checkout@v4 + + - name: Login Registry + run: | + echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ vars.REGISTRY }} -u "${{ vars.REGISTRY_USERNAME }}" --password-stdin + + - name: Docker build + run: | + docker build \ + -f admin/Dockerfile \ + -t ${{ vars.REGISTRY }}/$NAME:latest \ + . - name: Docker push run: | diff --git a/.gitignore b/.gitignore index a7fa598..274bfc8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,8 @@ deploy/redis/data *.log **/logs/ -deploy/docker-compose.override.yml +deploy/*.yml + runner.conf Dockerfile.dev */tmp \ No newline at end of file diff --git a/README.md b/README.md index 7b5186f..9120946 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,36 @@ +## 常用命令 + +### 命令 ①:goctl 生成/更新脚手架 + +```bash +goctl -I. -I../pkg/third_party rpc protoc proto/order.proto --go_out=. --go-grpc_out=. --zrpc_out=. +``` + +### 命令 ②:生成服务端 pb / grpc + +```bash +goctl rpc protoc proto/order.proto --proto_path=. --proto_path=../pkg/third_party --go_out=. --go-grpc_out=. --zrpc_out=. +``` + +**什么时候跑:** + +- 只改 **校验规则**(必填/长度/范围等)→ **只跑这条** +- 增删改字段、增删 RPC → 也要跑(服务端描述符要更新) + +### 命令 ③:生成 BFF ProtoSet + +```bash +protoc -I. -I../pkg/third_party --descriptor_set_out=../bff/etc/order.pb --include_imports proto/order.proto +``` + +**什么时候跑:** + +- 增删改 **字段**(BFF gateway 编解码需要) +- 增删 **RPC** +- 改 **google.api.http** 路由 + + + ## 如何加一个新服务 以加 `order` 为例(对标现有 `product`)。 @@ -11,6 +44,8 @@ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest ``` + + ### 1. 创建 RPC 服务(goctl) 在仓库根目录执行: @@ -20,6 +55,8 @@ goctl rpc new order cd order ``` + + ### 2. 将 proto 移到 `proto/` 目录 `goctl rpc new` 默认把 proto 放在服务根目录(如 `order/order.proto`)。统一挪到 `proto/`: @@ -29,6 +66,8 @@ mkdir proto mv order.proto proto/ ``` + + ### 3. Zero 兼容 Nacos 等配置 编辑 `order/internal/config/config.go`: @@ -88,6 +127,8 @@ type LogConf struct { ``` + + ### 4. 配置服务名与监听端口 编辑 `order/etc/order.yaml`: @@ -147,6 +188,8 @@ AppLog: ``` + + ### 5. 构建 mod 编辑 `order/go.mod` 增加本地包 pkg.local @@ -157,6 +200,8 @@ go 1.26 replace pkg.local => ../pkg ``` + + ### 6. 服务注册 编辑 `order/order.go`: @@ -173,6 +218,7 @@ replace pkg.local => ../pkg ``` 增加初始化 + ```go func main() { @@ -308,9 +354,11 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { ``` + + ### 7. 接入 Docker Compose -在 `deploy/docker-compose.override.yml` 增加服务: +在 `deploy/docker-compose.dev.override.yml` 增加服务: ```yaml order: @@ -328,6 +376,8 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { - rnacos ``` + + ### 8. 生成 ProtoSet 给 BFF ```bash @@ -335,6 +385,8 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { protoc --include_imports --proto_path=proto --descriptor_set_out=../bff/etc/order.pb order.proto ``` + + ### 9. 在 BFF 配 Upstream(HTTP 路由写在 proto) 在对应 RPC 上声明 `google.api.http`(需 `import "google/api/annotations.proto";`): @@ -359,6 +411,8 @@ rpc Ping(Request) returns (Response) { - etc/order.pb ``` + + ### 编写业务须知 只改业务逻辑(`internal/logic/`)不必跑 goctl。 @@ -368,16 +422,21 @@ rpc Ping(Request) returns (Response) { --- + + ### 命令 ①:生成服务端 pb / grpc ```bash -goctl rpc protoc proto/admin.proto --proto_path=. --proto_path=../pkg/third_party --go_out=. --go-grpc_out=. --zrpc_out=. +goctl rpc protoc proto/order.proto --proto_path=. --proto_path=../pkg/third_party --go_out=. --go-grpc_out=. --zrpc_out=. ``` **什么时候跑:** + - 只改 **校验规则**(必填/长度/范围等)→ **只跑这条** - 增删改字段、增删 RPC → 也要跑(服务端描述符要更新) + + ### 命令 ②:生成 BFF ProtoSet ```bash @@ -390,10 +449,12 @@ protoc -I. -I../pkg/third_party --descriptor_set_out=../bff/etc/order.pb --inclu - 增删 **RPC** - 改 **google.api.http** 路由 + + ### 命令 ③:goctl 生成/更新脚手架 ```bash -goctl rpc protoc proto/order.proto --go_out=. --go-grpc_out=. --zrpc_out=. +goctl -I. -I../pkg/third_party rpc protoc proto/order.proto --go_out=. --go-grpc_out=. --zrpc_out=. ``` **什么时候跑:** @@ -401,9 +462,11 @@ goctl rpc protoc proto/order.proto --go_out=. --go-grpc_out=. --zrpc_out=. - **新增 RPC**:需要生成 `internal/logic`、更新 `server` / `orderclient` 等 - 注意:可能覆盖已改过的 `order.go` 等,生成后对比合并;也可用手写 logic/server 代替 + + ## Proto 常用校验规则(protovalidate) -文档:https://protovalidate.com/schemas/standard-rules/ +文档:[https://protovalidate.com/schemas/standard-rules/](https://protovalidate.com/schemas/standard-rules/) 依赖:`import "buf/validate/validate.proto";`,服务启动挂 `pkg.local/validate` 拦截器。 ### 必填字符串 @@ -429,6 +492,8 @@ double price = 6 [(buf.validate.field).double = {gte: 0}]; int32 period_validity = 16 [(buf.validate.field).int32 = {gte: 0}]; ``` + + ### 非必填数值(0 表示未传,跳过校验) ```protobuf @@ -454,22 +519,28 @@ uint32 sales_model = 4 [(buf.validate.field) = { }]; ``` + + ### ID 必须大于 0 ```protobuf int64 id = 1 [(buf.validate.field).int64 = {gt: 0}]; ``` + + ### 无规则字段 ```protobuf uint32 number = 20; // 不做 protovalidate ``` + + ### 删除字段编号(避免复用) ```protobuf // reserved 2; ``` -业务条件校验(如「普通商品必须带齐价格」)仍写在 `internal/logic`,不要全塞进 proto。 +业务条件校验(如「普通商品必须带齐价格」)仍写在 `internal/logic`,不要全塞进 proto。 \ No newline at end of file diff --git a/admin/Dockerfile b/admin/Dockerfile new file mode 100644 index 0000000..1c5da96 --- /dev/null +++ b/admin/Dockerfile @@ -0,0 +1,34 @@ +FROM golang:1.26.5-alpine AS builder + +WORKDIR /src + +ENV GOPROXY=https://goproxy.cn,direct \ + CGO_ENABLED=0 \ + GOOS=linux \ + GOARCH=amd64 + +COPY pkg ./pkg +COPY admin/go.mod admin/go.sum ./admin/ + +WORKDIR /src/admin +RUN go mod download + +COPY admin/ ./ +RUN go build -ldflags="-s -w" -o /out/admin . + +FROM alpine:3.22 + +WORKDIR /app + +ENV TZ=Asia/Shanghai + +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/Shanghai" > /etc/timezone + +COPY --from=builder /out/admin . +COPY admin/etc/admin.yaml ./etc/admin.yaml + +EXPOSE 10200 + +CMD ["./admin", "-f", "etc/admin.yaml"] diff --git a/bff/Dockerfile b/bff/Dockerfile index 279a881..f0888f4 100644 --- a/bff/Dockerfile +++ b/bff/Dockerfile @@ -1 +1,34 @@ -FROM golang:1.26.5 AS builder +FROM golang:1.26.5-alpine AS builder + +WORKDIR /src + +ENV GOPROXY=https://goproxy.cn,direct \ + CGO_ENABLED=0 \ + GOOS=linux \ + GOARCH=amd64 + +COPY pkg ./pkg +COPY bff/go.mod bff/go.sum ./bff/ + +WORKDIR /src/bff +RUN go mod download + +COPY bff/ ./ +RUN go build -ldflags="-s -w" -o /out/bff . + +FROM alpine:3.22 + +WORKDIR /app + +ENV TZ=Asia/Shanghai + +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/Shanghai" > /etc/timezone + +COPY --from=builder /out/bff . +COPY bff/etc/ ./etc/ + +EXPOSE 10000 + +CMD ["./bff", "-f", "etc/bff.yaml"] diff --git a/deploy/docker-compose.mysql.yml b/deploy/docker-compose.mysql.yml deleted file mode 100644 index 1f9dd98..0000000 --- a/deploy/docker-compose.mysql.yml +++ /dev/null @@ -1,16 +0,0 @@ -services: - mysql: - image: mysql:8.0 - restart: unless-stopped - environment: - MYSQL_ROOT_PASSWORD: "123123" - ports: - - "3306:3306" - volumes: - - ./mysql/data:/var/lib/mysql - # - ./mysql/init:/docker-entrypoint-initdb.d:ro - -networks: - default: - external: true - name: services-network diff --git a/deploy/docker-compose.redis.yml b/deploy/docker-compose.redis.yml deleted file mode 100644 index 70f799b..0000000 --- a/deploy/docker-compose.redis.yml +++ /dev/null @@ -1,14 +0,0 @@ -services: - redis: - image: redis:7.4-alpine - restart: unless-stopped - ports: - - "6379:6379" - volumes: - - ./redis/data:/data - command: ["redis-server", "--appendonly", "yes"] - -networks: - default: - external: true - name: services-network diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index 7cc430b..84292ed 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -27,4 +27,4 @@ services: networks: default: external: true - name: services-network \ No newline at end of file + name: services-network diff --git a/pkg/utils/status.go b/pkg/utils/status.go index 82e8fa9..d132d68 100644 --- a/pkg/utils/status.go +++ b/pkg/utils/status.go @@ -73,6 +73,17 @@ var ( ErrorAuthority = Status{Code: 10008, Msg: "没有权限"} ErrorNoLoginInfo = Status{Code: 10003, Msg: "没有获取到登录信息"} + // 数据类 + ErrorDataIsExist = Status{Code: 11004, Msg: "数据已存在"} + + // 参数类 + ErrorReasonParams = Status{Code: 10001, Msg: "原因不能为空"} + + // ErrorNotFund 数据类 + ErrorFormatDataError = Status{Code: 11010, Msg: "格式化数据出错"} + + // —————————————————————————————————————————————————————————————————————————————————————— + // 基础类 ErrorExist = NewError(998, "已存在") ErrorOvertime = NewError(997, "请求已超时") @@ -81,7 +92,6 @@ var ( ErrorWecomHttpError = NewError(994, "企业微信请求失败") // 参数类 - ErrorReasonParams = NewError(10001, "原因不能为空") ErrorDefaultError = NewError(10004, "默认地址不能删除") ErrorJwtExpired = NewError(10005, "jwt过期") ErrorMissingProjectId = NewError(10006, "缺少权限项目ID") @@ -95,13 +105,11 @@ var ( // ErrorNotFund 数据类 ErrorNoChange = NewError(11002, "没有改变") - ErrorDataIsExist = NewError(11004, "数据已存在") ErrorRepeatPayment = NewError(11005, "不能重复支付") ErrorNotSufficientFunds = NewError(11006, "余额不足") ErrorSaleLevel = NewError(11007, "有下级销售,不允许修改") ErrorFirstTryErr = NewError(11008, "已购买过首次试用品") ErrorTryError = NewError(11009, "不满足购买条件") - ErrorFormatDataError = NewError(11010, "格式化数据出错") ErrorDataNotExist = NewError(11011, "数据不存在") ErrorBindError = NewError(11012, "设备已绑定,请不要重复绑定") ErrorBindOtherError = NewError(11013, "该设备已绑定其它用户,请不要重复绑定") diff --git a/product/Dockerfile b/product/Dockerfile new file mode 100644 index 0000000..59f0124 --- /dev/null +++ b/product/Dockerfile @@ -0,0 +1,34 @@ +FROM golang:1.26.5-alpine AS builder + +WORKDIR /src + +ENV GOPROXY=https://goproxy.cn,direct \ + CGO_ENABLED=0 \ + GOOS=linux \ + GOARCH=amd64 + +COPY pkg ./pkg +COPY product/go.mod product/go.sum ./product/ + +WORKDIR /src/product +RUN go mod download + +COPY product/ ./ +RUN go build -ldflags="-s -w" -o /out/product . + +FROM alpine:3.22 + +WORKDIR /app + +ENV TZ=Asia/Shanghai + +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/Shanghai" > /etc/timezone + +COPY --from=builder /out/product . +COPY product/etc/product.yaml ./etc/product.yaml + +EXPOSE 10100 + +CMD ["./product", "-f", "etc/product.yaml"] diff --git a/product/internal/logic/createlogic.go b/product/internal/logic/createlogic.go index 8496140..946f817 100644 --- a/product/internal/logic/createlogic.go +++ b/product/internal/logic/createlogic.go @@ -68,13 +68,13 @@ func (l *CreateLogic) Create(in *product.CreateReq) (*product.Response, error) { return failResponse(utils.Fail), nil } if check.Id > 0 { - return failErr(utils.ErrorDataIsExist), nil + return failResponse(utils.ErrorDataIsExist), nil } - // 管理员信息后续从 ctx / metadata 取 - adminId := 0 - adminName := "" - + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } data := dao.ProductCreate{ Name: req.Name, Subhead: req.Subhead, @@ -103,8 +103,8 @@ func (l *CreateLogic) Create(in *product.CreateReq) (*product.Response, error) { IsBuy: uint8(req.IsBuy), PublishTime: publishTime, TryNumber: uint8(req.TryNumber), - AdminName: adminName, - AdminId: adminId, + AdminName: adminInfo.Name, + AdminId: int(adminInfo.ID), } if data.IsIndex == 0 { data.IsIndex = 2 @@ -153,7 +153,7 @@ func (l *CreateLogic) Create(in *product.CreateReq) (*product.Response, error) { return failResponse(utils.Fail), nil } - return okResponse(utils.StructToJson(data.Id)), nil + return okResponse(utils.StringEmpty), nil } func parsePublishTime(s string) (time.Time, error) { diff --git a/product/internal/logic/editapplylogic.go b/product/internal/logic/editapplylogic.go index 515041a..324315c 100644 --- a/product/internal/logic/editapplylogic.go +++ b/product/internal/logic/editapplylogic.go @@ -51,8 +51,11 @@ func (l *EditApplyLogic) EditApply(in *product.EditApplyReq) (*product.Response, return failResponse(utils.ErrorNotFund), nil } - // 管理员信息后续从 ctx / metadata 取 - adminId := 0 + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + adminId := int(adminInfo.ID) info, err := apply.Get(l.ctx, adminId, int(req.Id)) if err != nil { @@ -90,8 +93,11 @@ func (l *EditApplyLogic) EditApplyPass(in *product.EditApplyPassReq) (*product.R return failResponse(utils.ErrorNotFund), nil } - // 管理员信息后续从 ctx / metadata 取 - adminId := 0 + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + adminId := int(adminInfo.ID) if err = apply.Pass(l.ctx, adminId, int(req.Id)); err != nil { if apply.IsAlreadyHandled(err) { diff --git a/product/internal/logic/editbaselogic.go b/product/internal/logic/editbaselogic.go index 2511673..57cf3e0 100644 --- a/product/internal/logic/editbaselogic.go +++ b/product/internal/logic/editbaselogic.go @@ -41,12 +41,15 @@ func (l *EditBaseLogic) EditBase(in *product.EditBaseReq) (*product.Response, er return outResponse(utils.ErrorParams, msg), nil } - // 管理员信息后续从 ctx / metadata 取 - adminId := 0 - adminName := "" + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + adminId := int(adminInfo.ID) + adminName := adminInfo.Name if !apply.CanEdit(l.ctx, adminId, int(req.Id)) { - return failErr(utils.ErrorAuthority), nil + return failResponse(utils.ErrorAuthority), nil } w := modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)}} @@ -68,7 +71,7 @@ func (l *EditBaseLogic) EditBase(in *product.EditBaseReq) (*product.Response, er return failResponse(utils.Fail), nil } if nameCheck.Id > 0 && nameCheck.Id != int(req.Id) { - return failErr(utils.ErrorDataIsExist), nil + return failResponse(utils.ErrorDataIsExist), nil } publishTime := time.Now() diff --git a/product/internal/logic/editsusceptiblelogic.go b/product/internal/logic/editsusceptiblelogic.go index 89273c7..a00d340 100644 --- a/product/internal/logic/editsusceptiblelogic.go +++ b/product/internal/logic/editsusceptiblelogic.go @@ -50,12 +50,15 @@ func (l *EditSusceptibleLogic) EditSusceptible(in *product.EditSusceptibleReq) ( } } - // 管理员信息后续从 ctx / metadata 取 - adminId := 0 - adminName := "" + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + adminId := int(adminInfo.ID) + adminName := adminInfo.Name if !apply.CanEdit(l.ctx, adminId, int(req.Id)) { - return failErr(utils.ErrorAuthority), nil + return failResponse(utils.ErrorAuthority), nil } w := modelbase.Params{ diff --git a/product/internal/logic/infologic.go b/product/internal/logic/infologic.go index 26f1bc4..368c559 100644 --- a/product/internal/logic/infologic.go +++ b/product/internal/logic/infologic.go @@ -51,8 +51,11 @@ func (l *InfoLogic) Info(in *product.InfoReq) (*product.Response, error) { return failResponse(utils.ErrorNotFund), nil } - // 管理员信息后续从 ctx / metadata 取 - adminId := 0 + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + adminId := int(adminInfo.ID) if applyData, err := apply.Get(l.ctx, adminId, info.Id); err == nil { info.Edit = applyData.Status } diff --git a/product/internal/logic/itemslogic.go b/product/internal/logic/itemslogic.go index b374a46..5df948e 100644 --- a/product/internal/logic/itemslogic.go +++ b/product/internal/logic/itemslogic.go @@ -65,9 +65,13 @@ func (l *ItemsLogic) Items(in *product.ItemsReq) (*product.Response, error) { return failResponse(utils.Fail), nil } + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + adminId := int(adminInfo.ID) + items := make([]*product.Item, 0, len(info)) - // 管理员信息后续从 ctx / metadata 取 - adminId := 0 for _, row := range info { if applyData, err := apply.Get(l.ctx, adminId, row.Id); err == nil { row.Edit = applyData.Status diff --git a/product/internal/logic/response.go b/product/internal/logic/response.go index ac9713b..93b0c47 100644 --- a/product/internal/logic/response.go +++ b/product/internal/logic/response.go @@ -27,11 +27,3 @@ func outResponse(status utils.Status, msg string) *product.Response { Msg: msg, } } - -// failErr 兼容仍返回 utils.Error 的旧错误码 -func failErr(err utils.Error) *product.Response { - return &product.Response{ - Code: int32(err.GetCode()), - Msg: err.GetMsg(), - } -} diff --git a/product/internal/logic/sortlogic.go b/product/internal/logic/sortlogic.go index 64c2f20..2dc679c 100644 --- a/product/internal/logic/sortlogic.go +++ b/product/internal/logic/sortlogic.go @@ -52,10 +52,14 @@ func (l *SortLogic) Sort(in *product.SortReq) (*product.Response, error) { return failResponse(utils.ErrorNotFund), nil } + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + info.Sort = uint16(req.Sort) - // 管理员信息后续从 ctx / metadata 取 - info.AdminName = "" - info.AdminId = 0 + info.AdminName = adminInfo.Name + info.AdminId = int(adminInfo.ID) if _, err = m.Edit(w, &info); err != nil { log.Errorf("product sort edit: %v", err) diff --git a/product/internal/logic/statuslogic.go b/product/internal/logic/statuslogic.go index 10a741c..b89fad1 100644 --- a/product/internal/logic/statuslogic.go +++ b/product/internal/logic/statuslogic.go @@ -39,7 +39,7 @@ func (l *StatusLogic) Status(in *product.StatusReq) (*product.Response, error) { } if req.Status == uint32(dao.ProductStatusDisabled) && len(req.Reason) < 1 { - return failErr(utils.ErrorReasonParams), nil + return failResponse(utils.ErrorReasonParams), nil } var info dao.ProductCheckExist @@ -59,12 +59,16 @@ func (l *StatusLogic) Status(in *product.StatusReq) (*product.Response, error) { return failResponse(utils.ErrorNotFund), nil } - // 管理员信息后续从 ctx / metadata 取 + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + update := dao.ProductStatusUpdate{ Status: uint8(req.Status), Reason: req.Reason, - AdminName: "", - AdminId: 0, + AdminName: adminInfo.Name, + AdminId: int(adminInfo.ID), } if _, err = m.Edit(w, &update); err != nil { log.Errorf("product status edit: %v", err) diff --git a/product/internal/logic/verifylogic.go b/product/internal/logic/verifylogic.go index 9d42ce3..13a0540 100644 --- a/product/internal/logic/verifylogic.go +++ b/product/internal/logic/verifylogic.go @@ -108,7 +108,7 @@ func (l *VerifyLogic) Verify(in *product.VerifyReq) (*product.Response, error) { err = json.Unmarshal([]byte(v.Content), &content) if err != nil { log.Errorf("product verify content json: %v", err) - return failErr(utils.ErrorFormatDataError), nil + return failResponse(utils.ErrorFormatDataError), nil } items = append(items, &product.VerifyItem{ Name: row.Name, diff --git a/product/internal/logic/verifystatuslogic.go b/product/internal/logic/verifystatuslogic.go index e15360a..f5aab11 100644 --- a/product/internal/logic/verifystatuslogic.go +++ b/product/internal/logic/verifystatuslogic.go @@ -51,7 +51,7 @@ func (l *VerifyStatusLogic) verifyStatus(expectStatus uint8, in *product.VerifyS } if req.Status == uint32(dao.VerifyActionReject) && len(req.Reason) < 1 { - return failErr(utils.ErrorReasonParams), nil + return failResponse(utils.ErrorReasonParams), nil } var info dao.VerifyStatusRow @@ -70,9 +70,12 @@ func (l *VerifyStatusLogic) verifyStatus(expectStatus uint8, in *product.VerifyS return failResponse(utils.ErrorNotFund), nil } - // 管理员信息后续从 ctx / metadata 取 - adminId := 0 - adminName := "" + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + adminId := int(adminInfo.ID) + adminName := adminInfo.Name nextStatus := dao.VerifyStatusPass reason := req.Reason @@ -163,7 +166,7 @@ func (l *VerifyStatusLogic) verifyStatus(expectStatus uint8, in *product.VerifyS if err != nil { log.Errorf("verify status tx: %v", err) if isJSONError(err) { - return failErr(utils.ErrorFormatDataError), nil + return failResponse(utils.ErrorFormatDataError), nil } return failResponse(utils.Fail), nil } diff --git a/product/validator/validator.go b/product/validator/validator.go index 242b148..8318668 100644 --- a/product/validator/validator.go +++ b/product/validator/validator.go @@ -203,8 +203,8 @@ type ProductEditSusceptibleValidator struct { SalePrice float64 SharePrice float64 AgentPrice float64 - SaleReward string `validate:"max=255"` - NormsNumber uint32 `validate:"required,min=1"` + SaleReward string `validate:"max=255"` + NormsNumber uint32 `validate:"required,min=1"` BoxNumber float64 Type uint32 `validate:"required,oneof=1 2 3"` }