实现商户注册、管理员审核商户申请接口

This commit is contained in:
2025-06-04 15:10:56 +08:00
parent 00b889cfcc
commit caf3d42fe5
63 changed files with 1195 additions and 294 deletions

View File

@ -13,5 +13,7 @@ import (
type IAuthV1 interface {
AdminLogin(ctx context.Context, req *v1.AdminLoginReq) (res *v1.AdminLoginRes, err error)
MerchantLogin(ctx context.Context, req *v1.MerchantLoginReq) (res *v1.MerchantLoginRes, err error)
MerchantCode(ctx context.Context, req *v1.MerchantCodeReq) (res *v1.MerchantCodeRes, err error)
MerchantRegister(ctx context.Context, req *v1.MerchantRegisterReq) (res *v1.MerchantRegisterRes, err error)
StoreLogin(ctx context.Context, req *v1.StoreLoginReq) (res *v1.StoreLoginRes, err error)
}

View File

@ -7,6 +7,7 @@ type AdminLoginReq struct {
Username string `json:"username" v:"required" dc:"用户名"`
Password string `json:"password" v:"required" dc:"密码"`
}
type AdminLoginRes struct {
g.Meta `mime:"application/json"`
Token string `json:"token"`
@ -14,16 +15,37 @@ type AdminLoginRes struct {
type MerchantLoginReq struct {
g.Meta `path:"/merchant/login" method:"post" tags:"Merchant" summary:"(商户管理员)商户登录"`
Usernaem string `json:"username" v:"required" dc:"用户名"`
Username string `json:"username" dc:"用户名"`
Phone string `json:"phone" v:"regex:^1[3-9]\\d{9}$" dc:"手机号"`
Code string `json:"code" dc:"验证码"`
Password string `json:"password" v:"required" dc:"密码"`
}
type MerchantLoginRes struct {
g.Meta `mime:"application/json"`
Token string `json:"token"`
}
type MerchantRegisterReq struct {
type MerchantCodeReq struct {
g.Meta `path:"/merchant/code" method:"get" tags:"Merchant" summary:"(商户管理员)商户获取短信验证码"`
Phone string `json:"phone" v:"required" dc:"手机号"`
}
type MerchantCodeRes struct{}
type MerchantRegisterReq struct {
g.Meta `path:"/merchant/register" method:"post" tags:"Merchant" summary:"(商户管理员)商户注册"`
Username string `json:"username" v:"required" dc:"用户名"`
Phone string `json:"phone" v:"required|regex:^1[3-9]\\d{9}$" dc:"手机号"`
Code string `json:"code" v:"required" dc:"验证码"`
Password string `json:"password" v:"required|length:6,20" dc:"密码6-20位"`
Password2 string `json:"password2" v:"required|same:password" dc:"确认密码"`
ApplicationReason string `json:"applicationReason" v:"required|length:5,200" dc:"申请理由5~200字"`
}
type MerchantRegisterRes struct {
Success bool `json:"success" dc:"是否成功"`
Msg string `json:"msg" dc:"提示信息"`
}
type StoreLoginReq struct {
@ -31,6 +53,7 @@ type StoreLoginReq struct {
Username string `json:"username" v:"required" dc:"用户名"`
Password string `json:"password" v:"required" dc:"密码"`
}
type StoreLoginRes struct {
g.Meta `mime:"application/json"`
Token string `json:"token"`

View File

@ -2,15 +2,17 @@
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package roleMenu
package merchant
import (
"context"
"server/api/roleMenu/v1"
"server/api/merchant/v1"
)
type IRoleMenuV1 interface {
type IMerchantV1 interface {
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
SaveRoleMenu(ctx context.Context, req *v1.SaveRoleMenuReq) (res *v1.SaveRoleMenuRes, err error)
Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error)
Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error)
Audit(ctx context.Context, req *v1.AuditReq) (res *v1.AuditRes, err error)
}

View File

@ -0,0 +1,39 @@
package v1
import "github.com/gogf/gf/v2/frame/g"
type ListReq struct {
g.Meta `path:"/merchant" method:"get" tags:"Merchant" summary:"(系统管理员)获取商户列表"`
Page int `json:"page" dc:"页数"`
Size int `json:"size" dc:"每页数量"`
Status int `json:"status" dc:"状态1=启用2=禁用"`
AuditStatus int `json:"auditStatus" dc:"审核状态0=待审核1=审核通过2=审核拒绝"`
}
type ListRes struct {
List interface{} `json:"list" dc:"商户列表"`
Total int `json:"total" dc:"总数"`
}
type CreateReq struct {
g.Meta `path:"/merchant" method:"post" tags:"Merchant" summary:"(系统管理员)创建商户"`
}
type CreateRes struct {
Id int64 `json:"id" dc:"商户ID"`
}
type UpdateReq struct {
g.Meta `path:"/merchant" method:"put" tags:"Merchant" summary:"(系统管理员、商户管理员)更新商户"`
}
type UpdateRes struct {
Success bool `json:"success" dc:"是否成功"`
}
type AuditReq struct {
g.Meta `path:"/merchant/audit" method:"post" tags:"Merchant" summary:"(系统管理员)商户审核"`
Id int64 `json:"id" v:"required" dc:"商户ID"`
AuditStatus int `json:"auditStatus" v:"required" dc:"审核状态1=审核通过2=审核拒绝" `
AuditRemark string `json:"auditRemark" dc:"审核备注"`
RejectReason string `json:"rejectReason" dc:"拒绝原因"`
}
type AuditRes struct {
}

View File

@ -0,0 +1,15 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package merchantAdmin
import (
"context"
"server/api/merchantAdmin/v1"
)
type IMerchantAdminV1 interface {
MerchantAdminInfo(ctx context.Context, req *v1.MerchantAdminInfoReq) (res *v1.MerchantAdminInfoRes, err error)
}

View File

@ -0,0 +1,11 @@
package v1
import (
"github.com/gogf/gf/v2/frame/g"
)
type MerchantAdminInfoReq struct {
g.Meta `path:"/merchant/info" method:"get" tags:"MerchantAdmin" summary:"(商户管理员)获取商户管理员信息"`
}
type MerchantAdminInfoRes struct {
}

View File

@ -1,27 +0,0 @@
package v1
import (
"github.com/gogf/gf/v2/frame/g"
)
// ListReq 角色菜单列表请求
type ListReq struct {
g.Meta `path:"/role-menu" method:"get" tags:"角色菜单" summary:"获取角色菜单列表"`
RoleId int64 `json:"roleId" v:"required#角色ID不能为空" dc:"角色ID"`
}
// ListRes 角色菜单列表响应
type ListRes struct {
List interface{} `json:"list" dc:"角色菜单列表"`
Total int `json:"total" dc:"总条数"`
}
type SaveRoleMenuReq struct {
g.Meta `path:"/role-menu" method:"post" tags:"角色菜单" summary:"保存角色菜单"`
RoleId int `json:"roleId" v:"required#角色ID不能为空" dc:"角色ID"`
MenuIds []int `json:"menuIds" v:"required#菜单ID列表不能为空" dc:"菜单ID列表"`
}
type SaveRoleMenuRes struct {
Success bool `json:"success" dc:"是否成功"`
}

37
api/store/v1/store.go Normal file
View File

@ -0,0 +1,37 @@
package v1
import (
"github.com/gogf/gf/v2/frame/g"
)
type ListReq struct {
g.Meta `path:"/store" method:"get" tags:"Store" summary:"(系统管理员、商户管理员)获取门店列表"`
Page int `json:"page" dc:"页数"`
Size int `json:"size" dc:"每页数量"`
MerchantId int `json:"merchantId" dc:"商户ID"`
}
type ListRes struct {
List interface{} `json:"list" dc:"商户列表"`
Total int `json:"total" dc:"总数"`
}
type CreateReq struct {
g.Meta `path:"/store" method:"post" tags:"Store" summary:"(商户管理员)创建门店"`
Name string `json:"name" v:"required" dc:"门店名称"`
ContactName string `json:"contactName" v:"required" dc:"联系人"`
ContactPhone string `json:"contactPhone" v:"required" dc:"联系人电话"`
}
type CreateRes struct {
Id int64 `json:"id" dc:"门店ID"`
}
type UpdateReq struct {
g.Meta `path:"/store" method:"put" tags:"Store" summary:"(商户管理员)更新门店"`
Id int64 `json:"id" v:"required" dc:"门店ID"`
Name string `json:"name" v:"required" dc:"门店名称"`
Address string `json:"address" v:"required" dc:"门店地址"`
ContactName string `json:"contactName" v:"required" dc:"联系人"`
ContactPhone string `json:"contactPhone" v:"required" dc:"联系人电话"`
}
type UpdateRes struct {
Success bool `json:"success" dc:"是否成功"`
}

3
go.mod
View File

@ -3,6 +3,7 @@ module server
go 1.24.2
require (
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
github.com/casbin/casbin/v2 v2.105.0
github.com/go-resty/resty/v2 v2.16.5
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0
@ -12,7 +13,6 @@ require (
github.com/google/uuid v1.6.0
github.com/hailaz/gf-casbin-adapter/v2 v2.8.1
golang.org/x/crypto v0.38.0
golang.org/x/sync v0.14.0
)
require (
@ -44,5 +44,6 @@ require (
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/time v0.6.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

4
go.sum
View File

@ -1,5 +1,7 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
@ -95,8 +97,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@ -8,6 +8,7 @@ import (
"server/internal/controller/admin"
"server/internal/controller/auth"
"server/internal/controller/menu"
"server/internal/controller/merchant"
"server/internal/controller/role"
"server/internal/controller/wx"
"server/internal/middleware"
@ -34,6 +35,7 @@ var (
admin.NewV1(),
role.NewV1(),
menu.NewV1(),
merchant.NewV1(),
)
})
})

View File

@ -1,8 +1 @@
package consts
const (
UserRoleCode = "user"
AdminRoleCode = "admin"
MerchantRoleCode = "merchant"
StoreRoleCode = "store"
)

View File

@ -0,0 +1,20 @@
package consts
// 商户状态
const (
MerchantNormalStatus = iota + 1
MerchantDisabledStatus
)
// 商户审核状态
const (
MerchantPendingReview = iota
MerchantReviewPassed
MerchantReviewRejected
)
// 商户注册类型
const (
MerchantRegisterByAdmin = iota + 1
MerchantRegisterBySelf
)

View File

@ -0,0 +1,7 @@
package consts
// 商户管理员状态
const (
MerchantAdministratorEnable = iota + 1
MerchantAdministratorDisable
)

14
internal/consts/role.go Normal file
View File

@ -0,0 +1,14 @@
package consts
const (
GuestRoleCode = "guest"
UserRoleCode = "user"
AdminRoleCode = "admin"
MerchantRoleCode = "merchant"
StoreRoleCode = "store"
)
const (
RoleEnable = iota + 1
RoleDisable
)

View File

@ -11,7 +11,7 @@ import (
)
func (c *ControllerV1) AdminInfo(ctx context.Context, req *v1.AdminInfoReq) (res *v1.AdminInfoRes, err error) {
userId := g.RequestFromCtx(ctx).GetCtxVar("userId").Int()
userId := g.RequestFromCtx(ctx).GetCtxVar("userId").Int64()
out, err := service.Admin().Info(ctx, &model.AdminInfoIn{Id: userId})
if err != nil {
return nil, err

View File

@ -0,0 +1,16 @@
package auth
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/auth/v1"
)
func (c *ControllerV1) MerchantCode(ctx context.Context, req *v1.MerchantCodeReq) (res *v1.MerchantCodeRes, err error) {
if _, err = service.MerchantAdmin().Code(ctx, &model.MerchantAdminCodeIn{Phone: req.Phone}); err != nil {
return nil, err
}
return &v1.MerchantCodeRes{}, nil
}

View File

@ -2,13 +2,16 @@ package auth
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"server/internal/model"
"server/internal/service"
"server/api/auth/v1"
)
func (c *ControllerV1) MerchantLogin(ctx context.Context, req *v1.MerchantLoginReq) (res *v1.MerchantLoginRes, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
out, err := service.MerchantAdmin().Login(ctx, &model.MerchantLoginIn{Password: req.Password, Username: req.Username})
if err != nil {
return nil, err
}
return &v1.MerchantLoginRes{Token: out.Token}, nil
}

View File

@ -0,0 +1,20 @@
package auth
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/auth/v1"
)
func (c *ControllerV1) MerchantRegister(ctx context.Context, req *v1.MerchantRegisterReq) (res *v1.MerchantRegisterRes, err error) {
out, err := service.MerchantAdmin().Register(ctx, &model.MerchantAdminRegisterIn{Username: req.Username, Password: req.Password, Phone: req.Phone, ApplicationReason: req.ApplicationReason, Code: req.Code})
if err != nil {
return nil, err
}
return &v1.MerchantRegisterRes{
Msg: "申请成功, 等待系统管理员审核申请",
Success: out.Success,
}, nil
}

View File

@ -2,4 +2,4 @@
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package roleMenu
package merchant

View File

@ -2,14 +2,14 @@
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package roleMenu
package merchant
import (
"server/api/roleMenu"
"server/api/merchant"
)
type ControllerV1 struct{}
func NewV1() roleMenu.IRoleMenuV1 {
func NewV1() merchant.IMerchantV1 {
return &ControllerV1{}
}

View File

@ -0,0 +1,19 @@
package merchant
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"server/internal/model"
"server/internal/service"
"server/api/merchant/v1"
)
func (c *ControllerV1) Audit(ctx context.Context, req *v1.AuditReq) (res *v1.AuditRes, err error) {
adminId := g.RequestFromCtx(ctx).GetCtxVar("adminId").Int64()
_, err = service.Merchant().Audit(ctx, &model.MerchantAuditIn{Id: req.Id, AuditStatus: req.AuditStatus, AuditRemark: req.AuditRemark, AdminId: adminId, RejectReason: req.RejectReason})
if err != nil {
return nil, err
}
return &v1.AuditRes{}, nil
}

View File

@ -0,0 +1,14 @@
package merchant
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"server/api/merchant/v1"
)
func (c *ControllerV1) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}

View File

@ -1,20 +1,20 @@
package roleMenu
package merchant
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/roleMenu/v1"
"server/api/merchant/v1"
)
func (c *ControllerV1) List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) {
list, err := service.RoleMenu().List(ctx, &model.RoleMenuListInput{RoleId: req.RoleId})
out, err := service.Merchant().List(ctx, &model.MerchantListIn{Page: req.Page, Size: req.Size, AuditStatus: req.AuditStatus, Status: req.Status})
if err != nil {
return nil, err
}
return &v1.ListRes{
List: list.List,
Total: list.Total,
List: out.List,
Total: out.Total,
}, nil
}

View File

@ -0,0 +1,14 @@
package merchant
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"server/api/merchant/v1"
)
func (c *ControllerV1) Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}

View File

@ -0,0 +1,5 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package merchantAdmin

View File

@ -0,0 +1,15 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package merchantAdmin
import (
"server/api/merchantAdmin"
)
type ControllerV1 struct{}
func NewV1() merchantAdmin.IMerchantAdminV1 {
return &ControllerV1{}
}

View File

@ -0,0 +1,14 @@
package merchantAdmin
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"server/api/merchantAdmin/v1"
)
func (c *ControllerV1) MerchantAdminInfo(ctx context.Context, req *v1.MerchantAdminInfoReq) (res *v1.MerchantAdminInfoRes, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}

View File

@ -1,20 +0,0 @@
package roleMenu
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/roleMenu/v1"
)
func (c *ControllerV1) SaveRoleMenu(ctx context.Context, req *v1.SaveRoleMenuReq) (res *v1.SaveRoleMenuRes, err error) {
out, err := service.RoleMenu().Save(ctx, &model.RoleMenuSaveInput{RoleId: req.RoleId, MenuIds: req.MenuIds})
if err != nil {
return nil, err
}
return &v1.SaveRoleMenuRes{
Success: out.Success,
}, nil
}

View File

@ -33,6 +33,9 @@ type MerchantAdminsColumns struct {
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
IsPrimary string // 是否主账号0=否1=是
LastLoginIp string // 最后登录IP
RoleId string // 角色ID
}
// merchantAdminsColumns holds the columns for the table merchant_admins.
@ -50,6 +53,9 @@ var merchantAdminsColumns = MerchantAdminsColumns{
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
IsPrimary: "is_primary",
LastLoginIp: "last_login_ip",
RoleId: "role_id",
}
// NewMerchantAdminsDao creates and returns a new DAO object for table data access.

View File

@ -20,36 +20,52 @@ type MerchantsDao struct {
// MerchantsColumns defines and stores column names for the table merchants.
type MerchantsColumns struct {
Id string // 商户ID
Name string // 商户名称
BusinessLicense string // 营业执照号
LegalPerson string // 法人姓名
ContactName string // 联系人姓名
ContactPhone string // 联系人电话
ContactEmail string // 联系人邮箱
Address string // 商户地址
Status string // 状态1=正常2=禁用3=待审核
ExpireAt string // 服务到期时间
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
Id string // 商户ID
Name string // 商户名称
BusinessLicense string // 营业执照号
LegalPerson string // 法人姓名
ContactName string // 联系人姓名
ContactPhone string // 联系人电话
ContactEmail string // 联系人邮箱
Address string // 商户地址
Status string // 状态1=正常2=禁用
ExpireAt string // 服务到期时间
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
ApplicationReason string // 申请理由
CreatedBy string // 创建人ID
CreatedByType string // 创建人类型1=系统管理员2=商户注册
AuditStatus string // 审核状态0=待审核1=审核通过2=审核拒绝
AuditBy string // 审核人ID
AuditAt string // 审核时间
AuditRemark string // 审核备注
RejectReason string // 拒绝原因
}
// merchantsColumns holds the columns for the table merchants.
var merchantsColumns = MerchantsColumns{
Id: "id",
Name: "name",
BusinessLicense: "business_license",
LegalPerson: "legal_person",
ContactName: "contact_name",
ContactPhone: "contact_phone",
ContactEmail: "contact_email",
Address: "address",
Status: "status",
ExpireAt: "expire_at",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
Id: "id",
Name: "name",
BusinessLicense: "business_license",
LegalPerson: "legal_person",
ContactName: "contact_name",
ContactPhone: "contact_phone",
ContactEmail: "contact_email",
Address: "address",
Status: "status",
ExpireAt: "expire_at",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
ApplicationReason: "application_reason",
CreatedBy: "created_by",
CreatedByType: "created_by_type",
AuditStatus: "audit_status",
AuditBy: "audit_by",
AuditAt: "audit_at",
AuditRemark: "audit_remark",
RejectReason: "reject_reason",
}
// NewMerchantsDao creates and returns a new DAO object for table data access.

View File

@ -33,6 +33,7 @@ type StoreAdminsColumns struct {
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
RoleId string // 角色ID
}
// storeAdminsColumns holds the columns for the table store_admins.
@ -50,6 +51,7 @@ var storeAdminsColumns = StoreAdminsColumns{
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
RoleId: "role_id",
}
// NewStoreAdminsDao creates and returns a new DAO object for table data access.

View File

@ -20,34 +20,32 @@ type StoresDao struct {
// StoresColumns defines and stores column names for the table stores.
type StoresColumns struct {
Id string // 门店ID
MerchantId string // 所属商户ID
Name string // 门店名称
StoreCode string // 门店编号
Address string // 门店地址
ContactName string // 联系人姓名
ContactPhone string // 联系人电话
BusinessHours string // 营业时间
Status string // 状态1=正常营业2=暂停营业3=已关闭
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
Id string // 门店ID
MerchantId string // 所属商户ID
Name string // 门店名称
StoreCode string // 门店编号
Address string // 门店地址
ContactName string // 联系人姓名
ContactPhone string // 联系人电话
Status string // 状态1=正常营业2=暂停营业3=已关闭
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间
}
// storesColumns holds the columns for the table stores.
var storesColumns = StoresColumns{
Id: "id",
MerchantId: "merchant_id",
Name: "name",
StoreCode: "store_code",
Address: "address",
ContactName: "contact_name",
ContactPhone: "contact_phone",
BusinessHours: "business_hours",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
Id: "id",
MerchantId: "merchant_id",
Name: "name",
StoreCode: "store_code",
Address: "address",
ContactName: "contact_name",
ContactPhone: "contact_phone",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewStoresDao creates and returns a new DAO object for table data access.

View File

@ -37,7 +37,7 @@ func checkAdmin() {
Name: "系统管理员",
Code: consts.AdminRoleCode,
Description: "管理员角色",
Status: 1,
Status: consts.RoleEnable,
IsDeletable: false,
})
} else {

View File

@ -7,9 +7,8 @@ package logic
import (
_ "server/internal/logic/admin"
_ "server/internal/logic/menu"
_ "server/internal/logic/merchant"
_ "server/internal/logic/merchantAdmin"
_ "server/internal/logic/role"
_ "server/internal/logic/roleMenu"
_ "server/internal/logic/storeAdmin"
_ "server/internal/logic/user"
)

View File

@ -0,0 +1,83 @@
package merchant
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/os/gtime"
"server/internal/consts"
"server/internal/dao"
"server/internal/model"
"server/internal/model/do"
"server/internal/service"
"server/utility/ecode"
)
type sMerchant struct {
}
func New() service.IMerchant {
return &sMerchant{}
}
func init() {
service.RegisterMerchant(New())
}
func (s *sMerchant) List(ctx context.Context, in *model.MerchantListIn) (out *model.MerchantListOut, err error) {
list := make([]model.Merchant, 0)
var total int
orm := dao.Merchants.Ctx(ctx)
if in.Status != 0 {
orm = orm.Where(dao.Merchants.Columns().Status, in.Status)
}
if in.AuditStatus != 0 {
orm = orm.Where(dao.Merchants.Columns().AuditStatus, in.AuditStatus)
}
if err = orm.Page(in.Page, in.Size).ScanAndCount(&list, &total, false); err != nil {
return nil, ecode.Fail.Sub("查询商户列表失败")
}
return &model.MerchantListOut{
List: list,
Total: total,
}, nil
}
func (s *sMerchant) Audit(ctx context.Context, in *model.MerchantAuditIn) (out *model.MerchantAuditOut, err error) {
merchant, err := dao.Merchants.Ctx(ctx).WherePri(in.Id).One()
if err != nil {
return nil, ecode.Fail.Sub("查询商户失败")
}
if merchant.IsEmpty() {
return nil, ecode.Params.Sub("商户不存在")
}
if merchant[dao.Merchants.Columns().AuditStatus].Int() != 0 {
return nil, ecode.Params.Sub("商户已审核")
}
if err = dao.Merchants.Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
if _, err = tx.Model(dao.Merchants.Table()).WherePri(in.Id).Data(do.Merchants{
AuditBy: in.AdminId,
AuditRemark: in.AuditRemark,
AuditStatus: in.AuditStatus,
AuditAt: gtime.Now(),
Status: in.AuditStatus, // 暂定审核通过商户即可使用
RejectReason: in.RejectReason,
}).OmitEmptyData().Update(); err != nil {
return ecode.Fail.Sub("审核商户失败")
}
if _, err = tx.Model(dao.MerchantAdmins.Table()).Where(do.MerchantAdmins{MerchantId: in.Id, IsPrimary: true}).Data(do.MerchantAdmins{
Status: consts.MerchantAdministratorEnable,
}).Update(); err != nil {
return ecode.Fail.Sub("审核商户失败")
}
return nil
}); err != nil {
return nil, err
}
return
}
func (s *sMerchant) Create(ctx context.Context, in *model.MerchantCreateIn) (out *model.CreateOut, err error) {
return
}

View File

@ -1 +1,168 @@
package merchantAdmin
import (
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/grand"
"server/internal/consts"
"server/internal/dao"
"server/internal/model"
"server/internal/model/do"
"server/internal/service"
"server/utility/ecode"
utility "server/utility/encrypt"
"server/utility/jwt"
)
type sMerchantAdmin struct {
}
func New() service.IMerchantAdmin {
return &sMerchantAdmin{}
}
func init() {
service.RegisterMerchantAdmin(New())
go checkMerchantRole()
}
func checkMerchantRole() {
ctx := context.Background()
exist, err := dao.Roles.Ctx(ctx).Where(do.Roles{Code: consts.MerchantRoleCode}).Exist()
if err != nil {
return
}
if !exist {
_, err = dao.Roles.Ctx(ctx).Insert(do.Roles{
Name: "商户管理员",
Code: consts.MerchantRoleCode,
Description: "商户管理员角色",
Status: consts.RoleEnable,
IsDeletable: false,
})
if err != nil {
return
}
}
}
func (s *sMerchantAdmin) Login(ctx context.Context, in *model.MerchantLoginIn) (out *model.MerchantLoginOut, err error) {
mAdmin, err := dao.MerchantAdmins.Ctx(ctx).Where(do.MerchantAdmins{Username: in.Username}).One()
if err != nil {
return nil, ecode.Fail.Sub("查询商户管理员失败")
}
if mAdmin.IsEmpty() {
return nil, ecode.Params.Sub("该用户不存在")
}
if mAdmin[dao.MerchantAdmins.Columns().Status].Int() == consts.MerchantAdministratorDisable {
return nil, ecode.Params.Sub("该用户已被禁用")
}
if !utility.ComparePassword(mAdmin[dao.MerchantAdmins.Columns().PasswordHash].String(), in.Password) {
return nil, ecode.Params.Sub("密码错误")
}
value, err := dao.Roles.Ctx(ctx).WherePri(mAdmin[dao.MerchantAdmins.Columns().RoleId].Int()).Fields(dao.Roles.Columns().Code).Value()
if err != nil {
return nil, ecode.Fail.Sub("查询角色失败")
}
mAdminId := mAdmin[dao.MerchantAdmins.Columns().Id].Int64()
token, err := jwt.GenerateToken(&jwt.TokenIn{UserId: mAdminId, Role: value.String()})
if err != nil {
return nil, ecode.Fail.Sub("生成token失败")
}
out = &model.MerchantLoginOut{
Token: token,
}
go func(ctx context.Context, merchantAdminId int64) {
// 更新商户管理员登录时间
dao.MerchantAdmins.Ctx(ctx).WherePri(merchantAdminId).Update(do.MerchantAdmins{
LastLoginAt: gtime.Now(),
LastLoginIp: ghttp.RequestFromCtx(ctx).RemoteAddr,
})
}(ctx, mAdminId)
return
}
func (s *sMerchantAdmin) Info(ctx context.Context, in *model.MerchantAdminInfoIn) (out *model.MerchantAdminInfoOut, err error) {
return
}
func (s *sMerchantAdmin) Code(ctx context.Context, in *model.MerchantAdminCodeIn) (out *model.MerchantAdminCodeOut, err error) {
exist, err := dao.MerchantAdmins.Ctx(ctx).Where(do.MerchantAdmins{Phone: in.Phone}).Exist()
if err != nil {
return nil, ecode.Fail.Sub("查询商户管理员失败")
}
if exist {
return nil, ecode.Fail.Sub("该手机号已被注册")
}
// TODO 调用验证码服务发送验证码
// 插入缓存,过期时间为 5 分钟
if err = g.Redis().SetEX(ctx, "merchant_admin_code:"+in.Phone, grand.Digits(6), 5*60); err != nil {
return nil, ecode.Fail.Sub("插入验证码缓存失败")
}
return &model.MerchantAdminCodeOut{}, nil
}
func (s *sMerchantAdmin) VertifyPhone(ctx context.Context, in *model.MerchantAdminVertifyPhoneIn) (out *model.MerchantAdminVertifyPhoneOut, err error) {
return
}
func (s *sMerchantAdmin) Register(ctx context.Context, in *model.MerchantAdminRegisterIn) (out *model.MerchantAdminRegisterOut, err error) {
exist, err := dao.MerchantAdmins.Ctx(ctx).Where(do.MerchantAdmins{Username: in.Username}).Exist()
if err != nil {
return nil, ecode.Fail.Sub("查询商户管理员失败")
}
if exist {
return nil, ecode.Fail.Sub("该用户名已被注册")
}
// 验证码校验
code, err := g.Redis().Get(ctx, "merchant_admin_code:"+in.Phone)
if err != nil {
return nil, ecode.Fail.Sub("获取验证码缓存失败")
}
if code.IsEmpty() {
return nil, ecode.Fail.Sub("验证码已过期")
}
if code.String() != in.Code {
return nil, ecode.Fail.Sub("验证码错误")
}
hashPass, err := utility.EncryptPassword(in.Password)
if err != nil {
return nil, ecode.Fail.Sub("密码加密失败")
}
if err = dao.MerchantAdmins.Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
// 插入商户数据
id, err := tx.Model(dao.Merchants.Table()).Data(do.Merchants{
Name: fmt.Sprintf("%s的商铺", in.Username),
CreatedByType: consts.MerchantRegisterByAdmin,
Status: consts.MerchantDisabledStatus,
AuditStatus: consts.MerchantPendingReview,
ContactPhone: in.Phone,
ApplicationReason: in.ApplicationReason,
}).InsertAndGetId()
if err != nil {
return ecode.Fail.Sub("插入商户数据失败")
}
// 插入商户管理员数据
if _, err = tx.Model(dao.MerchantAdmins.Table()).Data(do.MerchantAdmins{
MerchantId: id,
PasswordHash: hashPass,
Phone: in.Phone,
IsPrimary: true,
Username: in.Username,
Status: consts.MerchantAdministratorEnable,
}).Insert(); err != nil {
return ecode.Fail.Sub("插入商户管理员数据失败")
}
return
}); err != nil {
return nil, err
}
g.Redis().Del(ctx, "merchant_admin_code:"+in.Phone)
return &model.MerchantAdminRegisterOut{Success: true}, nil
}

View File

@ -1,28 +0,0 @@
package roleMenu
import (
"context"
"server/internal/model"
"server/internal/service"
)
type sRoleMenu struct {
}
func New() service.IRoleMenu {
return &sRoleMenu{}
}
func init() {
service.RegisterRoleMenu(New())
}
func init() {
}
func (s *sRoleMenu) List(ctx context.Context, in *model.RoleMenuListInput) (out *model.MenuListOutput, err error) {
return
}
func (s *sRoleMenu) Save(ctx context.Context, in *model.RoleMenuSaveInput) (out *model.UpdateOut, err error) {
return
}

View File

@ -1 +0,0 @@
package storeAdmin

View File

@ -33,7 +33,7 @@ func checkUserRole() {
Name: "用户",
Code: consts.UserRoleCode,
Description: "用户角色",
Status: 1,
Status: consts.RoleEnable,
IsDeletable: false,
}).Insert()
if err != nil {

View File

@ -1,16 +1,55 @@
package model
type (
AdminLoginIn struct {
Username string
Password string
}
// Admin 管理员信息
type Admin struct {
Id int64 `json:"id" orm:"id,primary"` // 管理员ID
RoleId int64 `json:"roleId" orm:"role_id,not null"` // 角色ID
Username string `json:"username" orm:"username,not null"` // 管理员用户名
PasswordHash string `json:"passwordHash" orm:"password_hash,not null"` // 密码哈希
RealName string `json:"realName" orm:"real_name"` // 真实姓名
Phone string `json:"phone" orm:"phone"` // 手机号
Email string `json:"email" orm:"email"` // 邮箱
Status int `json:"status" orm:"status,default:1"` // 状态1=正常2=禁用
}
AdminInfoIn struct {
Id int
}
AdminInfoOut struct {
Id int64
Username string
}
)
// AdminCreateIn 创建管理员请求
type AdminCreateIn struct {
RoleId int64
Username string
Password string
RealName string
Phone string
Email string
Status int
}
// AdminUpdateIn 更新管理员请求
type AdminUpdateIn struct {
Id int64
RoleId int64
RealName string
Phone string
Email string
Status int
}
// AdminOut 管理员响应
type AdminOut struct {
*Admin
}
type AdminLoginIn struct {
Username string
Password string
}
type AdminInfoIn struct {
Id int64
}
type AdminInfoOut struct {
Id int64
Username string
PasswordHash string
RealName string
Phone string
Email string
}

View File

@ -25,4 +25,7 @@ type MerchantAdmins struct {
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间
DeletedAt *gtime.Time // 软删除时间戳
IsPrimary interface{} // 是否主账号0=否1=是
LastLoginIp interface{} // 最后登录IP
RoleId interface{} // 角色ID
}

View File

@ -11,18 +11,26 @@ import (
// Merchants is the golang structure of table merchants for DAO operations like Where/Data.
type Merchants struct {
g.Meta `orm:"table:merchants, do:true"`
Id interface{} // 商户ID
Name interface{} // 商户名称
BusinessLicense interface{} // 营业执照号
LegalPerson interface{} // 法人姓名
ContactName interface{} // 联系人姓名
ContactPhone interface{} // 联系人电话
ContactEmail interface{} // 联系人邮箱
Address interface{} // 商户地址
Status interface{} // 状态1=正常2=禁用3=待审核
ExpireAt *gtime.Time // 服务到期时间
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间
DeletedAt *gtime.Time // 软删除时间戳
g.Meta `orm:"table:merchants, do:true"`
Id interface{} // 商户ID
Name interface{} // 商户名称
BusinessLicense interface{} // 营业执照号
LegalPerson interface{} // 法人姓名
ContactName interface{} // 联系人姓名
ContactPhone interface{} // 联系人电话
ContactEmail interface{} // 联系人邮箱
Address interface{} // 商户地址
Status interface{} // 状态1=正常2=禁用
ExpireAt *gtime.Time // 服务到期时间
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间
DeletedAt *gtime.Time // 软删除时间戳
ApplicationReason interface{} // 申请理由
CreatedBy interface{} // 创建人ID
CreatedByType interface{} // 创建人类型1=系统管理员2=商户注册
AuditStatus interface{} // 审核状态0=待审核1=审核通过2=审核拒绝
AuditBy interface{} // 审核人ID
AuditAt *gtime.Time // 审核时间
AuditRemark interface{} // 审核备注
RejectReason interface{} // 拒绝原因
}

View File

@ -25,4 +25,5 @@ type StoreAdmins struct {
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间
DeletedAt *gtime.Time // 软删除时间戳
RoleId interface{} // 角色ID
}

View File

@ -11,17 +11,16 @@ import (
// Stores is the golang structure of table stores for DAO operations like Where/Data.
type Stores struct {
g.Meta `orm:"table:stores, do:true"`
Id interface{} // 门店ID
MerchantId interface{} // 所属商户ID
Name interface{} // 门店名称
StoreCode interface{} // 门店编号
Address interface{} // 门店地址
ContactName interface{} // 联系人姓名
ContactPhone interface{} // 联系人电话
BusinessHours interface{} // 营业时间
Status interface{} // 状态1=正常营业2=暂停营业3=已关闭
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间
DeletedAt *gtime.Time // 软删除时间戳
g.Meta `orm:"table:stores, do:true"`
Id interface{} // 门店ID
MerchantId interface{} // 所属商户ID
Name interface{} // 门店名称
StoreCode interface{} // 门店编号
Address interface{} // 门店地址
ContactName interface{} // 联系人姓名
ContactPhone interface{} // 联系人电话
Status interface{} // 状态1=正常营业2=暂停营业3=已关闭
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间
DeletedAt *gtime.Time // 软删除时间
}

View File

@ -23,4 +23,7 @@ type MerchantAdmins struct {
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
IsPrimary bool `json:"isPrimary" orm:"is_primary" description:"是否主账号0=否1=是"` // 是否主账号0=否1=是
LastLoginIp string `json:"lastLoginIp" orm:"last_login_ip" description:"最后登录IP"` // 最后登录IP
RoleId int64 `json:"roleId" orm:"role_id" description:"角色ID"` // 角色ID
}

View File

@ -10,17 +10,25 @@ import (
// Merchants is the golang structure for table merchants.
type Merchants struct {
Id int64 `json:"id" orm:"id" description:"商户ID"` // 商户ID
Name string `json:"name" orm:"name" description:"商户名称"` // 商户名称
BusinessLicense string `json:"businessLicense" orm:"business_license" description:"营业执照号"` // 营业执照号
LegalPerson string `json:"legalPerson" orm:"legal_person" description:"法人姓名"` // 法人姓名
ContactName string `json:"contactName" orm:"contact_name" description:"联系人姓名"` // 联系人姓名
ContactPhone string `json:"contactPhone" orm:"contact_phone" description:"联系人电话"` // 联系人电话
ContactEmail string `json:"contactEmail" orm:"contact_email" description:"联系人邮箱"` // 联系人邮箱
Address string `json:"address" orm:"address" description:"商户地址"` // 商户地址
Status int `json:"status" orm:"status" description:"状态1=正常2=禁用3=待审核"` // 状态1=正常2=禁用3=待审核
ExpireAt *gtime.Time `json:"expireAt" orm:"expire_at" description:"服务到期时间"` // 服务到期时间
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
Id int64 `json:"id" orm:"id" description:"商户ID"` // 商户ID
Name string `json:"name" orm:"name" description:"商户名称"` // 商户名称
BusinessLicense string `json:"businessLicense" orm:"business_license" description:"营业执照号"` // 营业执照号
LegalPerson string `json:"legalPerson" orm:"legal_person" description:"法人姓名"` // 法人姓名
ContactName string `json:"contactName" orm:"contact_name" description:"联系人姓名"` // 联系人姓名
ContactPhone string `json:"contactPhone" orm:"contact_phone" description:"联系人电话"` // 联系人电话
ContactEmail string `json:"contactEmail" orm:"contact_email" description:"联系人邮箱"` // 联系人邮箱
Address string `json:"address" orm:"address" description:"商户地址"` // 商户地址
Status int `json:"status" orm:"status" description:"状态1=正常2=禁用"` // 状态1=正常2=禁用
ExpireAt *gtime.Time `json:"expireAt" orm:"expire_at" description:"服务到期时间"` // 服务到期时间
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
ApplicationReason string `json:"applicationReason" orm:"application_reason" description:"申请理由"` // 申请理由
CreatedBy int64 `json:"createdBy" orm:"created_by" description:"创建人ID"` // 创建人ID
CreatedByType int `json:"createdByType" orm:"created_by_type" description:"创建人类型1=系统管理员2=商户注册"` // 创建人类型1=系统管理员2=商户注册
AuditStatus int `json:"auditStatus" orm:"audit_status" description:"审核状态0=待审核1=审核通过2=审核拒绝"` // 审核状态0=待审核1=审核通过2=审核拒绝
AuditBy int64 `json:"auditBy" orm:"audit_by" description:"审核人ID"` // 审核人ID
AuditAt *gtime.Time `json:"auditAt" orm:"audit_at" description:"审核时间"` // 审核时间
AuditRemark string `json:"auditRemark" orm:"audit_remark" description:"审核备注"` // 审核备注
RejectReason string `json:"rejectReason" orm:"reject_reason" description:"拒绝原因"` // 拒绝原因
}

View File

@ -23,4 +23,5 @@ type StoreAdmins struct {
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
RoleId int64 `json:"roleId" orm:"role_id" description:"角色ID"` // 角色ID
}

View File

@ -10,16 +10,15 @@ import (
// Stores is the golang structure for table stores.
type Stores struct {
Id int64 `json:"id" orm:"id" description:"门店ID"` // 门店ID
MerchantId int64 `json:"merchantId" orm:"merchant_id" description:"所属商户ID"` // 所属商户ID
Name string `json:"name" orm:"name" description:"门店名称"` // 门店名称
StoreCode string `json:"storeCode" orm:"store_code" description:"门店编号"` // 门店编号
Address string `json:"address" orm:"address" description:"门店地址"` // 门店地址
ContactName string `json:"contactName" orm:"contact_name" description:"联系人姓名"` // 联系人姓名
ContactPhone string `json:"contactPhone" orm:"contact_phone" description:"联系人电话"` // 联系人电话
BusinessHours string `json:"businessHours" orm:"business_hours" description:"营业时间"` // 营业时间
Status int `json:"status" orm:"status" description:"状态1=正常营业2=暂停营业3=已关闭"` // 状态1=正常营业2=暂停营业3=已关闭
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
Id int64 `json:"id" orm:"id" description:"门店ID"` // 门店ID
MerchantId int64 `json:"merchantId" orm:"merchant_id" description:"所属商户ID"` // 所属商户ID
Name string `json:"name" orm:"name" description:"门店名称"` // 门店名称
StoreCode string `json:"storeCode" orm:"store_code" description:"门店编号"` // 门店编号
Address string `json:"address" orm:"address" description:"门店地址"` // 门店地址
ContactName string `json:"contactName" orm:"contact_name" description:"联系人姓名"` // 联系人姓名
ContactPhone string `json:"contactPhone" orm:"contact_phone" description:"联系人电话"` // 联系人电话
Status int `json:"status" orm:"status" description:"状态1=正常营业2=暂停营业3=已关闭"` // 状态1=正常营业2=暂停营业3=已关闭
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间"` // 软删除时间
}

View File

@ -0,0 +1,80 @@
package model
import (
"github.com/gogf/gf/v2/os/gtime"
)
// Merchant 商户信息
type Merchant struct {
Id int64 `json:"id" orm:"id,primary"` // 商户ID
Name string `json:"name" orm:"name,not null"` // 商户名称
BusinessLicense string `json:"businessLicense" orm:"business_license"` // 营业执照号
LegalPerson string `json:"legalPerson" orm:"legal_person"` // 法人姓名
ContactName string `json:"contactName" orm:"contact_name"` // 联系人姓名
ContactPhone string `json:"contactPhone" orm:"contact_phone"` // 联系人电话
ContactEmail string `json:"contactEmail" orm:"contact_email"` // 联系人邮箱
Address string `json:"address" orm:"address"` // 商户地址
Status int `json:"status" orm:"status,default:1"` // 状态1=正常2=禁用
ExpireAt *gtime.Time `json:"expireAt" orm:"expire_at"` // 服务到期时间
ApplicationReason int64 `json:"applicationReason" orm:"application_reason"` // 申请理由
CreatedBy int64 `json:"createdBy" orm:"created_by"` // 创建人ID
CreatedByType int `json:"createdByType" orm:"created_by_type"` // 创建人类型1=系统管理员2=商户注册
AuditStatus int `json:"auditStatus" orm:"audit_status,default:0"` // 审核状态0=待审核1=审核通过2=审核拒绝
AuditBy int64 `json:"auditBy" orm:"audit_by"` // 审核人ID
AuditAt *gtime.Time `json:"auditAt" orm:"audit_at"` // 审核时间
AuditRemark string `json:"auditRemark" orm:"audit_remark"` // 审核备注
RejectReason string `json:"rejectReason" orm:"reject_reason"` // 拒绝原因
}
// MerchantCreateIn 创建商户请求
type MerchantCreateIn struct {
Name string
BusinessLicense string
LegalPerson string
ContactName string
ContactPhone string
ContactEmail string
Address string
ApplicationReason int64
}
// MerchantUpdateIn 更新商户请求
type MerchantUpdateIn struct {
Id int64
Name string
BusinessLicense string
LegalPerson string
ContactName string
ContactPhone string
ContactEmail string
Address string
Status int
ExpireAt *gtime.Time
}
// MerchantAuditIn 审核商户请求
type MerchantAuditIn struct {
AdminId int64
Id int64
AuditStatus int
AuditRemark string
RejectReason string
}
type MerchantAuditOut struct {
}
// MerchantOut 商户响应
type MerchantOut struct {
*Merchant
}
type MerchantListIn struct {
Page int
Size int
Status int
AuditStatus int
}
type MerchantListOut struct {
List []Merchant
Total int
}

View File

@ -0,0 +1,46 @@
package model
// MerchantAdmin 商户管理员信息
type MerchantAdmin struct {
}
// MerchantLoginIn 商户登录入参
type MerchantLoginIn struct {
Phone string
Username string
Password string
Code string
}
type MerchantLoginOut struct {
Token string
}
type MerchantAdminInfoIn struct {
MerchantAdminId int64
}
type MerchantAdminInfoOut struct {
*MerchantAdmin
}
type MerchantAdminCodeIn struct {
Phone string
}
type MerchantAdminCodeOut struct {
}
type MerchantAdminVertifyPhoneIn struct {
MerchantAdminId int64
Phone string
Code string
}
type MerchantAdminVertifyPhoneOut struct {
}
type MerchantAdminRegisterIn struct {
Username string
Phone string
Password string
Password2 string
Code string
ApplicationReason string
}
type MerchantAdminRegisterOut struct {
Success bool
}

View File

@ -1,24 +0,0 @@
package model
import "github.com/gogf/gf/v2/frame/g"
type RoleMenu struct {
g.Meta `orm:"table:role_menus"`
Id int64 `json:"id" orm:"id" dc:"角色菜单ID"`
RoleId int64 `json:"roleId" orm:"role_id" dc:"角色ID"`
MenuId int64 `json:"menuId" orm:"menu_id" dc:"菜单ID"`
}
type RoleMenuListInput struct {
Page int
Size int
RoleId int64
}
type RoleMenuListOutput struct {
List []RoleMenu
Total int
}
type RoleMenuSaveInput struct {
RoleId int
MenuIds []int
}

29
internal/model/upload.go Normal file
View File

@ -0,0 +1,29 @@
package model
import "github.com/gogf/gf/v2/net/ghttp"
type UploadIn struct {
File *ghttp.UploadFile
}
type UploadOut struct {
Url string
}
type OssOutput struct {
Url string
}
type OssBytesInput struct {
Bytes []byte
Name string
}
type OssGetFileInput struct {
FilePath string
Name string
}
type OssUploadFileInput struct {
Filename string
File *ghttp.UploadFile
}

View File

@ -1,6 +1,58 @@
package model
import "time"
import (
"time"
"github.com/gogf/gf/v2/os/gtime"
)
// User 用户信息
type User struct {
Id int64 `json:"id" orm:"id,primary"` // 用户ID
Username string `json:"username" orm:"username,not null"` // 用户名
PasswordHash string `json:"passwordHash" orm:"password_hash,not null"` // 密码哈希
Nickname string `json:"nickname" orm:"nickname"` // 昵称
Avatar string `json:"avatar" orm:"avatar"` // 头像
Phone string `json:"phone" orm:"phone"` // 手机号
Email string `json:"email" orm:"email"` // 邮箱
Gender int `json:"gender" orm:"gender,default:0"` // 性别0=未知1=男2=女
Birthday *gtime.Time `json:"birthday" orm:"birthday"` // 生日
Status int `json:"status" orm:"status,default:1"` // 状态1=正常2=禁用
LastLoginAt *gtime.Time `json:"lastLoginAt" orm:"last_login_at"` // 最后登录时间
LastLoginIp string `json:"lastLoginIp" orm:"last_login_ip"` // 最后登录IP
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at"` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at"` // 更新时间
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at"` // 软删除时间戳
}
// UserCreateIn 创建用户请求
type UserCreateIn struct {
Username string
Password string
Nickname string
Avatar string
Phone string
Email string
Gender int
Birthday *gtime.Time
}
// UserUpdateIn 更新用户请求
type UserUpdateIn struct {
Id int64
Nickname string
Avatar string
Phone string
Email string
Gender int
Birthday *gtime.Time
Status int
}
// UserOut 用户响应
type UserOut struct {
*User
}
type LoginCache struct {
Token string `json:"token"`
@ -23,7 +75,5 @@ type UserInfoOut struct {
Id int64
}
type UserUpdateIn struct {
}
type UserBindPhoneIn struct {
}

View File

@ -0,0 +1,34 @@
// ================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package service
import (
"context"
"server/internal/model"
)
type (
IMerchant interface {
List(ctx context.Context, in *model.MerchantListIn) (out *model.MerchantListOut, err error)
Audit(ctx context.Context, in *model.MerchantAuditIn) (out *model.MerchantAuditOut, err error)
Create(ctx context.Context, in *model.MerchantCreateIn) (out *model.CreateOut, err error)
}
)
var (
localMerchant IMerchant
)
func Merchant() IMerchant {
if localMerchant == nil {
panic("implement not found for interface IMerchant, forgot register?")
}
return localMerchant
}
func RegisterMerchant(i IMerchant) {
localMerchant = i
}

View File

@ -5,4 +5,32 @@
package service
type ()
import (
"context"
"server/internal/model"
)
type (
IMerchantAdmin interface {
Login(ctx context.Context, in *model.MerchantLoginIn) (out *model.MerchantLoginOut, err error)
Info(ctx context.Context, in *model.MerchantAdminInfoIn) (out *model.MerchantAdminInfoOut, err error)
Code(ctx context.Context, in *model.MerchantAdminCodeIn) (out *model.MerchantAdminCodeOut, err error)
VertifyPhone(ctx context.Context, in *model.MerchantAdminVertifyPhoneIn) (out *model.MerchantAdminVertifyPhoneOut, err error)
Register(ctx context.Context, in *model.MerchantAdminRegisterIn) (out *model.MerchantAdminRegisterOut, err error)
}
)
var (
localMerchantAdmin IMerchantAdmin
)
func MerchantAdmin() IMerchantAdmin {
if localMerchantAdmin == nil {
panic("implement not found for interface IMerchantAdmin, forgot register?")
}
return localMerchantAdmin
}
func RegisterMerchantAdmin(i IMerchantAdmin) {
localMerchantAdmin = i
}

View File

@ -1,33 +0,0 @@
// ================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package service
import (
"context"
"server/internal/model"
)
type (
IRoleMenu interface {
List(ctx context.Context, in *model.RoleMenuListInput) (out *model.MenuListOutput, err error)
Save(ctx context.Context, in *model.RoleMenuSaveInput) (out *model.UpdateOut, err error)
}
)
var (
localRoleMenu IRoleMenu
)
func RoleMenu() IRoleMenu {
if localRoleMenu == nil {
panic("implement not found for interface IRoleMenu, forgot register?")
}
return localRoleMenu
}
func RegisterRoleMenu(i IRoleMenu) {
localRoleMenu = i
}

View File

@ -1,8 +0,0 @@
// ================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package service
type ()

View File

@ -6,6 +6,7 @@ import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/glog"
"github.com/hailaz/gf-casbin-adapter/v2"
"server/internal/consts"
"sync"
)
@ -33,6 +34,10 @@ func init() {
}
enforcer.LoadPolicy()
enforcer.AddGroupingPolicy(consts.UserRoleCode, consts.GuestRoleCode) // 用户继承游客角色权限
enforcer.AddGroupingPolicy(consts.MerchantRoleCode, consts.StoreRoleCode) // 商户继承门店角色权限
enforcer.AddGroupingPolicy(consts.AdminRoleCode, consts.MerchantRoleCode) // 管理员继承商户角色权限
// 管理员
{
// admin
@ -45,6 +50,10 @@ func init() {
enforcer.AddPolicy("admin", "/x/role", "DELETE", "管理员给角色分配权限")
enforcer.AddPolicy("admin", "/x/role/*", "DELETE", "管理员删除单个角色")
// merchant
enforcer.AddPolicy("admin", "/x/merchant", "GET", "管理员获取商户列表")
enforcer.AddPolicy("admin", "/x/merchant/audit", "POST", "管理员审核商户申请")
}
instance = &myCasbin{Enforcer: enforcer}

View File

@ -0,0 +1,97 @@
package aliyun
import (
"bytes"
"context"
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/grand"
"server/internal/model"
ioss "server/utility/oss"
)
type aliyunClient struct {
bucketName string
key string
secret string
endpoint string
}
// 初始化并注册
func init() {
ctx := context.Background()
client := &aliyunClient{
endpoint: g.Config().MustGet(ctx, "oss.aliyun.endpoint").String(),
key: g.Config().MustGet(ctx, "oss.aliyun.key").String(),
secret: g.Config().MustGet(ctx, "oss.aliyun.secret").String(),
bucketName: g.Config().MustGet(ctx, "oss.aliyun.bucket").String(),
}
ioss.Register("aliyun", client)
}
func (a *aliyunClient) client(ctx context.Context, endpoint, key, sercret string) (*oss.Client, error) {
client, err := oss.New(endpoint, key, sercret)
return client, err
}
func (a *aliyunClient) bucket(ctx context.Context, client *oss.Client) (*oss.Bucket, error) {
bucket, err := client.Bucket(a.bucketName)
return bucket, err
}
func (a *aliyunClient) bytes(ctx context.Context, in *model.OssBytesInput) (*model.OssOutput, error) {
client, err := a.client(ctx, a.endpoint, a.key, a.secret)
if err != nil {
return nil, err
}
bucket, err := a.bucket(ctx, client)
if err != nil {
return nil, err
}
if in.Name == "" {
in.Name = grand.Digits(32)
}
err = bucket.PutObject(in.Name, bytes.NewReader(in.Bytes))
if err != nil {
return nil, err
}
return &model.OssOutput{
Url: fmt.Sprintf("https://%s.%s/%s", a.bucketName, a.endpoint, in.Name),
}, nil
}
func (a *aliyunClient) UploadFile(ctx context.Context, in *model.OssUploadFileInput) (out *model.OssOutput, err error) {
f, err := in.File.Open()
if err != nil {
return nil, err
}
defer f.Close()
body := make([]byte, in.File.Size)
_, err = f.Read(body)
if err != nil {
return nil, err
}
return a.bytes(ctx, &model.OssBytesInput{
Name: in.Filename,
Bytes: body,
})
}
func (a *aliyunClient) GetFileURL(ctx context.Context, in *model.OssGetFileInput) (out *model.OssOutput, err error) {
client, err := a.client(ctx, a.endpoint, a.key, a.secret)
if err != nil {
return nil, err
}
bucket, err := a.bucket(ctx, client)
if err != nil {
return nil, err
}
if in.Name == "" {
in.Name = grand.Digits(32)
}
err = bucket.PutObjectFromFile(in.Name, in.FilePath)
if err != nil {
return nil, err
}
return &model.OssOutput{
Url: fmt.Sprintf("https://%s.%s/%s", a.bucketName, a.endpoint, in.Name),
}, nil
}

26
utility/oss/oss.go Normal file
View File

@ -0,0 +1,26 @@
package oss
import (
"context"
"server/internal/model"
)
// OssClient 是所有云存储平台要实现的统一接口
type OssClient interface {
UploadFile(ctx context.Context, in *model.OssUploadFileInput) (out *model.OssOutput, err error)
GetFileURL(ctx context.Context, in *model.OssGetFileInput) (out *model.OssOutput, err error)
}
// registry 存储各个平台的实现
var clients = make(map[string]OssClient)
// Register 用于注册平台实现
func Register(name string, client OssClient) {
clients[name] = client
}
// GetClient 获取指定平台的实现
func GetClient(name string) (OssClient, bool) {
client, ok := clients[name]
return client, ok
}

View File

@ -0,0 +1,4 @@
package aliyun
type aliyunClient struct {
}

21
utility/sms/sms.go Normal file
View File

@ -0,0 +1,21 @@
package sms
import (
"context"
"server/internal/model"
)
type SMSClient interface {
UploadFile(ctx context.Context, in *model.OssUploadFileInput) (out *model.OssOutput, err error)
GetFileURL(ctx context.Context, in *model.OssGetFileInput) (out *model.OssOutput, err error)
}
var clients = make(map[string]SMSClient)
func Register(name string, client SMSClient) {
clients[name] = client
}
func GetClient(name string) (SMSClient, bool) {
client, ok := clients[name]
return client, ok
}