恢复余额功能 & 管理员修改余额功能
This commit is contained in:
47
README.md
47
README.md
@@ -2,54 +2,19 @@
|
|||||||
|
|
||||||
用户请求需要检查数据权限
|
用户请求需要检查数据权限
|
||||||
|
|
||||||
管理页面查询统一加排序
|
|
||||||
|
|
||||||
后端默认用户名不能是完整手机号
|
|
||||||
|
|
||||||
前端需要 token 化改造,以避免每次 basic 认证流程中 bcrypt 对比导致的性能对比
|
前端需要 token 化改造,以避免每次 basic 认证流程中 bcrypt 对比导致的性能对比
|
||||||
|
|
||||||
优化中间件,配置通用限速
|
|
||||||
|
|
||||||
observe 部署,蓝狐部署
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
用反射实现环境变量解析,以简化函数签名
|
用反射实现环境变量解析,以简化函数签名
|
||||||
|
|
||||||
分离 task 的客户端,支持多进程(prefork 必要!)
|
分离 task 的客户端,支持多进程(prefork 必要!)
|
||||||
|
|
||||||
调整目录结构:
|
jsonb 类型转换问题,考虑一个高效的 any 到 struct 转换工具
|
||||||
|
|
||||||
```
|
|
||||||
- /util 工具函数
|
|
||||||
|
|
||||||
- /models 模型
|
|
||||||
- /queries 数据库层
|
|
||||||
- /clients 三方依赖的客户端实例
|
|
||||||
|
|
||||||
- /services 服务层
|
|
||||||
- /auth 认证相关,特化服务
|
|
||||||
|
|
||||||
- /app 应用相关,初始化日志,环境变量,错误类型等
|
|
||||||
- /http 协议层,http 服务
|
|
||||||
- /cmd 主函数
|
|
||||||
|
|
||||||
逐层向上依赖
|
|
||||||
cmd 调用 app, http 的初始化函数
|
|
||||||
http 调用 clients 的初始化函数
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
数据库转模型文件
|
|
||||||
|
|
||||||
jsonb 类型转换问题,考虑一个高效的 any 到 struct 转换工具
|
|
||||||
|
|
||||||
慢速请求底层调用埋点监控
|
慢速请求底层调用埋点监控
|
||||||
|
|
||||||
- redis
|
数据库转模型文件
|
||||||
- gorm
|
|
||||||
- 三方接口
|
|
||||||
|
|
||||||
冷数据迁移方案
|
冷数据迁移方案
|
||||||
|
|
||||||
@@ -67,6 +32,14 @@ jsonb 类型转换问题,考虑一个高效的 any 到 struct 转换工具
|
|||||||
3. 创建 model 文件,并将其添加到 gen 代码中
|
3. 创建 model 文件,并将其添加到 gen 代码中
|
||||||
4. 生成查询文件
|
4. 生成查询文件
|
||||||
|
|
||||||
|
### 权限管理
|
||||||
|
|
||||||
|
在 `web/core/scopes.go` 下定义了系统所有静态权限
|
||||||
|
|
||||||
|
新增系统权限需要在数据库中配套添加权限
|
||||||
|
|
||||||
|
前端也需要新增配套权限定义
|
||||||
|
|
||||||
## 业务逻辑
|
## 业务逻辑
|
||||||
|
|
||||||
### 订单关闭的几种方式
|
### 订单关闭的几种方式
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ func main() {
|
|||||||
m.Whitelist{},
|
m.Whitelist{},
|
||||||
m.Inquiry{},
|
m.Inquiry{},
|
||||||
m.ProductDiscount{},
|
m.ProductDiscount{},
|
||||||
|
m.BalanceActivity{},
|
||||||
)
|
)
|
||||||
g.Execute()
|
g.Execute()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,6 @@ func Else[T any](v *T, or T) T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ElseTo[A any, B any](a *A, f func(A) B) *B {
|
|
||||||
if a == nil {
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return P(f(*a))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 三元表达式
|
// 三元表达式
|
||||||
func Ternary[T any](condition bool, trueValue T, falseValue T) T {
|
func Ternary[T any](condition bool, trueValue T, falseValue T) T {
|
||||||
if condition {
|
if condition {
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ create table admin (
|
|||||||
updated_at timestamptz default current_timestamp,
|
updated_at timestamptz default current_timestamp,
|
||||||
deleted_at timestamptz
|
deleted_at timestamptz
|
||||||
);
|
);
|
||||||
create unique index udx_admin_username on admin (username);
|
create unique index udx_admin_username on admin (username) where deleted_at is null;
|
||||||
create index idx_admin_status on admin (status) where deleted_at is null;
|
create index idx_admin_status on admin (status) where deleted_at is null;
|
||||||
create index idx_admin_created_at on admin (created_at) where deleted_at is null;
|
create index idx_admin_created_at on admin (created_at) where deleted_at is null;
|
||||||
|
|
||||||
@@ -1018,6 +1018,36 @@ comment on column bill.created_at is '创建时间';
|
|||||||
comment on column bill.updated_at is '更新时间';
|
comment on column bill.updated_at is '更新时间';
|
||||||
comment on column bill.deleted_at is '删除时间';
|
comment on column bill.deleted_at is '删除时间';
|
||||||
|
|
||||||
|
-- balance_activity 余额变动记录
|
||||||
|
drop table if exists balance_activity cascade;
|
||||||
|
create table balance_activity (
|
||||||
|
id int generated by default as identity primary key,
|
||||||
|
user_id int not null,
|
||||||
|
bill_id int,
|
||||||
|
admin_id int,
|
||||||
|
amount text not null,
|
||||||
|
balance_prev text not null,
|
||||||
|
balance_curr text not null,
|
||||||
|
remark text,
|
||||||
|
created_at timestamptz default current_timestamp
|
||||||
|
);
|
||||||
|
create index idx_balance_activity_user_id on balance_activity (user_id);
|
||||||
|
create index idx_balance_activity_bill_id on balance_activity (bill_id);
|
||||||
|
create index idx_balance_activity_admin_id on balance_activity (admin_id);
|
||||||
|
create index idx_balance_activity_created_at on balance_activity (created_at);
|
||||||
|
|
||||||
|
-- balance_activity表字段注释
|
||||||
|
comment on table balance_activity is '余额变动记录表';
|
||||||
|
comment on column balance_activity.id is '记录ID';
|
||||||
|
comment on column balance_activity.user_id is '用户ID';
|
||||||
|
comment on column balance_activity.bill_id is '账单ID';
|
||||||
|
comment on column balance_activity.admin_id is '管理员ID';
|
||||||
|
comment on column balance_activity.amount is '变动金额';
|
||||||
|
comment on column balance_activity.balance_prev is '变动前余额';
|
||||||
|
comment on column balance_activity.balance_curr is '变动后余额';
|
||||||
|
comment on column balance_activity.remark is '备注';
|
||||||
|
comment on column balance_activity.created_at is '创建时间';
|
||||||
|
|
||||||
-- coupon 优惠券
|
-- coupon 优惠券
|
||||||
drop table if exists coupon cascade;
|
drop table if exists coupon cascade;
|
||||||
create table coupon (
|
create table coupon (
|
||||||
@@ -1175,4 +1205,10 @@ alter table product_sku_user
|
|||||||
alter table product_sku_user
|
alter table product_sku_user
|
||||||
add constraint fk_product_sku_user_discount_id foreign key (discount_id) references product_discount (id) on delete restrict;
|
add constraint fk_product_sku_user_discount_id foreign key (discount_id) references product_discount (id) on delete restrict;
|
||||||
|
|
||||||
|
--balance_activity表外键
|
||||||
|
alter table balance_activity
|
||||||
|
add constraint fk_balance_activity_user_id foreign key (user_id) references "user" (id) on delete cascade;
|
||||||
|
alter table balance_activity
|
||||||
|
add constraint fk_balance_activity_bill_id foreign key (bill_id) references bill (id) on delete set null;
|
||||||
|
|
||||||
-- endregion
|
-- endregion
|
||||||
|
|||||||
@@ -155,22 +155,8 @@ func authAdminByPassword(tx *q.Query, username, password string) (*m.Admin, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func adminScopes(admin *m.Admin) ([]string, error) {
|
func adminScopes(admin *m.Admin) ([]string, error) {
|
||||||
count, err := q.Admin.
|
var scopes []struct{ Name string }
|
||||||
LeftJoin(q.LinkAdminRole, q.LinkAdminRole.AdminID.EqCol(q.Admin.ID)).
|
err := q.Admin.
|
||||||
LeftJoin(q.LinkAdminRolePermission, q.LinkAdminRolePermission.RoleID.EqCol(q.LinkAdminRole.RoleID)).
|
|
||||||
LeftJoin(q.Permission, q.Permission.ID.EqCol(q.LinkAdminRolePermission.PermissionID)).
|
|
||||||
Where(q.Admin.ID.Eq(admin.ID)).
|
|
||||||
Select(q.Permission.Name).
|
|
||||||
Count()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if count == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
scopes := make([]string, 0, count)
|
|
||||||
err = q.Admin.
|
|
||||||
LeftJoin(q.LinkAdminRole, q.LinkAdminRole.AdminID.EqCol(q.Admin.ID)).
|
LeftJoin(q.LinkAdminRole, q.LinkAdminRole.AdminID.EqCol(q.Admin.ID)).
|
||||||
LeftJoin(q.LinkAdminRolePermission, q.LinkAdminRolePermission.RoleID.EqCol(q.LinkAdminRole.RoleID)).
|
LeftJoin(q.LinkAdminRolePermission, q.LinkAdminRolePermission.RoleID.EqCol(q.LinkAdminRole.RoleID)).
|
||||||
LeftJoin(q.Permission, q.Permission.ID.EqCol(q.LinkAdminRolePermission.PermissionID)).
|
LeftJoin(q.Permission, q.Permission.ID.EqCol(q.LinkAdminRolePermission.PermissionID)).
|
||||||
@@ -181,5 +167,9 @@ func adminScopes(admin *m.Admin) ([]string, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return scopes, nil
|
scopeNames := make([]string, 0, len(scopes))
|
||||||
|
for _, scope := range scopes {
|
||||||
|
scopeNames = append(scopeNames, scope.Name)
|
||||||
|
}
|
||||||
|
return scopeNames, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -337,7 +337,6 @@ func authPassword(c *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (*m
|
|||||||
// 手机号首次登录的自动创建用户
|
// 手机号首次登录的自动创建用户
|
||||||
user = &m.User{
|
user = &m.User{
|
||||||
Phone: req.Username,
|
Phone: req.Username,
|
||||||
Username: u.P(req.Username),
|
|
||||||
Status: m.UserStatusEnabled,
|
Status: m.UserStatusEnabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -549,22 +548,30 @@ func introspectUser(ctx *fiber.Ctx, authCtx *AuthCtx) error {
|
|||||||
func introspectAdmin(ctx *fiber.Ctx, authCtx *AuthCtx) error {
|
func introspectAdmin(ctx *fiber.Ctx, authCtx *AuthCtx) error {
|
||||||
// 获取管理员信息
|
// 获取管理员信息
|
||||||
profile, err := q.Admin.
|
profile, err := q.Admin.
|
||||||
|
Preload(q.Admin.Roles, q.Admin.Roles.Permissions).
|
||||||
Where(q.Admin.ID.Eq(authCtx.Admin.ID)).
|
Where(q.Admin.ID.Eq(authCtx.Admin.ID)).
|
||||||
Omit(q.Admin.DeletedAt).
|
Omit(q.Admin.DeletedAt, q.Admin.Password).
|
||||||
Take()
|
Take()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 不返回密码
|
// 整理权限列表
|
||||||
profile.Password = ""
|
scopes := make(map[string]struct{}, 0)
|
||||||
|
for _, role := range profile.Roles {
|
||||||
// 掩码敏感信息
|
for _, permission := range role.Permissions {
|
||||||
if profile.Phone != nil && *profile.Phone != "" {
|
scopes[permission.Name] = struct{}{}
|
||||||
profile.Phone = u.P(maskPhone(*profile.Phone))
|
}
|
||||||
|
}
|
||||||
|
list := make([]string, 0, len(scopes))
|
||||||
|
for scope := range scopes {
|
||||||
|
list = append(list, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.JSON(profile)
|
return ctx.JSON(struct {
|
||||||
|
*m.Admin
|
||||||
|
Scopes []string `json:"scopes"`
|
||||||
|
}{profile, list})
|
||||||
}
|
}
|
||||||
|
|
||||||
func maskPhone(phone string) string {
|
func maskPhone(phone string) string {
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ const (
|
|||||||
|
|
||||||
ScopeUser = string("user") // 用户
|
ScopeUser = string("user") // 用户
|
||||||
ScopeUserRead = string("user:read") // 读取用户列表
|
ScopeUserRead = string("user:read") // 读取用户列表
|
||||||
|
ScopeUserReadOne = string("user:read:one") // 读取单个用户
|
||||||
ScopeUserWrite = string("user:write") // 写入用户
|
ScopeUserWrite = string("user:write") // 写入用户
|
||||||
|
ScopeUserWriteBalance = string("user:write:balance") // 写入用户余额
|
||||||
|
ScopeUserWriteBind = string("user:write:bind") // 用户认领
|
||||||
|
|
||||||
ScopeCoupon = string("coupon") // 优惠券
|
ScopeCoupon = string("coupon") // 优惠券
|
||||||
ScopeCouponRead = string("coupon:read") // 读取优惠券列表
|
ScopeCouponRead = string("coupon:read") // 读取优惠券列表
|
||||||
|
|||||||
11
web/error.go
11
web/error.go
@@ -22,8 +22,9 @@ func ErrorHandler(c *fiber.Ctx, err error) error {
|
|||||||
var authErr auth.AuthErr
|
var authErr auth.AuthErr
|
||||||
var bizErr *core.BizErr
|
var bizErr *core.BizErr
|
||||||
var servErr *core.ServErr
|
var servErr *core.ServErr
|
||||||
var jsonErr *json.UnmarshalTypeError
|
|
||||||
var timeErr *time.ParseError
|
var timeErr *time.ParseError
|
||||||
|
var jsonErr *json.UnmarshalTypeError
|
||||||
|
var jsonSyntaxErr *json.SyntaxError
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
||||||
@@ -53,13 +54,17 @@ func ErrorHandler(c *fiber.Ctx, err error) error {
|
|||||||
code = fiber.StatusInternalServerError
|
code = fiber.StatusInternalServerError
|
||||||
message = err.Error()
|
message = err.Error()
|
||||||
|
|
||||||
|
case errors.As(err, &timeErr):
|
||||||
|
code = fiber.StatusBadRequest
|
||||||
|
message = fmt.Sprintf("时间格式不正确,传入值为 %s,检查传参是否为时间类型", timeErr.Value)
|
||||||
|
|
||||||
case errors.As(err, &jsonErr):
|
case errors.As(err, &jsonErr):
|
||||||
code = fiber.StatusBadRequest
|
code = fiber.StatusBadRequest
|
||||||
message = fmt.Sprintf("参数 %s 类型不正确,传入类型为 %s,正确类型应该为 %s", jsonErr.Field, jsonErr.Value, jsonErr.Type.Name())
|
message = fmt.Sprintf("参数 %s 类型不正确,传入类型为 %s,正确类型应该为 %s", jsonErr.Field, jsonErr.Value, jsonErr.Type.Name())
|
||||||
|
|
||||||
case errors.As(err, &timeErr):
|
case errors.As(err, &jsonSyntaxErr):
|
||||||
code = fiber.StatusBadRequest
|
code = fiber.StatusBadRequest
|
||||||
message = fmt.Sprintf("时间格式不正确,传入值为 %s,检查传参是否为时间类型", timeErr.Value)
|
message = "参数格式不正确,检查传参是否为 JSON 格式"
|
||||||
|
|
||||||
// 所有未手动声明的错误类型
|
// 所有未手动声明的错误类型
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ func PageBatchByAdmin(c *fiber.Ctx) error {
|
|||||||
q.Resource.As("Resource").ResourceNo.As("Resource__resource_no"),
|
q.Resource.As("Resource").ResourceNo.As("Resource__resource_no"),
|
||||||
).
|
).
|
||||||
Where(do).
|
Where(do).
|
||||||
|
Order(q.LogsUserUsage.Time.Desc()).
|
||||||
FindByPage(req.GetOffset(), req.GetLimit())
|
FindByPage(req.GetOffset(), req.GetLimit())
|
||||||
|
|
||||||
return c.JSON(core.PageResp{
|
return c.JSON(core.PageResp{
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func PageBillByAdmin(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询用户列表
|
// 查询用户列表
|
||||||
list, total, err := q.Bill.Debug().
|
list, total, err := q.Bill.
|
||||||
Joins(
|
Joins(
|
||||||
q.Bill.User,
|
q.Bill.User,
|
||||||
q.Bill.Resource,
|
q.Bill.Resource,
|
||||||
@@ -70,6 +70,7 @@ func PageBillByAdmin(c *fiber.Ctx) error {
|
|||||||
q.User.As("User").Phone.As("User__phone"),
|
q.User.As("User").Phone.As("User__phone"),
|
||||||
q.User.As("User").Name.As("User__name"),
|
q.User.As("User").Name.As("User__name"),
|
||||||
q.Trade.As("Trade").InnerNo.As("Trade__inner_no"),
|
q.Trade.As("Trade").InnerNo.As("Trade__inner_no"),
|
||||||
|
q.Trade.As("Trade").Acquirer.As("Trade__acquirer"),
|
||||||
q.Resource.As("Resource").ResourceNo.As("Resource__resource_no"),
|
q.Resource.As("Resource").ResourceNo.As("Resource__resource_no"),
|
||||||
).
|
).
|
||||||
Where(do).
|
Where(do).
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ func PageChannelByAdmin(c *fiber.Ctx) error {
|
|||||||
q.User.As("User").Name.As("User__name"),
|
q.User.As("User").Name.As("User__name"),
|
||||||
).
|
).
|
||||||
Where(do).
|
Where(do).
|
||||||
|
Order(q.Channel.CreatedAt.Desc()).
|
||||||
FindByPage(req.GetOffset(), req.GetLimit())
|
FindByPage(req.GetOffset(), req.GetLimit())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -190,6 +191,10 @@ func CreateChannel(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建通道
|
// 创建通道
|
||||||
|
var isp *m.EdgeISP
|
||||||
|
if req.Isp != nil {
|
||||||
|
isp = u.X(m.ToEdgeISP(*req.Isp))
|
||||||
|
}
|
||||||
result, err := s.Channel.CreateChannels(
|
result, err := s.Channel.CreateChannels(
|
||||||
ip,
|
ip,
|
||||||
req.ResourceId,
|
req.ResourceId,
|
||||||
@@ -197,7 +202,7 @@ func CreateChannel(c *fiber.Ctx) error {
|
|||||||
req.AuthType == s.ChannelAuthTypePass,
|
req.AuthType == s.ChannelAuthTypePass,
|
||||||
req.Count,
|
req.Count,
|
||||||
s.EdgeFilter{
|
s.EdgeFilter{
|
||||||
Isp: u.ElseTo(req.Isp, m.ToEdgeISP),
|
Isp: isp,
|
||||||
Prov: req.Prov,
|
Prov: req.Prov,
|
||||||
City: req.City,
|
City: req.City,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ func PageResourceShortByAdmin(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list, total, err := q.Resource.Debug().
|
list, total, err := q.Resource.
|
||||||
Joins(q.Resource.User, q.Resource.Short, q.Resource.Short.Sku).
|
Joins(q.Resource.User, q.Resource.Short, q.Resource.Short.Sku).
|
||||||
Select(
|
Select(
|
||||||
q.Resource.ALL,
|
q.Resource.ALL,
|
||||||
@@ -352,7 +352,7 @@ func PageResourceLongByAdmin(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list, total, err := q.Resource.Debug().
|
list, total, err := q.Resource.
|
||||||
Joins(q.Resource.User, q.Resource.Long, q.Resource.Long.Sku).
|
Joins(q.Resource.User, q.Resource.Long, q.Resource.Long.Sku).
|
||||||
Select(
|
Select(
|
||||||
q.Resource.ALL,
|
q.Resource.ALL,
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ func PageTradeByAdmin(c *fiber.Ctx) error {
|
|||||||
q.User.As("User").Name.As("User__name"),
|
q.User.As("User").Name.As("User__name"),
|
||||||
).
|
).
|
||||||
Where(do).
|
Where(do).
|
||||||
|
Order(q.Trade.CreatedAt.Desc()).
|
||||||
FindByPage(req.GetOffset(), req.GetLimit())
|
FindByPage(req.GetOffset(), req.GetLimit())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -121,7 +122,13 @@ func TradeCreate(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理订单
|
// 处理订单
|
||||||
result, err := s.Trade.Create(authCtx.User, req.CreateTradeData, req.Resource)
|
var result *s.CreateTradeResult
|
||||||
|
switch req.Type {
|
||||||
|
case m.TradeTypePurchase:
|
||||||
|
result, err = s.Trade.Create(authCtx.User, req.CreateTradeData, req.Resource)
|
||||||
|
case m.TradeTypeRecharge:
|
||||||
|
result, err = s.Trade.Create(authCtx.User, req.CreateTradeData, req.Recharge)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return core.NewServErr("处理购买产品信息失败", err)
|
return core.NewServErr("处理购买产品信息失败", err)
|
||||||
}
|
}
|
||||||
@@ -193,11 +200,7 @@ type TradeCancelReq struct {
|
|||||||
|
|
||||||
// 检查订单
|
// 检查订单
|
||||||
func TradeCheck(c *fiber.Ctx) error {
|
func TradeCheck(c *fiber.Ctx) error {
|
||||||
// 检查权限
|
// 检查权限:sse 接口暂时不检查权限
|
||||||
_, err := auth.GetAuthCtx(c).PermitUser()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析请求参数
|
// 解析请求参数
|
||||||
req := new(TradeCheckReq)
|
req := new(TradeCheckReq)
|
||||||
|
|||||||
@@ -9,9 +9,157 @@ import (
|
|||||||
s "platform/web/services"
|
s "platform/web/services"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 分页获取用户
|
||||||
|
func PageUserByAdmin(c *fiber.Ctx) error {
|
||||||
|
// 检查权限
|
||||||
|
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserRead)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析请求参数
|
||||||
|
req := new(PageUserByAdminReq)
|
||||||
|
if err := g.Validator.ParseBody(c, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件
|
||||||
|
do := q.User.Where()
|
||||||
|
if req.Account != nil {
|
||||||
|
do = do.Where(q.User.Where(
|
||||||
|
q.User.Username.Like("%" + *req.Account + "%"),
|
||||||
|
).Or(
|
||||||
|
q.User.Phone.Like("%" + *req.Account + "%"),
|
||||||
|
).Or(
|
||||||
|
q.User.Email.Like("%" + *req.Account + "%"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
if req.Name != nil {
|
||||||
|
do = do.Where(q.User.Name.Eq(*req.Name))
|
||||||
|
}
|
||||||
|
if req.Identified != nil {
|
||||||
|
if *req.Identified {
|
||||||
|
do = do.Where(q.User.IDType.Gt(0))
|
||||||
|
} else {
|
||||||
|
do = do.Where(q.User.IDType.Eq(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.Enabled != nil {
|
||||||
|
if *req.Enabled {
|
||||||
|
do = do.Where(q.User.Status.Eq(1))
|
||||||
|
} else {
|
||||||
|
do = do.Where(q.User.Status.Eq(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.Assigned != nil {
|
||||||
|
if *req.Assigned {
|
||||||
|
do = do.Where(q.User.AdminID.IsNotNull())
|
||||||
|
} else {
|
||||||
|
do = do.Where(q.User.AdminID.IsNull())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询用户列表
|
||||||
|
users, total, err := q.User.
|
||||||
|
Preload(q.User.Admin, q.User.Discount).
|
||||||
|
Omit(q.User.Password).
|
||||||
|
Where(do).
|
||||||
|
Order(q.User.CreatedAt.Desc()).
|
||||||
|
FindByPage(req.GetOffset(), req.GetLimit())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
if user.Admin != nil {
|
||||||
|
user.Admin = &m.Admin{
|
||||||
|
Name: user.Admin.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回结果
|
||||||
|
return c.JSON(core.PageResp{
|
||||||
|
Total: int(total),
|
||||||
|
Page: req.GetPage(),
|
||||||
|
Size: req.GetSize(),
|
||||||
|
List: users,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type PageUserByAdminReq struct {
|
||||||
|
core.PageReq
|
||||||
|
Account *string `json:"account,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Identified *bool `json:"identified,omitempty"`
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
Assigned *bool `json:"assigned,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 管理员获取单个用户
|
||||||
|
func GetUserByAdmin(c *fiber.Ctx) error {
|
||||||
|
// 检查权限
|
||||||
|
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserReadOne)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析请求参数
|
||||||
|
var req GetUserByAdminReq
|
||||||
|
if err := g.Validator.ParseBody(c, &req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件
|
||||||
|
do := q.User.Where()
|
||||||
|
if req.Account != nil {
|
||||||
|
do = do.Where(q.User.Where(
|
||||||
|
q.User.Username.Like("%" + *req.Account + "%"),
|
||||||
|
).Or(
|
||||||
|
q.User.Phone.Like("%" + *req.Account + "%"),
|
||||||
|
).Or(
|
||||||
|
q.User.Email.Like("%" + *req.Account + "%"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
if req.Name != nil {
|
||||||
|
do = do.Where(q.User.Name.Eq(*req.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询用户
|
||||||
|
user, err := q.User.
|
||||||
|
Preload(q.User.Admin, q.User.Discount).
|
||||||
|
Omit(q.User.Password).
|
||||||
|
Where(do).
|
||||||
|
Order(q.User.CreatedAt.Desc()).
|
||||||
|
First()
|
||||||
|
if err == gorm.ErrRecordNotFound {
|
||||||
|
return core.NewBizErr("找不到用户")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 仅保留管理员名称
|
||||||
|
if user.Admin != nil {
|
||||||
|
user.Admin = &m.Admin{
|
||||||
|
Name: user.Admin.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回结果
|
||||||
|
return c.JSON(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetUserByAdminReq struct {
|
||||||
|
Account *string `json:"account,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// 管理员创建用户
|
// 管理员创建用户
|
||||||
func CreateUserByAdmin(c *fiber.Ctx) error {
|
func CreateUserByAdmin(c *fiber.Ctx) error {
|
||||||
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWrite)
|
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWrite)
|
||||||
@@ -69,91 +217,36 @@ func RemoveUserByAdmin(c *fiber.Ctx) error {
|
|||||||
return c.JSON(nil)
|
return c.JSON(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分页获取用户
|
// 管理员更新用户余额
|
||||||
func PageUserByAdmin(c *fiber.Ctx) error {
|
func UpdateUserBalanceByAdmin(c *fiber.Ctx) error {
|
||||||
// 检查权限
|
authCtx, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWriteBalance)
|
||||||
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserRead)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析请求参数
|
var req UpdateUserBalanceByAdminData
|
||||||
req := new(PageUserByAdminReq)
|
if err := g.Validator.ParseBody(c, &req); err != nil {
|
||||||
if err := g.Validator.ParseBody(c, req); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建查询条件
|
user, err := s.User.Get(q.Q, req.UserID)
|
||||||
do := q.User.Where()
|
|
||||||
if req.Account != nil {
|
|
||||||
do = do.Where(q.User.Where(
|
|
||||||
q.User.Username.Like("%" + *req.Account + "%"),
|
|
||||||
).Or(
|
|
||||||
q.User.Phone.Like("%" + *req.Account + "%"),
|
|
||||||
).Or(
|
|
||||||
q.User.Email.Like("%" + *req.Account + "%"),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
if req.Name != nil {
|
|
||||||
do = do.Where(q.User.Name.Eq(*req.Name))
|
|
||||||
}
|
|
||||||
if req.Identified != nil {
|
|
||||||
if *req.Identified {
|
|
||||||
do = do.Where(q.User.IDType.Gt(0))
|
|
||||||
} else {
|
|
||||||
do = do.Where(q.User.IDType.Eq(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if req.Enabled != nil {
|
|
||||||
if *req.Enabled {
|
|
||||||
do = do.Where(q.User.Status.Eq(1))
|
|
||||||
} else {
|
|
||||||
do = do.Where(q.User.Status.Eq(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if req.Assigned != nil {
|
|
||||||
if *req.Assigned {
|
|
||||||
do = do.Where(q.User.AdminID.IsNotNull())
|
|
||||||
} else {
|
|
||||||
do = do.Where(q.User.AdminID.IsNull())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询用户列表
|
|
||||||
users, total, err := q.User.Debug().
|
|
||||||
Preload(q.User.Admin, q.User.Discount).
|
|
||||||
Omit(q.User.Password).
|
|
||||||
Where(do).
|
|
||||||
Order(q.User.CreatedAt).
|
|
||||||
FindByPage(req.GetOffset(), req.GetLimit())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
balance, err := decimal.NewFromString(req.Balance)
|
||||||
for _, user := range users {
|
if err != nil {
|
||||||
if user.Admin != nil {
|
return err
|
||||||
user.Admin = &m.Admin{
|
|
||||||
Name: user.Admin.Name,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if err := s.User.UpdateBalanceByAdmin(user, balance, &authCtx.Admin.ID); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回结果
|
return c.JSON(nil)
|
||||||
return c.JSON(core.PageResp{
|
|
||||||
Total: int(total),
|
|
||||||
Page: req.GetPage(),
|
|
||||||
Size: req.GetSize(),
|
|
||||||
List: users,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PageUserByAdminReq struct {
|
type UpdateUserBalanceByAdminData struct {
|
||||||
core.PageReq
|
UserID int32 `json:"user_id" validate:"required"`
|
||||||
Account *string `json:"account,omitempty"`
|
Balance string `json:"balance" validate:"required"`
|
||||||
Name *string `json:"name,omitempty"`
|
|
||||||
Identified *bool `json:"identified,omitempty"`
|
|
||||||
Enabled *bool `json:"enabled,omitempty"`
|
|
||||||
Assigned *bool `json:"assigned,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绑定管理员
|
// 绑定管理员
|
||||||
|
|||||||
22
web/models/balance_activity.go
Normal file
22
web/models/balance_activity.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BalanceActivity 余额变动记录表
|
||||||
|
type BalanceActivity struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id;primaryKey"` // 记录ID
|
||||||
|
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
BillID *int32 `json:"bill_id,omitempty" gorm:"column:bill_id"` // 账单ID
|
||||||
|
AdminID *int32 `json:"admin_id,omitempty" gorm:"column:admin_id"` // 管理员ID
|
||||||
|
Amount string `json:"amount" gorm:"column:amount"` // 变动金额
|
||||||
|
BalancePrev string `json:"balance_prev" gorm:"column:balance_prev"` // 变动前余额
|
||||||
|
BalanceCurr string `json:"balance_curr" gorm:"column:balance_curr"` // 变动后余额
|
||||||
|
Remark *string `json:"remark,omitempty" gorm:"column:remark"` // 备注
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` // 创建时间
|
||||||
|
|
||||||
|
User *User `json:"user,omitempty" gorm:"foreignKey:UserID"`
|
||||||
|
Bill *Bill `json:"bill,omitempty" gorm:"foreignKey:BillID"`
|
||||||
|
Admin *User `json:"admin,omitempty" gorm:"foreignKey:AdminID"`
|
||||||
|
}
|
||||||
871
web/queries/balance_activity.gen.go
Normal file
871
web/queries/balance_activity.gen.go
Normal file
@@ -0,0 +1,871 @@
|
|||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package queries
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
|
|
||||||
|
"gorm.io/gen"
|
||||||
|
"gorm.io/gen/field"
|
||||||
|
|
||||||
|
"gorm.io/plugin/dbresolver"
|
||||||
|
|
||||||
|
"platform/web/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
|
||||||
|
_balanceActivity := balanceActivity{}
|
||||||
|
|
||||||
|
_balanceActivity.balanceActivityDo.UseDB(db, opts...)
|
||||||
|
_balanceActivity.balanceActivityDo.UseModel(&models.BalanceActivity{})
|
||||||
|
|
||||||
|
tableName := _balanceActivity.balanceActivityDo.TableName()
|
||||||
|
_balanceActivity.ALL = field.NewAsterisk(tableName)
|
||||||
|
_balanceActivity.ID = field.NewInt32(tableName, "id")
|
||||||
|
_balanceActivity.UserID = field.NewInt32(tableName, "user_id")
|
||||||
|
_balanceActivity.BillID = field.NewInt32(tableName, "bill_id")
|
||||||
|
_balanceActivity.AdminID = field.NewInt32(tableName, "admin_id")
|
||||||
|
_balanceActivity.Amount = field.NewString(tableName, "amount")
|
||||||
|
_balanceActivity.BalancePrev = field.NewString(tableName, "balance_prev")
|
||||||
|
_balanceActivity.BalanceCurr = field.NewString(tableName, "balance_curr")
|
||||||
|
_balanceActivity.Remark = field.NewString(tableName, "remark")
|
||||||
|
_balanceActivity.CreatedAt = field.NewTime(tableName, "created_at")
|
||||||
|
_balanceActivity.Admin = balanceActivityHasOneAdmin{
|
||||||
|
db: db.Session(&gorm.Session{}),
|
||||||
|
|
||||||
|
RelationField: field.NewRelation("Admin", "models.User"),
|
||||||
|
Admin: struct {
|
||||||
|
field.RelationField
|
||||||
|
Roles struct {
|
||||||
|
field.RelationField
|
||||||
|
Permissions struct {
|
||||||
|
field.RelationField
|
||||||
|
Parent struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Children struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Admin.Admin", "models.Admin"),
|
||||||
|
Roles: struct {
|
||||||
|
field.RelationField
|
||||||
|
Permissions struct {
|
||||||
|
field.RelationField
|
||||||
|
Parent struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Children struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Admin.Admin.Roles", "models.AdminRole"),
|
||||||
|
Permissions: struct {
|
||||||
|
field.RelationField
|
||||||
|
Parent struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Children struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Admin.Admin.Roles.Permissions", "models.Permission"),
|
||||||
|
Parent: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Admin.Admin.Roles.Permissions.Parent", "models.Permission"),
|
||||||
|
},
|
||||||
|
Children: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Admin.Admin.Roles.Permissions.Children", "models.Permission"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Discount: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Admin.Discount", "models.ProductDiscount"),
|
||||||
|
},
|
||||||
|
Roles: struct {
|
||||||
|
field.RelationField
|
||||||
|
Permissions struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Admin.Roles", "models.UserRole"),
|
||||||
|
Permissions: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Admin.Roles.Permissions", "models.Permission"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_balanceActivity.User = balanceActivityBelongsToUser{
|
||||||
|
db: db.Session(&gorm.Session{}),
|
||||||
|
|
||||||
|
RelationField: field.NewRelation("User", "models.User"),
|
||||||
|
}
|
||||||
|
|
||||||
|
_balanceActivity.Bill = balanceActivityBelongsToBill{
|
||||||
|
db: db.Session(&gorm.Session{}),
|
||||||
|
|
||||||
|
RelationField: field.NewRelation("Bill", "models.Bill"),
|
||||||
|
User: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.User", "models.User"),
|
||||||
|
},
|
||||||
|
Trade: struct {
|
||||||
|
field.RelationField
|
||||||
|
User struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Trade", "models.Trade"),
|
||||||
|
User: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Trade.User", "models.User"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Resource: struct {
|
||||||
|
field.RelationField
|
||||||
|
User struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Short struct {
|
||||||
|
field.RelationField
|
||||||
|
Sku struct {
|
||||||
|
field.RelationField
|
||||||
|
Product struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Discount struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Long struct {
|
||||||
|
field.RelationField
|
||||||
|
Sku struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Product struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Resource", "models.Resource"),
|
||||||
|
User: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Resource.User", "models.User"),
|
||||||
|
},
|
||||||
|
Short: struct {
|
||||||
|
field.RelationField
|
||||||
|
Sku struct {
|
||||||
|
field.RelationField
|
||||||
|
Product struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Discount struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Resource.Short", "models.ResourceShort"),
|
||||||
|
Sku: struct {
|
||||||
|
field.RelationField
|
||||||
|
Product struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Discount struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Resource.Short.Sku", "models.ProductSku"),
|
||||||
|
Product: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Resource.Short.Sku.Product", "models.Product"),
|
||||||
|
},
|
||||||
|
Discount: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Resource.Short.Sku.Discount", "models.ProductDiscount"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Long: struct {
|
||||||
|
field.RelationField
|
||||||
|
Sku struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Resource.Long", "models.ResourceLong"),
|
||||||
|
Sku: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Resource.Long.Sku", "models.ProductSku"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Product: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Resource.Product", "models.Product"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Refund: struct {
|
||||||
|
field.RelationField
|
||||||
|
}{
|
||||||
|
RelationField: field.NewRelation("Bill.Refund", "models.Refund"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_balanceActivity.fillFieldMap()
|
||||||
|
|
||||||
|
return _balanceActivity
|
||||||
|
}
|
||||||
|
|
||||||
|
type balanceActivity struct {
|
||||||
|
balanceActivityDo
|
||||||
|
|
||||||
|
ALL field.Asterisk
|
||||||
|
ID field.Int32
|
||||||
|
UserID field.Int32
|
||||||
|
BillID field.Int32
|
||||||
|
AdminID field.Int32
|
||||||
|
Amount field.String
|
||||||
|
BalancePrev field.String
|
||||||
|
BalanceCurr field.String
|
||||||
|
Remark field.String
|
||||||
|
CreatedAt field.Time
|
||||||
|
Admin balanceActivityHasOneAdmin
|
||||||
|
|
||||||
|
User balanceActivityBelongsToUser
|
||||||
|
|
||||||
|
Bill balanceActivityBelongsToBill
|
||||||
|
|
||||||
|
fieldMap map[string]field.Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivity) Table(newTableName string) *balanceActivity {
|
||||||
|
b.balanceActivityDo.UseTable(newTableName)
|
||||||
|
return b.updateTableName(newTableName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivity) As(alias string) *balanceActivity {
|
||||||
|
b.balanceActivityDo.DO = *(b.balanceActivityDo.As(alias).(*gen.DO))
|
||||||
|
return b.updateTableName(alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *balanceActivity) updateTableName(table string) *balanceActivity {
|
||||||
|
b.ALL = field.NewAsterisk(table)
|
||||||
|
b.ID = field.NewInt32(table, "id")
|
||||||
|
b.UserID = field.NewInt32(table, "user_id")
|
||||||
|
b.BillID = field.NewInt32(table, "bill_id")
|
||||||
|
b.AdminID = field.NewInt32(table, "admin_id")
|
||||||
|
b.Amount = field.NewString(table, "amount")
|
||||||
|
b.BalancePrev = field.NewString(table, "balance_prev")
|
||||||
|
b.BalanceCurr = field.NewString(table, "balance_curr")
|
||||||
|
b.Remark = field.NewString(table, "remark")
|
||||||
|
b.CreatedAt = field.NewTime(table, "created_at")
|
||||||
|
|
||||||
|
b.fillFieldMap()
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *balanceActivity) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
|
||||||
|
_f, ok := b.fieldMap[fieldName]
|
||||||
|
if !ok || _f == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
_oe, ok := _f.(field.OrderExpr)
|
||||||
|
return _oe, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *balanceActivity) fillFieldMap() {
|
||||||
|
b.fieldMap = make(map[string]field.Expr, 12)
|
||||||
|
b.fieldMap["id"] = b.ID
|
||||||
|
b.fieldMap["user_id"] = b.UserID
|
||||||
|
b.fieldMap["bill_id"] = b.BillID
|
||||||
|
b.fieldMap["admin_id"] = b.AdminID
|
||||||
|
b.fieldMap["amount"] = b.Amount
|
||||||
|
b.fieldMap["balance_prev"] = b.BalancePrev
|
||||||
|
b.fieldMap["balance_curr"] = b.BalanceCurr
|
||||||
|
b.fieldMap["remark"] = b.Remark
|
||||||
|
b.fieldMap["created_at"] = b.CreatedAt
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivity) clone(db *gorm.DB) balanceActivity {
|
||||||
|
b.balanceActivityDo.ReplaceConnPool(db.Statement.ConnPool)
|
||||||
|
b.Admin.db = db.Session(&gorm.Session{Initialized: true})
|
||||||
|
b.Admin.db.Statement.ConnPool = db.Statement.ConnPool
|
||||||
|
b.User.db = db.Session(&gorm.Session{Initialized: true})
|
||||||
|
b.User.db.Statement.ConnPool = db.Statement.ConnPool
|
||||||
|
b.Bill.db = db.Session(&gorm.Session{Initialized: true})
|
||||||
|
b.Bill.db.Statement.ConnPool = db.Statement.ConnPool
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivity) replaceDB(db *gorm.DB) balanceActivity {
|
||||||
|
b.balanceActivityDo.ReplaceDB(db)
|
||||||
|
b.Admin.db = db.Session(&gorm.Session{})
|
||||||
|
b.User.db = db.Session(&gorm.Session{})
|
||||||
|
b.Bill.db = db.Session(&gorm.Session{})
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
type balanceActivityHasOneAdmin struct {
|
||||||
|
db *gorm.DB
|
||||||
|
|
||||||
|
field.RelationField
|
||||||
|
|
||||||
|
Admin struct {
|
||||||
|
field.RelationField
|
||||||
|
Roles struct {
|
||||||
|
field.RelationField
|
||||||
|
Permissions struct {
|
||||||
|
field.RelationField
|
||||||
|
Parent struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Children struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Discount struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Roles struct {
|
||||||
|
field.RelationField
|
||||||
|
Permissions struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdmin) Where(conds ...field.Expr) *balanceActivityHasOneAdmin {
|
||||||
|
if len(conds) == 0 {
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
exprs := make([]clause.Expression, 0, len(conds))
|
||||||
|
for _, cond := range conds {
|
||||||
|
exprs = append(exprs, cond.BeCond().(clause.Expression))
|
||||||
|
}
|
||||||
|
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdmin) WithContext(ctx context.Context) *balanceActivityHasOneAdmin {
|
||||||
|
a.db = a.db.WithContext(ctx)
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdmin) Session(session *gorm.Session) *balanceActivityHasOneAdmin {
|
||||||
|
a.db = a.db.Session(session)
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdmin) Model(m *models.BalanceActivity) *balanceActivityHasOneAdminTx {
|
||||||
|
return &balanceActivityHasOneAdminTx{a.db.Model(m).Association(a.Name())}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdmin) Unscoped() *balanceActivityHasOneAdmin {
|
||||||
|
a.db = a.db.Unscoped()
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
type balanceActivityHasOneAdminTx struct{ tx *gorm.Association }
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdminTx) Find() (result *models.User, err error) {
|
||||||
|
return result, a.tx.Find(&result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdminTx) Append(values ...*models.User) (err error) {
|
||||||
|
targetValues := make([]interface{}, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
targetValues[i] = v
|
||||||
|
}
|
||||||
|
return a.tx.Append(targetValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdminTx) Replace(values ...*models.User) (err error) {
|
||||||
|
targetValues := make([]interface{}, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
targetValues[i] = v
|
||||||
|
}
|
||||||
|
return a.tx.Replace(targetValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdminTx) Delete(values ...*models.User) (err error) {
|
||||||
|
targetValues := make([]interface{}, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
targetValues[i] = v
|
||||||
|
}
|
||||||
|
return a.tx.Delete(targetValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdminTx) Clear() error {
|
||||||
|
return a.tx.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdminTx) Count() int64 {
|
||||||
|
return a.tx.Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityHasOneAdminTx) Unscoped() *balanceActivityHasOneAdminTx {
|
||||||
|
a.tx = a.tx.Unscoped()
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
type balanceActivityBelongsToUser struct {
|
||||||
|
db *gorm.DB
|
||||||
|
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUser) Where(conds ...field.Expr) *balanceActivityBelongsToUser {
|
||||||
|
if len(conds) == 0 {
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
exprs := make([]clause.Expression, 0, len(conds))
|
||||||
|
for _, cond := range conds {
|
||||||
|
exprs = append(exprs, cond.BeCond().(clause.Expression))
|
||||||
|
}
|
||||||
|
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUser) WithContext(ctx context.Context) *balanceActivityBelongsToUser {
|
||||||
|
a.db = a.db.WithContext(ctx)
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUser) Session(session *gorm.Session) *balanceActivityBelongsToUser {
|
||||||
|
a.db = a.db.Session(session)
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUser) Model(m *models.BalanceActivity) *balanceActivityBelongsToUserTx {
|
||||||
|
return &balanceActivityBelongsToUserTx{a.db.Model(m).Association(a.Name())}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUser) Unscoped() *balanceActivityBelongsToUser {
|
||||||
|
a.db = a.db.Unscoped()
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
type balanceActivityBelongsToUserTx struct{ tx *gorm.Association }
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUserTx) Find() (result *models.User, err error) {
|
||||||
|
return result, a.tx.Find(&result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUserTx) Append(values ...*models.User) (err error) {
|
||||||
|
targetValues := make([]interface{}, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
targetValues[i] = v
|
||||||
|
}
|
||||||
|
return a.tx.Append(targetValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUserTx) Replace(values ...*models.User) (err error) {
|
||||||
|
targetValues := make([]interface{}, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
targetValues[i] = v
|
||||||
|
}
|
||||||
|
return a.tx.Replace(targetValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUserTx) Delete(values ...*models.User) (err error) {
|
||||||
|
targetValues := make([]interface{}, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
targetValues[i] = v
|
||||||
|
}
|
||||||
|
return a.tx.Delete(targetValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUserTx) Clear() error {
|
||||||
|
return a.tx.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUserTx) Count() int64 {
|
||||||
|
return a.tx.Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToUserTx) Unscoped() *balanceActivityBelongsToUserTx {
|
||||||
|
a.tx = a.tx.Unscoped()
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
type balanceActivityBelongsToBill struct {
|
||||||
|
db *gorm.DB
|
||||||
|
|
||||||
|
field.RelationField
|
||||||
|
|
||||||
|
User struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Trade struct {
|
||||||
|
field.RelationField
|
||||||
|
User struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Resource struct {
|
||||||
|
field.RelationField
|
||||||
|
User struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Short struct {
|
||||||
|
field.RelationField
|
||||||
|
Sku struct {
|
||||||
|
field.RelationField
|
||||||
|
Product struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
Discount struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Long struct {
|
||||||
|
field.RelationField
|
||||||
|
Sku struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Product struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Refund struct {
|
||||||
|
field.RelationField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBill) Where(conds ...field.Expr) *balanceActivityBelongsToBill {
|
||||||
|
if len(conds) == 0 {
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
exprs := make([]clause.Expression, 0, len(conds))
|
||||||
|
for _, cond := range conds {
|
||||||
|
exprs = append(exprs, cond.BeCond().(clause.Expression))
|
||||||
|
}
|
||||||
|
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBill) WithContext(ctx context.Context) *balanceActivityBelongsToBill {
|
||||||
|
a.db = a.db.WithContext(ctx)
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBill) Session(session *gorm.Session) *balanceActivityBelongsToBill {
|
||||||
|
a.db = a.db.Session(session)
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBill) Model(m *models.BalanceActivity) *balanceActivityBelongsToBillTx {
|
||||||
|
return &balanceActivityBelongsToBillTx{a.db.Model(m).Association(a.Name())}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBill) Unscoped() *balanceActivityBelongsToBill {
|
||||||
|
a.db = a.db.Unscoped()
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
type balanceActivityBelongsToBillTx struct{ tx *gorm.Association }
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBillTx) Find() (result *models.Bill, err error) {
|
||||||
|
return result, a.tx.Find(&result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBillTx) Append(values ...*models.Bill) (err error) {
|
||||||
|
targetValues := make([]interface{}, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
targetValues[i] = v
|
||||||
|
}
|
||||||
|
return a.tx.Append(targetValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBillTx) Replace(values ...*models.Bill) (err error) {
|
||||||
|
targetValues := make([]interface{}, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
targetValues[i] = v
|
||||||
|
}
|
||||||
|
return a.tx.Replace(targetValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBillTx) Delete(values ...*models.Bill) (err error) {
|
||||||
|
targetValues := make([]interface{}, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
targetValues[i] = v
|
||||||
|
}
|
||||||
|
return a.tx.Delete(targetValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBillTx) Clear() error {
|
||||||
|
return a.tx.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBillTx) Count() int64 {
|
||||||
|
return a.tx.Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a balanceActivityBelongsToBillTx) Unscoped() *balanceActivityBelongsToBillTx {
|
||||||
|
a.tx = a.tx.Unscoped()
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
type balanceActivityDo struct{ gen.DO }
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Debug() *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Debug())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) WithContext(ctx context.Context) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) ReadDB() *balanceActivityDo {
|
||||||
|
return b.Clauses(dbresolver.Read)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) WriteDB() *balanceActivityDo {
|
||||||
|
return b.Clauses(dbresolver.Write)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Session(config *gorm.Session) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Session(config))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Clauses(conds ...clause.Expression) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Clauses(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Returning(value interface{}, columns ...string) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Returning(value, columns...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Not(conds ...gen.Condition) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Not(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Or(conds ...gen.Condition) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Or(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Select(conds ...field.Expr) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Select(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Where(conds ...gen.Condition) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Where(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Order(conds ...field.Expr) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Order(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Distinct(cols ...field.Expr) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Distinct(cols...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Omit(cols ...field.Expr) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Omit(cols...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Join(table schema.Tabler, on ...field.Expr) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Join(table, on...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) LeftJoin(table schema.Tabler, on ...field.Expr) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.LeftJoin(table, on...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) RightJoin(table schema.Tabler, on ...field.Expr) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.RightJoin(table, on...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Group(cols ...field.Expr) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Group(cols...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Having(conds ...gen.Condition) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Having(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Limit(limit int) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Limit(limit))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Offset(offset int) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Offset(offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Scopes(funcs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Unscoped() *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Unscoped())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Create(values ...*models.BalanceActivity) error {
|
||||||
|
if len(values) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return b.DO.Create(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) CreateInBatches(values []*models.BalanceActivity, batchSize int) error {
|
||||||
|
return b.DO.CreateInBatches(values, batchSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save : !!! underlying implementation is different with GORM
|
||||||
|
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
|
||||||
|
func (b balanceActivityDo) Save(values ...*models.BalanceActivity) error {
|
||||||
|
if len(values) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return b.DO.Save(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) First() (*models.BalanceActivity, error) {
|
||||||
|
if result, err := b.DO.First(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*models.BalanceActivity), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Take() (*models.BalanceActivity, error) {
|
||||||
|
if result, err := b.DO.Take(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*models.BalanceActivity), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Last() (*models.BalanceActivity, error) {
|
||||||
|
if result, err := b.DO.Last(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*models.BalanceActivity), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Find() ([]*models.BalanceActivity, error) {
|
||||||
|
result, err := b.DO.Find()
|
||||||
|
return result.([]*models.BalanceActivity), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.BalanceActivity, err error) {
|
||||||
|
buf := make([]*models.BalanceActivity, 0, batchSize)
|
||||||
|
err = b.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
|
||||||
|
defer func() { results = append(results, buf...) }()
|
||||||
|
return fc(tx, batch)
|
||||||
|
})
|
||||||
|
return results, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) FindInBatches(result *[]*models.BalanceActivity, batchSize int, fc func(tx gen.Dao, batch int) error) error {
|
||||||
|
return b.DO.FindInBatches(result, batchSize, fc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Attrs(attrs ...field.AssignExpr) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Attrs(attrs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Assign(attrs ...field.AssignExpr) *balanceActivityDo {
|
||||||
|
return b.withDO(b.DO.Assign(attrs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Joins(fields ...field.RelationField) *balanceActivityDo {
|
||||||
|
for _, _f := range fields {
|
||||||
|
b = *b.withDO(b.DO.Joins(_f))
|
||||||
|
}
|
||||||
|
return &b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Preload(fields ...field.RelationField) *balanceActivityDo {
|
||||||
|
for _, _f := range fields {
|
||||||
|
b = *b.withDO(b.DO.Preload(_f))
|
||||||
|
}
|
||||||
|
return &b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) FirstOrInit() (*models.BalanceActivity, error) {
|
||||||
|
if result, err := b.DO.FirstOrInit(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*models.BalanceActivity), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) FirstOrCreate() (*models.BalanceActivity, error) {
|
||||||
|
if result, err := b.DO.FirstOrCreate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*models.BalanceActivity), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) FindByPage(offset int, limit int) (result []*models.BalanceActivity, count int64, err error) {
|
||||||
|
result, err = b.Offset(offset).Limit(limit).Find()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if size := len(result); 0 < limit && 0 < size && size < limit {
|
||||||
|
count = int64(size + offset)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err = b.Offset(-1).Limit(-1).Count()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
|
||||||
|
count, err = b.Count()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = b.Offset(offset).Limit(limit).Scan(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Scan(result interface{}) (err error) {
|
||||||
|
return b.DO.Scan(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b balanceActivityDo) Delete(models ...*models.BalanceActivity) (result gen.ResultInfo, err error) {
|
||||||
|
return b.DO.Delete(models)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *balanceActivityDo) withDO(do gen.Dao) *balanceActivityDo {
|
||||||
|
b.DO = *do.(*gen.DO)
|
||||||
|
return b
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ var (
|
|||||||
Admin *admin
|
Admin *admin
|
||||||
AdminRole *adminRole
|
AdminRole *adminRole
|
||||||
Announcement *announcement
|
Announcement *announcement
|
||||||
|
BalanceActivity *balanceActivity
|
||||||
Bill *bill
|
Bill *bill
|
||||||
Channel *channel
|
Channel *channel
|
||||||
Client *client
|
Client *client
|
||||||
@@ -57,6 +58,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
|
|||||||
Admin = &Q.Admin
|
Admin = &Q.Admin
|
||||||
AdminRole = &Q.AdminRole
|
AdminRole = &Q.AdminRole
|
||||||
Announcement = &Q.Announcement
|
Announcement = &Q.Announcement
|
||||||
|
BalanceActivity = &Q.BalanceActivity
|
||||||
Bill = &Q.Bill
|
Bill = &Q.Bill
|
||||||
Channel = &Q.Channel
|
Channel = &Q.Channel
|
||||||
Client = &Q.Client
|
Client = &Q.Client
|
||||||
@@ -95,6 +97,7 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
|
|||||||
Admin: newAdmin(db, opts...),
|
Admin: newAdmin(db, opts...),
|
||||||
AdminRole: newAdminRole(db, opts...),
|
AdminRole: newAdminRole(db, opts...),
|
||||||
Announcement: newAnnouncement(db, opts...),
|
Announcement: newAnnouncement(db, opts...),
|
||||||
|
BalanceActivity: newBalanceActivity(db, opts...),
|
||||||
Bill: newBill(db, opts...),
|
Bill: newBill(db, opts...),
|
||||||
Channel: newChannel(db, opts...),
|
Channel: newChannel(db, opts...),
|
||||||
Client: newClient(db, opts...),
|
Client: newClient(db, opts...),
|
||||||
@@ -134,6 +137,7 @@ type Query struct {
|
|||||||
Admin admin
|
Admin admin
|
||||||
AdminRole adminRole
|
AdminRole adminRole
|
||||||
Announcement announcement
|
Announcement announcement
|
||||||
|
BalanceActivity balanceActivity
|
||||||
Bill bill
|
Bill bill
|
||||||
Channel channel
|
Channel channel
|
||||||
Client client
|
Client client
|
||||||
@@ -174,6 +178,7 @@ func (q *Query) clone(db *gorm.DB) *Query {
|
|||||||
Admin: q.Admin.clone(db),
|
Admin: q.Admin.clone(db),
|
||||||
AdminRole: q.AdminRole.clone(db),
|
AdminRole: q.AdminRole.clone(db),
|
||||||
Announcement: q.Announcement.clone(db),
|
Announcement: q.Announcement.clone(db),
|
||||||
|
BalanceActivity: q.BalanceActivity.clone(db),
|
||||||
Bill: q.Bill.clone(db),
|
Bill: q.Bill.clone(db),
|
||||||
Channel: q.Channel.clone(db),
|
Channel: q.Channel.clone(db),
|
||||||
Client: q.Client.clone(db),
|
Client: q.Client.clone(db),
|
||||||
@@ -221,6 +226,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
|
|||||||
Admin: q.Admin.replaceDB(db),
|
Admin: q.Admin.replaceDB(db),
|
||||||
AdminRole: q.AdminRole.replaceDB(db),
|
AdminRole: q.AdminRole.replaceDB(db),
|
||||||
Announcement: q.Announcement.replaceDB(db),
|
Announcement: q.Announcement.replaceDB(db),
|
||||||
|
BalanceActivity: q.BalanceActivity.replaceDB(db),
|
||||||
Bill: q.Bill.replaceDB(db),
|
Bill: q.Bill.replaceDB(db),
|
||||||
Channel: q.Channel.replaceDB(db),
|
Channel: q.Channel.replaceDB(db),
|
||||||
Client: q.Client.replaceDB(db),
|
Client: q.Client.replaceDB(db),
|
||||||
@@ -258,6 +264,7 @@ type queryCtx struct {
|
|||||||
Admin *adminDo
|
Admin *adminDo
|
||||||
AdminRole *adminRoleDo
|
AdminRole *adminRoleDo
|
||||||
Announcement *announcementDo
|
Announcement *announcementDo
|
||||||
|
BalanceActivity *balanceActivityDo
|
||||||
Bill *billDo
|
Bill *billDo
|
||||||
Channel *channelDo
|
Channel *channelDo
|
||||||
Client *clientDo
|
Client *clientDo
|
||||||
@@ -295,6 +302,7 @@ func (q *Query) WithContext(ctx context.Context) *queryCtx {
|
|||||||
Admin: q.Admin.WithContext(ctx),
|
Admin: q.Admin.WithContext(ctx),
|
||||||
AdminRole: q.AdminRole.WithContext(ctx),
|
AdminRole: q.AdminRole.WithContext(ctx),
|
||||||
Announcement: q.Announcement.WithContext(ctx),
|
Announcement: q.Announcement.WithContext(ctx),
|
||||||
|
BalanceActivity: q.BalanceActivity.WithContext(ctx),
|
||||||
Bill: q.Bill.WithContext(ctx),
|
Bill: q.Bill.WithContext(ctx),
|
||||||
Channel: q.Channel.WithContext(ctx),
|
Channel: q.Channel.WithContext(ctx),
|
||||||
Client: q.Client.WithContext(ctx),
|
Client: q.Client.WithContext(ctx),
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ func clientRouter(api fiber.Router) {
|
|||||||
client := api
|
client := api
|
||||||
|
|
||||||
// 验证短信令牌
|
// 验证短信令牌
|
||||||
client.Post("/sms/verify", handlers.SmsCode)
|
client.Post("/verify/sms", handlers.SmsCode)
|
||||||
|
|
||||||
// 套餐定价查询
|
// 套餐定价查询
|
||||||
resource := client.Group("/resource")
|
resource := client.Group("/resource")
|
||||||
@@ -159,11 +159,13 @@ func adminRouter(api fiber.Router) {
|
|||||||
// user 用户
|
// user 用户
|
||||||
var user = api.Group("/user")
|
var user = api.Group("/user")
|
||||||
user.Post("/page", handlers.PageUserByAdmin)
|
user.Post("/page", handlers.PageUserByAdmin)
|
||||||
|
user.Post("/get", handlers.GetUserByAdmin)
|
||||||
user.Post("/create", handlers.CreateUserByAdmin)
|
user.Post("/create", handlers.CreateUserByAdmin)
|
||||||
user.Post("/update", handlers.UpdateUserByAdmin)
|
user.Post("/update", handlers.UpdateUserByAdmin)
|
||||||
user.Post("/remove", handlers.RemoveUserByAdmin)
|
user.Post("/remove", handlers.RemoveUserByAdmin)
|
||||||
|
|
||||||
user.Post("/bind", handlers.BindAdmin)
|
user.Post("/bind", handlers.BindAdmin)
|
||||||
|
user.Post("/update/balance", handlers.UpdateUserBalanceByAdmin)
|
||||||
|
|
||||||
// resource 套餐
|
// resource 套餐
|
||||||
var resource = api.Group("/resource")
|
var resource = api.Group("/resource")
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ func (s *adminService) UpdateAdmin(update *UpdateAdmin) error {
|
|||||||
// 更新管理员基本信息
|
// 更新管理员基本信息
|
||||||
if len(simples) > 0 {
|
if len(simples) > 0 {
|
||||||
_, err := tx.Admin.
|
_, err := tx.Admin.
|
||||||
Where(tx.Admin.ID.Eq(update.Id)).
|
Where(tx.Admin.ID.Eq(update.Id), tx.Admin.Username.Neq("admin")).
|
||||||
UpdateSimple(simples...)
|
UpdateSimple(simples...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -154,6 +154,6 @@ func (s *adminService) UpdateAdmin(update *UpdateAdmin) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *adminService) RemoveAdmin(id int32) error {
|
func (s *adminService) RemoveAdmin(id int32) error {
|
||||||
_, err := q.Admin.Where(q.Admin.ID.Eq(id)).UpdateColumn(q.Admin.DeletedAt, time.Now())
|
_, err := q.Admin.Where(q.Admin.ID.Eq(id), q.Admin.Username.Neq("admin")).UpdateColumn(q.Admin.DeletedAt, time.Now())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ var Coupon = &couponService{}
|
|||||||
type couponService struct{}
|
type couponService struct{}
|
||||||
|
|
||||||
func (s *couponService) All() (result []*m.Coupon, err error) {
|
func (s *couponService) All() (result []*m.Coupon, err error) {
|
||||||
return q.Coupon.Find()
|
return q.Coupon.Order(q.Coupon.CreatedAt.Desc()).Find()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *couponService) Page(req *core.PageReq) (result []*m.Coupon, count int64, err error) {
|
func (s *couponService) Page(req *core.PageReq) (result []*m.Coupon, count int64, err error) {
|
||||||
return q.Coupon.FindByPage(req.GetOffset(), req.GetLimit())
|
return q.Coupon.Order(q.Coupon.CreatedAt.Desc()).FindByPage(req.GetOffset(), req.GetLimit())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *couponService) Create(data CreateCouponData) error {
|
func (s *couponService) Create(data CreateCouponData) error {
|
||||||
|
|||||||
@@ -15,5 +15,5 @@ func (r *permissionService) ListPermissions() (result []*m.Permission, err error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *permissionService) PagePermissions(req core.PageReq) (result []*m.Permission, count int64, err error) {
|
func (p *permissionService) PagePermissions(req core.PageReq) (result []*m.Permission, count int64, err error) {
|
||||||
return q.Permission.FindByPage(req.GetOffset(), req.GetLimit())
|
return q.Permission.Order(q.Permission.Sort).FindByPage(req.GetOffset(), req.GetLimit())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ func (s *productService) GetPrice(code string) {
|
|||||||
|
|
||||||
// 获取所有产品
|
// 获取所有产品
|
||||||
func (s *productService) AllProducts() ([]*m.Product, error) {
|
func (s *productService) AllProducts() ([]*m.Product, error) {
|
||||||
return q.Product.Find()
|
return q.Product.
|
||||||
|
Order(q.Product.Sort.Asc(), q.Product.CreatedAt.Desc()).
|
||||||
|
Find()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增产品
|
// 新增产品
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ var ProductDiscount = &productDiscountService{}
|
|||||||
type productDiscountService struct{}
|
type productDiscountService struct{}
|
||||||
|
|
||||||
func (s *productDiscountService) All() (result []*m.ProductDiscount, err error) {
|
func (s *productDiscountService) All() (result []*m.ProductDiscount, err error) {
|
||||||
return q.ProductDiscount.Find()
|
return q.ProductDiscount.Order(q.ProductDiscount.CreatedAt.Desc()).Find()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *productDiscountService) Page(req *core.PageReq) (result []*m.ProductDiscount, count int64, err error) {
|
func (s *productDiscountService) Page(req *core.PageReq) (result []*m.ProductDiscount, count int64, err error) {
|
||||||
return q.ProductDiscount.FindByPage(req.GetOffset(), req.GetLimit())
|
return q.ProductDiscount.Order(q.ProductDiscount.CreatedAt.Desc()).FindByPage(req.GetOffset(), req.GetLimit())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *productDiscountService) Create(data CreateProductDiscountData) (err error) {
|
func (s *productDiscountService) Create(data CreateProductDiscountData) (err error) {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ func (s *productSkuService) All(product_code string) (result []*m.ProductSku, er
|
|||||||
Joins(q.ProductSku.Product).
|
Joins(q.ProductSku.Product).
|
||||||
Where(q.Product.As("Product").Code.Eq(product_code)).
|
Where(q.Product.As("Product").Code.Eq(product_code)).
|
||||||
Select(q.ProductSku.ALL).
|
Select(q.ProductSku.ALL).
|
||||||
|
Order(q.ProductSku.CreatedAt.Desc()).
|
||||||
Find()
|
Find()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ func (s *productSkuService) Page(req *core.PageReq, productId *int32) (result []
|
|||||||
return q.ProductSku.
|
return q.ProductSku.
|
||||||
Joins(q.ProductSku.Discount).
|
Joins(q.ProductSku.Discount).
|
||||||
Where(do...).
|
Where(do...).
|
||||||
|
Order(q.ProductSku.CreatedAt.Desc()).
|
||||||
FindByPage(req.GetOffset(), req.GetLimit())
|
FindByPage(req.GetOffset(), req.GetLimit())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,21 +26,10 @@ func (s *resourceService) CreateResourceByBalance(user *m.User, data *CreateReso
|
|||||||
return core.NewServErr("获取产品支付信息失败", err)
|
return core.NewServErr("获取产品支付信息失败", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newBalance := user.Balance.Sub(detail.Actual)
|
|
||||||
if newBalance.IsNegative() {
|
|
||||||
return ErrBalanceNotEnough
|
|
||||||
}
|
|
||||||
|
|
||||||
return q.Q.Transaction(func(q *q.Query) error {
|
return q.Q.Transaction(func(q *q.Query) error {
|
||||||
|
|
||||||
// 更新用户余额
|
// 更新用户余额
|
||||||
_, err = q.User.
|
if err := User.UpdateBalance(q, user, detail.Actual.Neg(), "余额购买产品", nil); err != nil {
|
||||||
Where(
|
|
||||||
q.User.ID.Eq(user.ID),
|
|
||||||
q.User.Balance.Eq(user.Balance),
|
|
||||||
).
|
|
||||||
UpdateSimple(q.User.Balance.Value(newBalance))
|
|
||||||
if err != nil {
|
|
||||||
return core.NewServErr("更新用户余额失败", err)
|
return core.NewServErr("更新用户余额失败", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,13 +262,21 @@ func (data *CreateResourceData) TradeDetail(user *m.User) (*TradeDetail, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var discountId *int32 = nil
|
||||||
|
if discount != nil {
|
||||||
|
discountId = &discount.ID
|
||||||
|
}
|
||||||
|
var couponId *int32 = nil
|
||||||
|
if coupon != nil {
|
||||||
|
couponId = &coupon.ID
|
||||||
|
}
|
||||||
return &TradeDetail{
|
return &TradeDetail{
|
||||||
data,
|
data,
|
||||||
m.TradeTypePurchase,
|
m.TradeTypePurchase,
|
||||||
sku.Name,
|
sku.Name,
|
||||||
amount, actual,
|
amount, actual,
|
||||||
&discount.ID, discount,
|
discountId, discount,
|
||||||
&coupon.ID, coupon,
|
couponId, coupon,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/gob"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -26,13 +27,18 @@ import (
|
|||||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gob.Register(&CreateResourceData{})
|
||||||
|
gob.Register(&UpdateBalanceData{})
|
||||||
|
}
|
||||||
|
|
||||||
var Trade = &tradeService{}
|
var Trade = &tradeService{}
|
||||||
|
|
||||||
type tradeService struct {
|
type tradeService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建交易
|
// 创建交易
|
||||||
func (s *tradeService) Create(user *m.User, tradeData *CreateTradeData, productData *CreateResourceData) (*CreateTradeResult, error) {
|
func (s *tradeService) Create(user *m.User, tradeData *CreateTradeData, productData ProductData) (*CreateTradeResult, error) {
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return nil, core.NewBizErr("用户未登录")
|
return nil, core.NewBizErr("用户未登录")
|
||||||
}
|
}
|
||||||
@@ -196,15 +202,12 @@ func (s *tradeService) Create(user *m.User, tradeData *CreateTradeData, productD
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 缓存产品数据
|
// 缓存产品数据
|
||||||
serialized, err := json.Marshal(detail)
|
w := bytes.Buffer{}
|
||||||
if err != nil {
|
gob.NewEncoder(&w).Encode(detail)
|
||||||
return nil, core.NewServErr("序列化产品信息失败", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = g.Redis.Set(
|
err = g.Redis.Set(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
tradeProductKey(tradeNo),
|
tradeProductKey(tradeNo),
|
||||||
serialized,
|
w.Bytes(),
|
||||||
expireIn,
|
expireIn,
|
||||||
).Err()
|
).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -267,14 +270,15 @@ func (s *tradeService) OnCompleteTrade(user *m.User, interNo string, outerNo str
|
|||||||
case m.TradeStatusPending:
|
case m.TradeStatusPending:
|
||||||
}
|
}
|
||||||
|
|
||||||
// 恢复购买信息
|
// 恢复购买信息;如果反序列化失败,检查开头 init 函数中是否注册了对应的 struct 类型
|
||||||
detailStr, err := g.Redis.Get(context.Background(), tradeProductKey(interNo)).Result()
|
detailBytes, err := g.Redis.Get(context.Background(), tradeProductKey(interNo)).Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return core.NewServErr("恢复购买信息失败", err)
|
return core.NewServErr("恢复购买信息失败", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var detail TradeDetail
|
var detail TradeDetail
|
||||||
if err := json.Unmarshal([]byte(detailStr), &detail); err != nil {
|
r := bytes.NewReader(detailBytes)
|
||||||
|
if err := gob.NewDecoder(r).Decode(&detail); err != nil {
|
||||||
return core.NewServErr("解析购买信息失败", err)
|
return core.NewServErr("解析购买信息失败", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +303,7 @@ func (s *tradeService) OnCompleteTrade(user *m.User, interNo string, outerNo str
|
|||||||
switch trade.Type {
|
switch trade.Type {
|
||||||
case m.TradeTypeRecharge:
|
case m.TradeTypeRecharge:
|
||||||
// 更新用户余额
|
// 更新用户余额
|
||||||
if err := User.UpdateBalance(q, user, detail.Actual); err != nil {
|
if err := User.UpdateBalance(q, user, detail.Actual, "充值余额", nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -605,12 +609,12 @@ type OnTradeCompletedData struct {
|
|||||||
*TradeSuccessResult
|
*TradeSuccessResult
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductInfo interface {
|
type ProductData interface {
|
||||||
TradeDetail(user *m.User) (*TradeDetail, error)
|
TradeDetail(user *m.User) (*TradeDetail, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TradeDetail struct {
|
type TradeDetail struct {
|
||||||
Product ProductInfo `json:"product"`
|
Product ProductData `json:"product"`
|
||||||
Type m.TradeType `json:"type"`
|
Type m.TradeType `json:"type"`
|
||||||
Subject string `json:"subject"`
|
Subject string `json:"subject"`
|
||||||
Amount decimal.Decimal `json:"amount"`
|
Amount decimal.Decimal `json:"amount"`
|
||||||
@@ -621,11 +625,6 @@ type TradeDetail struct {
|
|||||||
Coupon *m.Coupon `json:"-"` // 不应缓存
|
Coupon *m.Coupon `json:"-"` // 不应缓存
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompleteEvent interface {
|
|
||||||
Check(t m.TradeType) (ProductInfo, bool)
|
|
||||||
OnTradeComplete(info ProductInfo, trade *m.Trade) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type TradeErr string
|
type TradeErr string
|
||||||
|
|
||||||
func (e TradeErr) Error() string {
|
func (e TradeErr) Error() string {
|
||||||
|
|||||||
@@ -28,12 +28,28 @@ func (s *userService) Get(q *q.Query, uid int32) (*m.User, error) {
|
|||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *userService) UpdateBalance(q *q.Query, user *m.User, amount decimal.Decimal) error {
|
func (s *userService) UpdateBalanceByAdmin(user *m.User, newBalance decimal.Decimal, adminId *int32) error {
|
||||||
|
if user == nil {
|
||||||
|
return core.NewServErr("用户不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
amount := newBalance.Sub(user.Balance)
|
||||||
|
if amount.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.Q.Transaction(func(q *q.Query) error {
|
||||||
|
return s.UpdateBalance(q, user, amount, "管理员修改余额", adminId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *userService) UpdateBalance(q *q.Query, user *m.User, amount decimal.Decimal, remark string, adminId *int32) error {
|
||||||
balance := user.Balance.Add(amount)
|
balance := user.Balance.Add(amount)
|
||||||
if balance.IsNegative() {
|
if balance.IsNegative() {
|
||||||
return core.NewServErr("用户余额不足")
|
return core.NewServErr("用户余额不足")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新余额
|
||||||
_, err := q.User.
|
_, err := q.User.
|
||||||
Where(
|
Where(
|
||||||
q.User.ID.Eq(user.ID),
|
q.User.ID.Eq(user.ID),
|
||||||
@@ -46,6 +62,19 @@ func (s *userService) UpdateBalance(q *q.Query, user *m.User, amount decimal.Dec
|
|||||||
return core.NewServErr("更新用户余额失败", err)
|
return core.NewServErr("更新用户余额失败", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增动账记录
|
||||||
|
err = q.BalanceActivity.Create(&m.BalanceActivity{
|
||||||
|
UserID: user.ID,
|
||||||
|
AdminID: adminId,
|
||||||
|
Amount: amount.StringFixed(2),
|
||||||
|
BalancePrev: user.Balance.StringFixed(2),
|
||||||
|
BalanceCurr: balance.StringFixed(2),
|
||||||
|
Remark: &remark,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return core.NewServErr("新增动账记录失败", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user