From c71c996afd895f4642c5ef2ae369fa4077ff1f33 Mon Sep 17 00:00:00 2001 From: Leufolium Date: Thu, 1 Feb 2024 09:52:45 +0800 Subject: [PATCH] by Robin at 20240201; --- api/errcode/errcode.go | 8 +++ api/proto/app_config/proto/app_config_api.go | 21 ++++++ api/proto/app_config/proto/app_config_op.go | 63 +++++++++++++++++ .../app_config/proto/not_null_def_api.go | 11 +++ api/proto/app_config/proto/not_null_def_op.go | 19 +++++ api/proto/vas/proto/pay.go | 9 +++ app/mix/controller/app_config_api.go | 26 +++++++ app/mix/controller/app_config_op.go | 38 ++++++++++ app/mix/controller/init.go | 11 +++ app/mix/controller/vas.go | 18 ++++- app/mix/dao/mongo.go | 59 +++++++++++++++- app/mix/service/apiservice.go | 15 ++++ app/mix/service/logic/app_config.go | 65 ++++++++++++++++++ app/mix/service/logic/vas.go | 11 +++ .../service/opservice_business_validation.go | 35 ++++++++++ app/mix/service/service.go | 62 ++++++++++++++++- codecreate/codecreate.go | 8 +-- codecreate/resource/EntityDefine.xlsx | Bin 41355 -> 42466 bytes codecreate/template/controller_center.txt | 8 +-- dbstruct/app_config.go | 11 +++ library/idgenerator/genid.go | 7 ++ 21 files changed, 493 insertions(+), 12 deletions(-) create mode 100644 api/proto/app_config/proto/app_config_api.go create mode 100644 api/proto/app_config/proto/app_config_op.go create mode 100644 api/proto/app_config/proto/not_null_def_api.go create mode 100644 api/proto/app_config/proto/not_null_def_op.go create mode 100644 app/mix/controller/app_config_api.go create mode 100644 app/mix/controller/app_config_op.go create mode 100644 app/mix/service/logic/app_config.go create mode 100644 dbstruct/app_config.go diff --git a/api/errcode/errcode.go b/api/errcode/errcode.go index d39914c5..89a8eb6e 100644 --- a/api/errcode/errcode.go +++ b/api/errcode/errcode.go @@ -140,6 +140,9 @@ var ErrCodeMsgMap = map[ErrCode]string{ ErrCodeDailyStatementSrvFail: "每日报表表服务错误", ErrCodeDailyStatementNotExist: "每日报表表不存在", + + ErrCodeAppConfigSrvFail: "应用配置表服务错误", + ErrCodeAppConfigNotExist: "应用配置表不存在", } const ( @@ -332,6 +335,11 @@ const ( ErrCodeDailyStatementSrvFail ErrCode = -26001 // 每日报表表服务错误 ErrCodeDailyStatementNotExist ErrCode = -26002 // 每日报表表不存在 + // AppConfig: 27xxx + ErrCodeAppConfigSrvOk ErrCode = ErrCodeOk + ErrCodeAppConfigSrvFail ErrCode = -27001 // 应用配置表服务错误 + ErrCodeAppConfigNotExist ErrCode = -27002 // 应用配置表不存在 + // Media: 60xxx ErrCodeMediaSrvOk ErrCode = ErrCodeOk ErrCodeMediaSrvFail ErrCode = -60001 // 媒体服务错误 diff --git a/api/proto/app_config/proto/app_config_api.go b/api/proto/app_config/proto/app_config_api.go new file mode 100644 index 00000000..f0e69484 --- /dev/null +++ b/api/proto/app_config/proto/app_config_api.go @@ -0,0 +1,21 @@ +package proto + +import ( + "service/api/base" + "service/dbstruct" +) + +// op 列表 +type ApiListByKeyReq struct { + base.BaseRequest + ConfigKey string `json:"config_key"` +} + +type ApiListByKeyData struct { + AppConfig *dbstruct.AppConfig `json:"app_config"` +} + +type ApiListByKeyResp struct { + base.BaseResponse + Data *ApiListByKeyData `json:"data"` +} diff --git a/api/proto/app_config/proto/app_config_op.go b/api/proto/app_config/proto/app_config_op.go new file mode 100644 index 00000000..6dd21985 --- /dev/null +++ b/api/proto/app_config/proto/app_config_op.go @@ -0,0 +1,63 @@ +package proto + +import ( + "service/api/base" + "service/dbstruct" +) + +// op 创建 +type OpCreateReq struct { + base.BaseRequest + *dbstruct.AppConfig +} + +type OpCreateData struct { +} + +type OpCreateResp struct { + base.BaseResponse + Data *OpCreateData `json:"data"` +} + +// op 删除 +type OpDeleteReq struct { + base.BaseRequest + Id int64 `json:"id"` +} + +type OpDeleteData struct { +} + +type OpDeleteResp struct { + base.BaseResponse + Data *OpDeleteData `json:"data"` +} + +// op 更新 +type OpUpdateReq struct { + base.BaseRequest + *dbstruct.AppConfig +} + +type OpUpdateData struct { +} + +type OpUpdateResp struct { + base.BaseResponse + Data *OpUpdateData `json:"data"` +} + +// op 列表 +type OpListByKeyReq struct { + base.BaseRequest + ConfigKey string `json:"config_key"` +} + +type OpListByKeyData struct { + AppConfig *dbstruct.AppConfig `json:"app_config"` +} + +type OpListByKeyResp struct { + base.BaseResponse + Data *OpListByKeyData `json:"data"` +} diff --git a/api/proto/app_config/proto/not_null_def_api.go b/api/proto/app_config/proto/not_null_def_api.go new file mode 100644 index 00000000..f1e0b29f --- /dev/null +++ b/api/proto/app_config/proto/not_null_def_api.go @@ -0,0 +1,11 @@ +package proto + +import "service/library/validator" + +func (p *ApiListByKeyReq) ProvideNotNullValue() (params []*validator.JsonParam) { + params = make([]*validator.JsonParam, 0) + + params = append(params, validator.NewStringParam("请输入待查询配置的key!", p.ConfigKey)) + + return +} diff --git a/api/proto/app_config/proto/not_null_def_op.go b/api/proto/app_config/proto/not_null_def_op.go new file mode 100644 index 00000000..31e911eb --- /dev/null +++ b/api/proto/app_config/proto/not_null_def_op.go @@ -0,0 +1,19 @@ +package proto + +import "service/library/validator" + +func (p *OpUpdateReq) ProvideNotNullValue() (params []*validator.JsonParam) { + params = make([]*validator.JsonParam, 0) + + params = append(params, validator.NewStringPtrParam("请输入待更新配置的key!", p.ConfigKey)) + + return +} + +func (p *OpListByKeyReq) ProvideNotNullValue() (params []*validator.JsonParam) { + params = make([]*validator.JsonParam, 0) + + params = append(params, validator.NewStringParam("请输入待查询配置的key!", p.ConfigKey)) + + return +} diff --git a/api/proto/vas/proto/pay.go b/api/proto/vas/proto/pay.go index 469ed9ba..e90359ba 100644 --- a/api/proto/vas/proto/pay.go +++ b/api/proto/vas/proto/pay.go @@ -14,6 +14,15 @@ type GetCoinsProductListData struct { ListAlipayH5 []*dbstruct.Product `json:"list_alipay_h5"` } +// 用户获取会员商品列表 +type GetMembershipProductListReq struct { + base.BaseRequest +} + +type GetMembershipProductListData struct { + List []*dbstruct.Product `json:"list"` +} + // 创建订单 const ( PayTypeOp = "op" // op直冲 diff --git a/app/mix/controller/app_config_api.go b/app/mix/controller/app_config_api.go new file mode 100644 index 00000000..b1ff30fd --- /dev/null +++ b/app/mix/controller/app_config_api.go @@ -0,0 +1,26 @@ +package controller + +import ( + "service/api/errcode" + appconfigproto "service/api/proto/app_config/proto" + "service/app/mix/service" + "service/bizcommon/util" + "service/library/logger" + + "github.com/gin-gonic/gin" +) + +func ApiGetAppConfigListByKey(ctx *gin.Context) { + req := ctx.MustGet("client_req").(*appconfigproto.ApiListByKeyReq) + appconfig, ec := service.DefaultService.ApiGetAppConfigListByKey(ctx, req) + if ec != errcode.ErrCodeAppConfigSrvOk { + logger.Error("ApiGetAppConfigListByKey fail, req: %v, ec: %v", util.ToJson(req), ec) + ReplyErrCodeMsg(ctx, ec) + return + } + + data := &appconfigproto.ApiListByKeyData{ + AppConfig: appconfig, + } + ReplyOk(ctx, data) +} diff --git a/app/mix/controller/app_config_op.go b/app/mix/controller/app_config_op.go new file mode 100644 index 00000000..4397cdf6 --- /dev/null +++ b/app/mix/controller/app_config_op.go @@ -0,0 +1,38 @@ +package controller + +import ( + "service/api/errcode" + appconfigproto "service/api/proto/app_config/proto" + "service/app/mix/service" + "service/bizcommon/util" + "service/library/logger" + + "github.com/gin-gonic/gin" +) + +func OpUpdateAppConfig(ctx *gin.Context) { + req := ctx.MustGet("client_req").(*appconfigproto.OpUpdateReq) + ec := service.DefaultService.OpUpdateAppConfig(ctx, req) + if ec != errcode.ErrCodeAppConfigSrvOk { + logger.Error("OpUpdateAppConfig fail, req: %v, ec: %v", util.ToJson(req), ec) + ReplyErrCodeMsg(ctx, ec) + return + } + + ReplyOk(ctx, nil) +} + +func OpGetAppConfigListByKey(ctx *gin.Context) { + req := ctx.MustGet("client_req").(*appconfigproto.OpListByKeyReq) + appconfig, ec := service.DefaultService.OpGetAppConfigListByKey(ctx, req) + if ec != errcode.ErrCodeAppConfigSrvOk { + logger.Error("OpGetAppConfigListByKey fail, req: %v, ec: %v", util.ToJson(req), ec) + ReplyErrCodeMsg(ctx, ec) + return + } + + data := &appconfigproto.OpListByKeyData{ + AppConfig: appconfig, + } + ReplyOk(ctx, data) +} diff --git a/app/mix/controller/init.go b/app/mix/controller/init.go index d979d6f7..eb30450e 100644 --- a/app/mix/controller/init.go +++ b/app/mix/controller/init.go @@ -20,6 +20,7 @@ import ( "service/api/errcode" accountproto "service/api/proto/account/proto" accountrelationproto "service/api/proto/accountrelation/proto" + appconfigproto "service/api/proto/app_config/proto" callhistoryproto "service/api/proto/callhistory/proto" contact_customer_serviceproto "service/api/proto/contact_customer_service/proto" contact_customer_service_sessionproto "service/api/proto/contact_customer_service_session/proto" @@ -167,6 +168,10 @@ func Init(r *gin.Engine) { apiContactCustomerServiceSessionGroup.POST("create", middleware.JSONParamValidator(contact_customer_service_sessionproto.ApiCreateReq{}), middleware.JwtAuthenticator(), ApiCreateContactCustomerServiceSession) apiContactCustomerServiceSessionGroup.POST("list_by_mid", middleware.JSONParamValidator(contact_customer_service_sessionproto.ApiListByMidReq{}), middleware.JwtAuthenticator(), ApiGetContactCustomerServiceSessionListByMid) + // 应用配置表 + apiAppConfigGroup := r.Group("/api/app_config", PrepareToC()) + apiAppConfigGroup.POST("list_by_key", middleware.JSONParamValidator(appconfigproto.ApiListByKeyReq{}), middleware.JwtAuthenticator(), ApiGetAppConfigListByKey) + // 主播标签 apiStreamerTagGroup := r.Group("/api/streamer_tag", PrepareToC()) apiStreamerTagGroup.POST("list", middleware.JSONParamValidator(base.BaseRequest{}), middleware.JwtAuthenticator(), OpGetStreamerTagList) @@ -200,6 +205,7 @@ func Init(r *gin.Engine) { // 支付相关 vasPayGroup := r.Group("/api/vas", PrepareToC()) vasPayGroup.POST("get_coins_product_list", middleware.JSONParamValidator(vasproto.GetCoinsProductListReq{}), GetCoinsProductList) + vasPayGroup.POST("get_membership_product_list", middleware.JSONParamValidator(vasproto.GetMembershipProductListReq{}), GetMembershipProductList) vasPayGroup.POST("create_order", middleware.JSONParamValidator(vasproto.CreateOrderReq{}), middleware.JwtAuthenticator(), CreateOrder) vasPayGroup.POST("one_step_unlock", middleware.JSONParamValidator(vasproto.OneStepUnlockContactReq{}), OneStepUnlock) vasPayGroup.POST("consumer_fill_contact", middleware.JSONParamValidator(vasproto.ConsumerFillContactReq{}), ConsumerFillContact) @@ -386,6 +392,11 @@ func Init(r *gin.Engine) { opDailyStatementGroup := r.Group("/op/daily_statement", PrepareOp()) opDailyStatementGroup.POST("list", middleware.JSONParamValidator(daily_statementproto.OpListReq{}), middleware.JwtAuthenticator(), OpGetDailyStatementList) + // 应用配置表 + opAppConfigGroup := r.Group("/op/app_config", PrepareOp()) + opAppConfigGroup.POST("update", middleware.JSONParamValidator(appconfigproto.OpUpdateReq{}), middleware.JwtAuthenticator(), OpUpdateAppConfig) + opAppConfigGroup.POST("list_by_key", middleware.JSONParamValidator(appconfigproto.OpListByKeyReq{}), middleware.JwtAuthenticator(), OpGetAppConfigListByKey) + // 账号相关 //accountGroup := r.Group("/account") diff --git a/app/mix/controller/vas.go b/app/mix/controller/vas.go index 123eb7df..777f469c 100644 --- a/app/mix/controller/vas.go +++ b/app/mix/controller/vas.go @@ -1,7 +1,6 @@ package controller import ( - "github.com/gin-gonic/gin" "service/api/errcode" vasproto "service/api/proto/vas/proto" "service/app/mix/service" @@ -9,6 +8,8 @@ import ( "service/bizcommon/util" "service/library/logger" "time" + + "github.com/gin-gonic/gin" ) // 获取充值商品 @@ -26,6 +27,21 @@ func GetCoinsProductList(ctx *gin.Context) { ReplyOk(ctx, data) } +// 获取会员商品 +func GetMembershipProductList(ctx *gin.Context) { + req := ctx.MustGet("client_req").(*vasproto.GetMembershipProductListReq) + if req.Channel == "h5" { + req.DevType = common.DeviceTypeH5 + } + data, ec := service.DefaultService.GetMembershipProductList(ctx, req) + if ec != errcode.ErrCodeVasSrvOk { + logger.Error("GetMembershipProductList fail, req: %v, ec: %v", util.ToJson(req), ec) + ReplyErrCodeMsg(ctx, ec) + return + } + ReplyOk(ctx, data) +} + // 充值 创建订单 func CreateOrder(ctx *gin.Context) { defer logger.Recover() diff --git a/app/mix/dao/mongo.go b/app/mix/dao/mongo.go index 79222212..ecb14732 100644 --- a/app/mix/dao/mongo.go +++ b/app/mix/dao/mongo.go @@ -15,6 +15,7 @@ import ( accountproto "service/api/proto/account/proto" accountrelationproto "service/api/proto/accountrelation/proto" + appconfigproto "service/api/proto/app_config/proto" callhistoryproto "service/api/proto/callhistory/proto" contact_customer_service_proto "service/api/proto/contact_customer_service/proto" contact_customer_service_sessionproto "service/api/proto/contact_customer_service_session/proto" @@ -144,6 +145,9 @@ const ( DBDailyStatement = "daily_statement" COLDailyStatement = "daily_statement" + + DBAppConfig = "app_config" + COLAppConfig = "app_config" ) // 商品表 @@ -325,16 +329,21 @@ func (m *Mongo) getColTextAuditTask() *qmgo.Collection { return m.clientMix.Database(DBTextAudit).Collection(COLTextAuditTask) } -// 联系客服对话表表 +// 联系客服对话表 func (m *Mongo) getColContactCustomerServiceSession() *qmgo.Collection { return m.clientMix.Database(DBContactCustomerServiceSession).Collection(COLContactCustomerServiceSession) } -// 每日报表表表 +// 每日报表表 func (m *Mongo) getColDailyStatement() *qmgo.Collection { return m.clientMix.Database(DBDailyStatement).Collection(COLDailyStatement) } +// 应用配置表 +func (m *Mongo) getColAppConfig() *qmgo.Collection { + return m.clientMix.Database(DBAppConfig).Collection(COLAppConfig) +} + // 商品相关 func (m *Mongo) CreateProduct(ctx *gin.Context, product *dbstruct.Product) error { col := m.getColProduct() @@ -2860,3 +2869,49 @@ func (m *Mongo) GetDailyStatementList(ctx *gin.Context, req *daily_statementprot } return list, err } + +// 应用配置表相关 +func (m *Mongo) CreateAppConfig(ctx *gin.Context, appconfig *dbstruct.AppConfig) error { + col := m.getColAppConfig() + _, err := col.InsertOne(ctx, appconfig) + return err +} + +func (m *Mongo) UpdateAppConfig(ctx *gin.Context, appconfig *dbstruct.AppConfig) error { + col := m.getColAppConfig() + set := util.EntityToM(appconfig) + set["ut"] = time.Now().Unix() + up := qmgo.M{ + "$set": set, + } + filter := qmgo.M{ + "config_key": util.DerefString(appconfig.ConfigKey), + } + err := col.UpdateOne(ctx, filter, up) + return err +} + +func (m *Mongo) DeleteAppConfig(ctx *gin.Context, id int64) error { + col := m.getColAppConfig() + update := qmgo.M{ + "$set": qmgo.M{ + "del_flag": 1, + }, + } + err := col.UpdateId(ctx, id, update) + return err +} + +func (m *Mongo) GetAppConfigListByKey(ctx *gin.Context, req *appconfigproto.OpListByKeyReq) (*dbstruct.AppConfig, error) { + appconfig := &dbstruct.AppConfig{} + col := m.getColAppConfig() + query := qmgo.M{ + "del_flag": 0, + } + err := col.Find(ctx, query).One(appconfig) + if err == qmgo.ErrNoSuchDocuments { + err = nil + return nil, err + } + return appconfig, err +} diff --git a/app/mix/service/apiservice.go b/app/mix/service/apiservice.go index 5c3b987d..0e58bad4 100644 --- a/app/mix/service/apiservice.go +++ b/app/mix/service/apiservice.go @@ -6,6 +6,7 @@ import ( "service/api/errcode" accountproto "service/api/proto/account/proto" accountrelationproto "service/api/proto/accountrelation/proto" + appconfigproto "service/api/proto/app_config/proto" contact_customer_service_proto "service/api/proto/contact_customer_service/proto" contact_customer_service_sessionproto "service/api/proto/contact_customer_service_session/proto" feedbackproto "service/api/proto/feedback/proto" @@ -1804,3 +1805,17 @@ func (s *Service) ApiGetThumbsUpList(ctx *gin.Context, req *thumbsupproto.ApiLis } return } + +func (s *Service) ApiGetAppConfigListByKey(ctx *gin.Context, req *appconfigproto.ApiListByKeyReq) (appconfig *dbstruct.AppConfig, ec errcode.ErrCode) { + ec = errcode.ErrCodeAppConfigSrvOk + + appconfig, err := _DefaultAppConfig.OpListByKey(ctx, &appconfigproto.OpListByKeyReq{ + ConfigKey: req.ConfigKey, + }) + if err != nil { + logger.Error("OpGetAppConfigListByKey fail, req: %v, err: %v", util.ToJson(req), err) + ec = errcode.ErrCodeAppConfigSrvFail + return + } + return +} diff --git a/app/mix/service/logic/app_config.go b/app/mix/service/logic/app_config.go new file mode 100644 index 00000000..8ecf1fe4 --- /dev/null +++ b/app/mix/service/logic/app_config.go @@ -0,0 +1,65 @@ +package logic + +import ( + "service/api/consts" + app_configproto "service/api/proto/app_config/proto" + "service/app/mix/dao" + "service/dbstruct" + "service/library/idgenerator" + "service/library/logger" + "time" + + "github.com/gin-gonic/gin" + goproto "google.golang.org/protobuf/proto" +) + +type AppConfig struct { + store *dao.Store +} + +func NewAppConfig(store *dao.Store) (a *AppConfig) { + a = &AppConfig{ + store: store, + } + return +} + +func (p *AppConfig) OpCreate(ctx *gin.Context, req *app_configproto.OpCreateReq) error { + req.AppConfig.Id = goproto.Int64(idgenerator.GenAppConfigId()) + req.AppConfig.Ct = goproto.Int64(time.Now().Unix()) + req.AppConfig.Ut = goproto.Int64(time.Now().Unix()) + req.AppConfig.DelFlag = goproto.Int64(consts.Exist) + err := p.store.CreateAppConfig(ctx, req.AppConfig) + if err != nil { + logger.Error("CreateAppConfig fail, err: %v", err) + return err + } + return nil +} + +func (p *AppConfig) OpUpdate(ctx *gin.Context, req *app_configproto.OpUpdateReq) error { + err := p.store.UpdateAppConfig(ctx, req.AppConfig) + if err != nil { + logger.Error("UpdateAppConfig fail, err: %v", err) + return err + } + return nil +} + +func (p *AppConfig) OpDelete(ctx *gin.Context, id int64) error { + err := p.store.DeleteAppConfig(ctx, id) + if err != nil { + logger.Error("DeleteAppConfig fail, err: %v", err) + return err + } + return nil +} + +func (p *AppConfig) OpListByKey(ctx *gin.Context, req *app_configproto.OpListByKeyReq) (*dbstruct.AppConfig, error) { + appconfig, err := p.store.GetAppConfigListByKey(ctx, req) + if err != nil { + logger.Error("GetAppConfigListByKey fail, err: %v", err) + return nil, err + } + return appconfig, nil +} diff --git a/app/mix/service/logic/vas.go b/app/mix/service/logic/vas.go index c4d2470c..e53827fc 100644 --- a/app/mix/service/logic/vas.go +++ b/app/mix/service/logic/vas.go @@ -76,6 +76,17 @@ func (v *Vas) GetCoinsProductList(ctx *gin.Context, req *vasproto.GetCoinsProduc return } +func (v *Vas) GetMembershipProductList(ctx *gin.Context, req *vasproto.GetMembershipProductListReq) (list []*dbstruct.Product, err error) { + // 获取所有会员商品 + list, err = v.store.GetProductByDtType(ctx, req.DevType, dbstruct.ProductTypeMoneyMembership) + if err != nil { + logger.Error("GetProductByDtType fail, mid: %v, dt: %v", req.Mid, req.DevType) + return + } + logger.Info("GetProductByDtType, len: %v", len(list)) + return +} + func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data *vasproto.CreateOrderData, err error) { var ( productId = req.ProductId diff --git a/app/mix/service/opservice_business_validation.go b/app/mix/service/opservice_business_validation.go index b0c5ba85..a6f98473 100644 --- a/app/mix/service/opservice_business_validation.go +++ b/app/mix/service/opservice_business_validation.go @@ -4,6 +4,7 @@ import ( "service/api/errcode" accountproto "service/api/proto/account/proto" accountrelationproto "service/api/proto/accountrelation/proto" + appconfigproto "service/api/proto/app_config/proto" callhistoryproto "service/api/proto/callhistory/proto" contact_customer_service_proto "service/api/proto/contact_customer_service/proto" contact_customer_service_sessionproto "service/api/proto/contact_customer_service_session/proto" @@ -1231,3 +1232,37 @@ func (s *Service) OpGetThumbsUpListBusinessValidate(ctx *gin.Context, req *thumb } return } + +func (s *Service) OpUpdateAppConfigBusinessValidate(ctx *gin.Context, req *appconfigproto.OpUpdateReq) (ec errcode.ErrCode) { + ec = errcode.ErrCodeAppConfigSrvOk + + // 1.业务校验 + result := businessvalidator.NewAuthBusinessValidator(ctx, req). + QueryAccount(_DefaultAccount.OpListByMid). + EnsureAccountExist(). + EnsureIsOpRole(). + Validate(). + Collect() + if ec = result[0].(errcode.ErrCode); ec != errcode.ErrCodeOk { + logger.Error("OpUpdateAppConfig business validation failed") + return + } + return +} + +func (s *Service) OpGetAppConfigListByKeyBusinessValidate(ctx *gin.Context, req *appconfigproto.OpListByKeyReq) (ec errcode.ErrCode) { + ec = errcode.ErrCodeAppConfigSrvOk + + // 1.业务校验 + result := businessvalidator.NewAuthBusinessValidator(ctx, req). + QueryAccount(_DefaultAccount.OpListByMid). + EnsureAccountExist(). + EnsureIsOpRole(). + Validate(). + Collect() + if ec = result[0].(errcode.ErrCode); ec != errcode.ErrCodeOk { + logger.Error("OpGetAppConfigListByKey business validation failed") + return + } + return +} diff --git a/app/mix/service/service.go b/app/mix/service/service.go index 0259a0cc..b8fbbf27 100644 --- a/app/mix/service/service.go +++ b/app/mix/service/service.go @@ -9,6 +9,7 @@ import ( "service/api/errs" accountproto "service/api/proto/account/proto" accountrelationproto "service/api/proto/accountrelation/proto" + appconfigproto "service/api/proto/app_config/proto" bannerproto "service/api/proto/banner/proto" callhistoryproto "service/api/proto/callhistory/proto" catalogproto "service/api/proto/catalog/proto" @@ -94,6 +95,7 @@ var ( _DefaultTextAuditTask *logic.TextAuditTask _DefaultContactCustomerServiceSession *logic.ContactCustomerServiceSession _DefaultDailyStatement *logic.DailyStatement + _DefaultAppConfig *logic.AppConfig ) type Service struct { @@ -160,6 +162,7 @@ func (s *Service) Init(c any) (err error) { _DefaultVas = logic.NewVas(store, _DefaultStreamer, _DefaultAccount) _DefaultContactCustomerServiceSession = logic.NewContactCustomerServiceSession(store) _DefaultDailyStatement = logic.NewDailyStatement(store) + _DefaultAppConfig = logic.NewAppConfig(store) return } @@ -933,7 +936,7 @@ func (s *Service) GetCoinsProductList(ctx *gin.Context, req *vasproto.GetCoinsPr ok := false listH5alipay, err := _DefaultVas.GetCoinsProductList(ctx, req) if err != nil { - logger.Error("CreateOrder fail, err: %v", err) + logger.Error("GetCoinsProductList fail, err: %v", err) ec, ok = errs.ErrEcMap[err] if ok { return @@ -947,6 +950,25 @@ func (s *Service) GetCoinsProductList(ctx *gin.Context, req *vasproto.GetCoinsPr return } +func (s *Service) GetMembershipProductList(ctx *gin.Context, req *vasproto.GetMembershipProductListReq) (data *vasproto.GetMembershipProductListData, ec errcode.ErrCode) { + ec = errcode.ErrCodeVasSrvOk + ok := false + list, err := _DefaultVas.GetMembershipProductList(ctx, req) + if err != nil { + logger.Error("GetMembershipProductList fail, err: %v", err) + ec, ok = errs.ErrEcMap[err] + if ok { + return + } + ec = errcode.ErrCodeVasSrvFail + return + } + data = &vasproto.GetMembershipProductListData{ + List: list, + } + return +} + func (s *Service) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data *vasproto.CreateOrderData, ec errcode.ErrCode) { switch req.ProductId { case dbstruct.ProductIdMembership: @@ -2567,3 +2589,41 @@ func (s *Service) OpGetDailyStatementList(ctx *gin.Context, req *daily_statement } return } + +// AppConfig +func (s *Service) OpUpdateAppConfig(ctx *gin.Context, req *appconfigproto.OpUpdateReq) (ec errcode.ErrCode) { + ec = errcode.ErrCodeAppConfigSrvOk + + if ec = s.OpUpdateAppConfigBusinessValidate(ctx, req); ec != errcode.ErrCodeAppConfigSrvOk { + return + } + + err := _DefaultAppConfig.OpUpdate(ctx, req) + if err == qmgo.ErrNoSuchDocuments { + ec = errcode.ErrCodeAppConfigNotExist + err = nil + return + } + if err != nil { + logger.Error("OpUpdate fail, req: %v, err: %v", util.ToJson(req), err) + ec = errcode.ErrCodeAppConfigSrvFail + return + } + return +} + +func (s *Service) OpGetAppConfigListByKey(ctx *gin.Context, req *appconfigproto.OpListByKeyReq) (appconfig *dbstruct.AppConfig, ec errcode.ErrCode) { + ec = errcode.ErrCodeAppConfigSrvOk + + if ec = s.OpGetAppConfigListByKeyBusinessValidate(ctx, req); ec != errcode.ErrCodeAppConfigSrvOk { + return + } + + appconfig, err := _DefaultAppConfig.OpListByKey(ctx, req) + if err != nil { + logger.Error("OpGetAppConfigListByKey fail, req: %v, err: %v", util.ToJson(req), err) + ec = errcode.ErrCodeAppConfigSrvFail + return + } + return +} diff --git a/codecreate/codecreate.go b/codecreate/codecreate.go index 77a1b3d9..5e648fa5 100644 --- a/codecreate/codecreate.go +++ b/codecreate/codecreate.go @@ -9,10 +9,10 @@ import ( func main() { genSource := &generator.GenSource{ - EntityName: "DailyStatement", - ModuleName: "daily_statement", - EntityCNName: "每日报表表", - ErrCodeSeq: "26", + EntityName: "AppConfig", + ModuleName: "app_config", + EntityCNName: "应用配置表", + ErrCodeSeq: "27", } generator.CreateFileDirectory(genSource) diff --git a/codecreate/resource/EntityDefine.xlsx b/codecreate/resource/EntityDefine.xlsx index 9be680f00c6fa2ce756db45a6253e441b2d2896d..84bbb1cab9c6f9d67d930700b66fa2e101a83fa3 100644 GIT binary patch delta 8296 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 Cs!8Mk delta 7321 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