12 Commits

60 changed files with 3003 additions and 506 deletions

57
.env.example Normal file
View File

@@ -0,0 +1,57 @@
# 应用配置
RUN_MODE=development
DEBUG_HTTP_DUMP=false
# 数据库配置
DB_HOST=127.0.0.1
DB_PORT=5432
DB_NAME=app
DB_USERNAME=dev
DB_PASSWORD=dev
# redis 配置
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
# otel 配置
OTEL_HOST=127.0.0.1
OTEL_PORT=4317
# 白银节点
BAIYIN_CLOUD_URL=
BAIYIN_TOKEN_URL=
# 京东实名
IDEN_ACCESS_KEY=
IDEN_SECRET_KEY=
IDEN_CALLBACK_URL=
# 支付宝(暂时弃用,但是需要配置)
ALIPAY_APP_ID=
ALIPAY_APP_PRIVATE_KEY=
ALIPAY_PUBLIC_KEY=
ALIPAY_API_CERT=
# 微信支付(暂时弃用,但是需要配置)
WECHATPAY_APP_ID=
WECHATPAY_MCH_ID=
WECHATPAY_MCH_PRIVATE_KEY_SERIAL=
WECHATPAY_MCH_PRIVATE_KEY=
WECHATPAY_PUBLIC_KEY_ID=
WECHATPAY_PUBLIC_KEY=
WECHATPAY_API_CERT=
WECHATPAY_CALLBACK_URL=
# 阿里云
ALIYUN_ACCESS_KEY=
ALIYUN_ACCESS_KEY_SECRET=
ALIYUN_SMS_SIGNATURE=
ALIYUN_SMS_TEMPLATE_LOGIN=
# 商福通
SFTPAY_ENABLE=
SFTPAY_APP_ID=
SFTPAY_ROUTE_ID=
SFTPAY_APP_PRIVATE_KEY=
SFTPAY_PUBLIC_KEY=
SFTPAY_RETURN_URL=

View File

@@ -19,7 +19,7 @@ WORKDIR /app
ENV TZ=Asia/Shanghai ENV TZ=Asia/Shanghai
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk add --no-cache ca-certificates tzdata RUN apk add --no-cache ca-certificates tzdata
COPY --from=builder /build/bin/platform_linux_amd64 /app/platform COPY --from=builder /build/bin/platform_linux_amd64 /app/platform

View File

@@ -1,5 +1,7 @@
## TODO ## TODO
交易信息持久化
用户请求需要检查数据权限 用户请求需要检查数据权限
用反射实现环境变量解析,以简化函数签名 用反射实现环境变量解析,以简化函数签名

View File

@@ -66,6 +66,7 @@ func main() {
m.Inquiry{}, m.Inquiry{},
m.ProductDiscount{}, m.ProductDiscount{},
m.BalanceActivity{}, m.BalanceActivity{},
m.CouponUser{},
) )
g.Execute() g.Execute()
} }

2
pkg/env/env.go vendored
View File

@@ -24,7 +24,6 @@ var (
SessionAccessExpire = 60 * 60 * 2 // 访问令牌过期时间,单位秒。默认 2 小时 SessionAccessExpire = 60 * 60 * 2 // 访问令牌过期时间,单位秒。默认 2 小时
SessionRefreshExpire = 60 * 60 * 24 * 7 // 刷新令牌过期时间,单位秒。默认 7 天 SessionRefreshExpire = 60 * 60 * 24 * 7 // 刷新令牌过期时间,单位秒。默认 7 天
DebugHttpDump = false // 是否打印请求和响应的原始数据 DebugHttpDump = false // 是否打印请求和响应的原始数据
DebugExternalChange = true // 是否实际执行外部非幂等接口调用,在开发调试时可以关闭,避免对外部数据产生影响
DbHost = "localhost" DbHost = "localhost"
DbPort = "5432" DbPort = "5432"
@@ -106,7 +105,6 @@ func Init() {
errs = append(errs, parse(&SessionAccessExpire, "SESSION_ACCESS_EXPIRE", true, nil)) errs = append(errs, parse(&SessionAccessExpire, "SESSION_ACCESS_EXPIRE", true, nil))
errs = append(errs, parse(&SessionRefreshExpire, "SESSION_REFRESH_EXPIRE", true, nil)) errs = append(errs, parse(&SessionRefreshExpire, "SESSION_REFRESH_EXPIRE", true, nil))
errs = append(errs, parse(&DebugHttpDump, "DEBUG_HTTP_DUMP", true, nil)) errs = append(errs, parse(&DebugHttpDump, "DEBUG_HTTP_DUMP", true, nil))
errs = append(errs, parse(&DebugExternalChange, "DEBUG_EXTERNAL_CHANGE", true, nil))
errs = append(errs, parse(&DbHost, "DB_HOST", true, nil)) errs = append(errs, parse(&DbHost, "DB_HOST", true, nil))
errs = append(errs, parse(&DbPort, "DB_PORT", true, nil)) errs = append(errs, parse(&DbPort, "DB_PORT", true, nil))

View File

@@ -53,6 +53,18 @@ func X[T comparable](v T) *T {
return &v return &v
} }
// N 零值视为 nil
func N[T comparable](v *T) *T {
if v == nil {
return nil
}
var zero T
if *v == zero {
return nil
}
return v
}
// ==================== // ====================
// 数组 // 数组
// ==================== // ====================
@@ -110,3 +122,21 @@ func CombineErrors(errs []error) error {
} }
return combinedErr return combinedErr
} }
// ====================
// 业务
// ====================
func MaskPhone(phone string) string {
if len(phone) < 11 {
return phone
}
return phone[:3] + "****" + phone[7:]
}
func MaskIdNo(idNo string) string {
if len(idNo) < 18 {
return idNo
}
return idNo[:3] + "*********" + idNo[14:]
}

View File

@@ -1,21 +1,269 @@
-- ==================== -- ====================
-- region 填充数据 -- region 客户端
-- ==================== -- ====================
insert into client (type, spec, name, client_id, client_secret, redirect_uri) values (1, 3, 'web', 'web', '$2a$10$Ss12mXQgpYyo1CKIZ3URouDm.Lc2KcYJzsvEK2PTIXlv6fHQht45a', ''); insert into client (type, spec, name, client_id, client_secret, redirect_uri) values (1, 3, 'web', 'web', '$2a$10$Ss12mXQgpYyo1CKIZ3URouDm.Lc2KcYJzsvEK2PTIXlv6fHQht45a', '');
insert into client (type, spec, name, client_id, client_secret, redirect_uri) values (1, 3, 'admin', 'admin', '$2a$10$dlfvX5Uf3iVsUWgwlb0Wt.oYsw/OEXgS.Aior3yoT63Ju7ZSsJr/2', ''); insert into client (type, spec, name, client_id, client_secret, redirect_uri) values (1, 3, 'admin', 'admin', '$2a$10$dlfvX5Uf3iVsUWgwlb0Wt.oYsw/OEXgS.Aior3yoT63Ju7ZSsJr/2', '');
insert into product (code, name, description) values ('short', '短效动态', '短效动态'); -- ====================
insert into product (code, name, description) values ('long', '长效动态', '长效动态'); -- region 管理员
insert into product (code, name, description) values ('static', '长效静态', '长效静态'); -- ====================
insert into admin (username, password, name, lock) values ('admin', '', '超级管理员', true);
-- ====================
-- region 产品
-- ====================
delete from product where true;
insert into product (code, name, description, sort) values ('short', '短效动态', '短效动态', 1);
insert into product (code, name, description, sort) values ('long', '长效动态', '长效动态', 2);
insert into product (code, name, description, sort) values ('static', '长效静态', '长效静态', 3);
-- ====================
-- region 套餐
-- ====================
delete from product_sku where true;
insert into product_sku (product_id, code, name, price, price_min, sort) values
((select id from product where code = 'short' and deleted_at is null), 'mode=quota&live=3&expire=0', '短效动态包量 3 分钟', 10.00, 10.00, 1),
((select id from product where code = 'short' and deleted_at is null), 'mode=quota&live=5&expire=0', '短效动态包量 5 分钟', 10.00, 10.00, 2),
((select id from product where code = 'short' and deleted_at is null), 'mode=quota&live=10&expire=0', '短效动态包量 10 分钟', 10.00, 10.00, 3),
((select id from product where code = 'short' and deleted_at is null), 'mode=quota&live=15&expire=0', '短效动态包量 15 分钟', 10.00, 10.00, 4),
((select id from product where code = 'short' and deleted_at is null), 'mode=quota&live=30&expire=0', '短效动态包量 30 分钟', 10.00, 10.00, 5),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=3&expire=7', '短效动态包时 3 分钟 7 天', 10.00, 10.00, 6),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=5&expire=7', '短效动态包时 5 分钟 7 天', 10.00, 10.00, 7),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=10&expire=7', '短效动态包时 10 分钟 7 天', 10.00, 10.00, 8),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=15&expire=7', '短效动态包时 15 分钟 7 天', 10.00, 10.00, 9),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=30&expire=7', '短效动态包时 30 分钟 7 天', 10.00, 10.00, 10),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=3&expire=15', '短效动态包时 3 分钟 15 天', 10.00, 10.00, 11),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=5&expire=15', '短效动态包时 5 分钟 15 天', 10.00, 10.00, 12),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=10&expire=15', '短效动态包时 10 分钟 15 天', 10.00, 10.00, 13),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=15&expire=15', '短效动态包时 15 分钟 15 天', 10.00, 10.00, 14),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=30&expire=15', '短效动态包时 30 分钟 15 天', 10.00, 10.00, 15),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=3&expire=30', '短效动态包时 3 分钟 30 天', 10.00, 10.00, 16),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=5&expire=30', '短效动态包时 5 分钟 30 天', 10.00, 10.00, 17),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=10&expire=30', '短效动态包时 10 分钟 30 天', 10.00, 10.00, 18),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=15&expire=30', '短效动态包时 15 分钟 30 天', 10.00, 10.00, 19),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=30&expire=30', '短效动态包时 30 分钟 30 天', 10.00, 10.00, 20),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=3&expire=90', '短效动态包时 3 分钟 90 天', 10.00, 10.00, 21),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=5&expire=90', '短效动态包时 5 分钟 90 天', 10.00, 10.00, 22),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=10&expire=90', '短效动态包时 10 分钟 90 天', 10.00, 10.00, 23),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=15&expire=90', '短效动态包时 15 分钟 90 天', 10.00, 10.00, 24),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=30&expire=90', '短效动态包时 30 分钟 90 天', 10.00, 10.00, 25),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=3&expire=180', '短效动态包时 3 分钟 180 天', 10.00, 10.00, 26),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=5&expire=180', '短效动态包时 5 分钟 180 天', 10.00, 10.00, 27),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=10&expire=180', '短效动态包时 10 分钟 180 天', 10.00, 10.00, 28),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=15&expire=180', '短效动态包时 15 分钟 180 天', 10.00, 10.00, 29),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=30&expire=180', '短效动态包时 30 分钟 180 天', 10.00, 10.00, 30),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=3&expire=365', '短效动态包时 3 分钟 365 天', 10.00, 10.00, 31),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=5&expire=365', '短效动态包时 5 分钟 365 天', 10.00, 10.00, 32),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=10&expire=365', '短效动态包时 10 分钟 365 天', 10.00, 10.00, 33),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=15&expire=365', '短效动态包时 15 分钟 365 天', 10.00, 10.00, 34),
((select id from product where code = 'short' and deleted_at is null), 'mode=time&live=30&expire=365', '短效动态包时 30 分钟 365 天', 10.00, 10.00, 35)
;
insert into product_sku (product_id, code, name, price, price_min, sort) values
((select id from product where code = 'long' and deleted_at is null), 'mode=quota&live=60&expire=0', '长效动态包量 1 小时', 10.00, 10.00, 1),
((select id from product where code = 'long' and deleted_at is null), 'mode=quota&live=240&expire=0', '长效动态包量 4 小时', 10.00, 10.00, 2),
((select id from product where code = 'long' and deleted_at is null), 'mode=quota&live=480&expire=0', '长效动态包量 8 小时', 10.00, 10.00, 3),
((select id from product where code = 'long' and deleted_at is null), 'mode=quota&live=720&expire=0', '长效动态包量 12 小时', 10.00, 10.00, 4),
((select id from product where code = 'long' and deleted_at is null), 'mode=quota&live=1440&expire=0', '长效动态包量 24 小时', 10.00, 10.00, 5),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=60&expire=7', '长效动态包时 1 小时 7 天', 10.00, 10.00, 6),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=240&expire=7', '长效动态包时 4 小时 7 天', 10.00, 10.00, 7),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=480&expire=7', '长效动态包时 8 小时 7 天', 10.00, 10.00, 8),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=720&expire=7', '长效动态包时 12 小时 7 天', 10.00, 10.00, 9),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=1440&expire=7', '长效动态包时 24 小时 7 天', 10.00, 10.00, 10),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=60&expire=15', '长效动态包时 1 小时 15 天', 10.00, 10.00, 11),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=240&expire=15', '长效动态包时 4 小时 15 天', 10.00, 10.00, 12),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=480&expire=15', '长效动态包时 8 小时 15 天', 10.00, 10.00, 13),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=720&expire=15', '长效动态包时 12 小时 15 天', 10.00, 10.00, 14),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=1440&expire=15', '长效动态包时 24 小时 15 天', 10.00, 10.00, 15),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=60&expire=30', '长效动态包时 1 小时 30 天', 10.00, 10.00, 16),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=240&expire=30', '长效动态包时 4 小时 30 天', 10.00, 10.00, 17),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=480&expire=30', '长效动态包时 8 小时 30 天', 10.00, 10.00, 18),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=720&expire=30', '长效动态包时 12 小时 30 天', 10.00, 10.00, 19),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=1440&expire=30', '长效动态包时 24 小时 30 天', 10.00, 10.00, 20),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=60&expire=90', '长效动态包时 1 小时 90 天', 10.00, 10.00, 21),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=240&expire=90', '长效动态包时 4 小时 90 天', 10.00, 10.00, 22),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=480&expire=90', '长效动态包时 8 小时 90 天', 10.00, 10.00, 23),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=720&expire=90', '长效动态包时 12 小时 90 天', 10.00, 10.00, 24),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=1440&expire=90', '长效动态包时 24 小时 90 天', 10.00, 10.00, 25),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=60&expire=180', '长效动态包时 1 小时 180 天', 10.00, 10.00, 26),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=240&expire=180', '长效动态包时 4 小时 180 天', 10.00, 10.00, 27),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=480&expire=180', '长效动态包时 8 小时 180 天', 10.00, 10.00, 28),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=720&expire=180', '长效动态包时 12 小时 180 天', 10.00, 10.00, 29),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=1440&expire=180','长效动态包时 24 小时 180 天', 10.00, 10.00, 30),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=60&expire=365', '长效动态包时 1 小时 365 天', 10.00, 10.00, 31),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=240&expire=365', '长效动态包时 4 小时 365 天', 10.00, 10.00, 32),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=480&expire=365', '长效动态包时 8 小时 365 天', 10.00, 10.00, 33),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=720&expire=365', '长效动态包时 12 小时 365 天', 10.00, 10.00, 34),
((select id from product where code = 'long' and deleted_at is null), 'mode=time&live=1440&expire=365','长效动态包时 24 小时 365 天', 10.00, 10.00, 35)
;
-- ====================
-- region 权限
-- ====================
delete from permission where true; delete from permission where true;
insert into permission
(name, description) -- --------------------------
values -- level 1
('permission:read', '读取权限列表'), -- --------------------------
('permission:write', '写入权限'), insert into permission (name, description, sort) values
('admin-role:read', '读取管理员角色列表'), ('permission', '权限', 1),
('admin-role:write', '写入管理员角色') ('admin_role', '管理员角色', 2),
; ('admin', '管理员', 3),
('product', '产品', 4),
('product_sku', '产品套餐', 5),
('discount', '折扣', 6),
('resource', '用户套餐', 7),
('user', '用户', 8),
('coupon', '优惠券', 9),
('batch', '批次', 10),
('channel', 'IP', 11),
('trade', '交易', 12),
('bill', '账单', 13),
('balance_activity', '余额变动', 14);
-- --------------------------
-- level 2
-- --------------------------
-- permission 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'permission' and deleted_at is null), 'permission:read', '读取权限列表', 1),
((select id from permission where name = 'permission' and deleted_at is null), 'permission:write', '写入权限', 2);
-- admin_role 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'admin_role' and deleted_at is null), 'admin_role:read', '读取管理员角色列表', 1),
((select id from permission where name = 'admin_role' and deleted_at is null), 'admin_role:write', '写入管理员角色', 2);
-- admin 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'admin' and deleted_at is null), 'admin:read', '读取管理员列表', 1),
((select id from permission where name = 'admin' and deleted_at is null), 'admin:write', '写入管理员', 2);
-- product 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'product' and deleted_at is null), 'product:read', '读取产品列表', 1),
((select id from permission where name = 'product' and deleted_at is null), 'product:write', '写入产品', 2);
-- product_sku 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'product_sku' and deleted_at is null), 'product_sku:read', '读取产品套餐列表', 1),
((select id from permission where name = 'product_sku' and deleted_at is null), 'product_sku:write', '写入产品套餐', 2);
-- discount 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'discount' and deleted_at is null), 'discount:read', '读取折扣列表', 1),
((select id from permission where name = 'discount' and deleted_at is null), 'discount:write', '写入折扣', 2);
-- resource 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'resource' and deleted_at is null), 'resource:read', '读取用户套餐列表', 1),
((select id from permission where name = 'resource' and deleted_at is null), 'resource:write', '写入用户套餐', 2),
((select id from permission where name = 'resource' and deleted_at is null), 'resource:short', '短效动态套餐', 3),
((select id from permission where name = 'resource' and deleted_at is null), 'resource:long', '长效动态套餐', 4);
-- user 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'user' and deleted_at is null), 'user:read', '读取用户列表', 1),
((select id from permission where name = 'user' and deleted_at is null), 'user:write', '写入用户', 2);
-- coupon 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'coupon' and deleted_at is null), 'coupon:read', '读取优惠券列表', 1),
((select id from permission where name = 'coupon' and deleted_at is null), 'coupon:write', '写入优惠券', 2);
-- batch 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'batch' and deleted_at is null), 'batch:read', '读取批次列表', 1),
((select id from permission where name = 'batch' and deleted_at is null), 'batch:write', '写入批次', 2);
-- channel 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'channel' and deleted_at is null), 'channel:read', '读取 IP 列表', 1),
((select id from permission where name = 'channel' and deleted_at is null), 'channel:write', '写入 IP', 2);
-- trade 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'trade' and deleted_at is null), 'trade:read', '读取交易列表', 1),
((select id from permission where name = 'trade' and deleted_at is null), 'trade:write', '写入交易', 2);
-- bill 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'bill' and deleted_at is null), 'bill:read', '读取账单列表', 1),
((select id from permission where name = 'bill' and deleted_at is null), 'bill:write', '写入账单', 2);
-- balance_activity 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'balance_activity' and deleted_at is null), 'balance_activity:read', '读取余额变动列表', 1);
-- --------------------------
-- level 3
-- --------------------------
-- product_sku:write 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'product_sku:write' and deleted_at is null), 'product_sku:write:status', '更改产品套餐状态', 1);
-- resource:short 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'resource:short' and deleted_at is null), 'resource:short:read', '读取用户短效动态套餐列表', 1);
-- resource:long 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'resource:long' and deleted_at is null), 'resource:long:read', '读取用户长效动态套餐列表', 1);
-- user:read 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'user:read' and deleted_at is null), 'user:read:one', '读取单个用户', 1),
((select id from permission where name = 'user:read' and deleted_at is null), 'user:read:not_bind', '读取未绑定管理员的用户列表', 2);
-- user:write 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'user:write' and deleted_at is null), 'user:write:balance', '写入用户余额', 1),
((select id from permission where name = 'user:write' and deleted_at is null), 'user:write:bind', '用户认领', 2);
-- batch:read 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'batch:read' and deleted_at is null), 'batch:read:of_user', '读取指定用户的批次列表', 1);
-- channel:read 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'channel:read' and deleted_at is null), 'channel:read:of_user', '读取指定用户的 IP 列表', 1);
-- trade:read 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'trade:read' and deleted_at is null), 'trade:read:of_user', '读取指定用户的交易列表', 1);
-- bill:read 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'bill:read' and deleted_at is null), 'bill:read:of_user', '读取指定用户的账单列表', 1);
-- balance_activity:read 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'balance_activity:read' and deleted_at is null), 'balance_activity:read:of_user', '读取指定用户的余额变动列表', 1);
-- --------------------------
-- level 4
-- --------------------------
-- user:write:balance 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'user:write:balance' and deleted_at is null), 'user:write:balance:inc', '增加用户余额', 1),
((select id from permission where name = 'user:write:balance' and deleted_at is null), 'user:write:balance:dec', '减少用户余额', 2);
-- resource:short:read 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'resource:short:read' and deleted_at is null), 'resource:short:read:of_user', '读取指定用户的短效动态套餐列表', 1);
-- resource:long:read 子权限
insert into permission (parent_id, name, description, sort) values
((select id from permission where name = 'resource:long:read' and deleted_at is null), 'resource:long:read:of_user', '读取指定用户的长效动态套餐列表', 1);
-- endregion -- endregion

View File

@@ -196,6 +196,7 @@ create table admin (
last_login timestamptz, last_login timestamptz,
last_login_ip inet, last_login_ip inet,
last_login_ua text, last_login_ua text,
lock bool not null default false,
created_at timestamptz default current_timestamp, created_at timestamptz default current_timestamp,
updated_at timestamptz default current_timestamp, updated_at timestamptz default current_timestamp,
deleted_at timestamptz deleted_at timestamptz
@@ -217,6 +218,7 @@ comment on column admin.status is '状态0-禁用1-正常';
comment on column admin.last_login is '最后登录时间'; comment on column admin.last_login is '最后登录时间';
comment on column admin.last_login_ip is '最后登录地址'; comment on column admin.last_login_ip is '最后登录地址';
comment on column admin.last_login_ua is '最后登录代理'; comment on column admin.last_login_ua is '最后登录代理';
comment on column admin.lock is '是否锁定编辑';
comment on column admin.created_at is '创建时间'; comment on column admin.created_at is '创建时间';
comment on column admin.updated_at is '更新时间'; comment on column admin.updated_at is '更新时间';
comment on column admin.deleted_at is '删除时间'; comment on column admin.deleted_at is '删除时间';
@@ -757,6 +759,9 @@ create table product_sku (
code text not null unique, code text not null unique,
name text not null, name text not null,
price decimal not null, price decimal not null,
price_min decimal not null,
status int not null default 1,
sort int not null default 0,
created_at timestamptz default current_timestamp, created_at timestamptz default current_timestamp,
updated_at timestamptz default current_timestamp, updated_at timestamptz default current_timestamp,
deleted_at timestamptz deleted_at timestamptz
@@ -772,7 +777,9 @@ comment on column product_sku.product_id is '产品ID';
comment on column product_sku.discount_id is '折扣ID'; comment on column product_sku.discount_id is '折扣ID';
comment on column product_sku.code is 'SKU 代码:格式为 key=value,key=value,...其中key:value 是 SKU 的属性,多个属性用逗号分隔'; comment on column product_sku.code is 'SKU 代码:格式为 key=value,key=value,...其中key:value 是 SKU 的属性,多个属性用逗号分隔';
comment on column product_sku.name is 'SKU 可读名称'; comment on column product_sku.name is 'SKU 可读名称';
comment on column product_sku.price is '定价'; comment on column product_sku.price_min is '最低价格';
comment on column product_sku.status is 'SKU状态0-禁用1-正常';
comment on column product_sku.sort is '排序';
comment on column product_sku.created_at is '创建时间'; comment on column product_sku.created_at is '创建时间';
comment on column product_sku.updated_at is '更新时间'; comment on column product_sku.updated_at is '更新时间';
comment on column product_sku.deleted_at is '删除时间'; comment on column product_sku.deleted_at is '删除时间';
@@ -984,7 +991,7 @@ create table bill (
trade_id int, trade_id int,
resource_id int, resource_id int,
refund_id int, refund_id int,
coupon_id int, coupon_user_id int,
bill_no text not null, bill_no text not null,
info text, info text,
type int not null, type int not null,
@@ -999,7 +1006,7 @@ create index idx_bill_user_id on bill (user_id) where deleted_at is null;
create index idx_bill_trade_id on bill (trade_id) where deleted_at is null; create index idx_bill_trade_id on bill (trade_id) where deleted_at is null;
create index idx_bill_resource_id on bill (resource_id) where deleted_at is null; create index idx_bill_resource_id on bill (resource_id) where deleted_at is null;
create index idx_bill_refund_id on bill (refund_id) where deleted_at is null; create index idx_bill_refund_id on bill (refund_id) where deleted_at is null;
create index idx_bill_coupon_id on bill (coupon_id) where deleted_at is null; create index idx_bill_coupon_id on bill (coupon_user_id) where deleted_at is null;
create index idx_bill_created_at on bill (created_at) where deleted_at is null; create index idx_bill_created_at on bill (created_at) where deleted_at is null;
-- bill表字段注释 -- bill表字段注释
@@ -1009,6 +1016,7 @@ comment on column bill.user_id is '用户ID';
comment on column bill.trade_id is '订单ID'; comment on column bill.trade_id is '订单ID';
comment on column bill.resource_id is '套餐ID'; comment on column bill.resource_id is '套餐ID';
comment on column bill.refund_id is '退款ID'; comment on column bill.refund_id is '退款ID';
comment on column bill.coupon_user_id is '优惠券发放ID';
comment on column bill.bill_no is '易读账单号'; comment on column bill.bill_no is '易读账单号';
comment on column bill.info is '产品可读信息'; comment on column bill.info is '产品可读信息';
comment on column bill.type is '账单类型1-消费2-退款3-充值'; comment on column bill.type is '账单类型1-消费2-退款3-充值';
@@ -1051,36 +1059,59 @@ 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 (
id int generated by default as identity primary key, id int generated by default as identity primary key,
user_id int, name text not null,
code text not null, amount decimal(12, 2) not null default 0,
remark text, min_amount decimal(12, 2) not null default 0,
amount decimal(12, 2) not null default 0, count int not null default 0,
min_amount decimal(12, 2) not null default 0, status int not null default 1,
status int not null default 0, expire_type int not null default 0,
expire_at timestamptz, expire_at timestamptz,
created_at timestamptz default current_timestamp, expire_in int,
updated_at timestamptz default current_timestamp, created_at timestamptz default current_timestamp,
deleted_at timestamptz updated_at timestamptz default current_timestamp,
deleted_at timestamptz
); );
create index idx_coupon_user_id on coupon (user_id) where deleted_at is null;
create index idx_coupon_code on coupon (code) where deleted_at is null;
create index idx_coupon_created_at on coupon (created_at) where deleted_at is null;
-- coupon表字段注释 -- coupon表字段注释
comment on table coupon is '优惠券表'; comment on table coupon is '优惠券表';
comment on column coupon.id is '优惠券ID'; comment on column coupon.id is '优惠券ID';
comment on column coupon.user_id is '用户ID'; comment on column coupon.name is '优惠券名称';
comment on column coupon.code is '优惠券代码';
comment on column coupon.remark is '优惠券备注';
comment on column coupon.amount is '优惠券金额'; comment on column coupon.amount is '优惠券金额';
comment on column coupon.min_amount is '最低消费金额'; comment on column coupon.min_amount is '最低消费金额';
comment on column coupon.status is '优惠券状态0-未使用1-已使用2-已过期'; comment on column coupon.count is '优惠券数量';
comment on column coupon.expire_at is '过期时间'; comment on column coupon.status is '优惠券状态0-禁用1-正常';
comment on column coupon.expire_type is '过期类型0-不过期1-固定日期2-相对日期(从发放时间算起)';
comment on column coupon.expire_at is '过期时间,固定日期必填';
comment on column coupon.expire_in is '过期时长(天),相对日期必填';
comment on column coupon.created_at is '创建时间'; comment on column coupon.created_at is '创建时间';
comment on column coupon.updated_at is '更新时间'; comment on column coupon.updated_at is '更新时间';
comment on column coupon.deleted_at is '删除时间'; comment on column coupon.deleted_at is '删除时间';
-- coupon_user 优惠券发放
drop table if exists coupon_user cascade;
create table coupon_user (
id int generated by default as identity primary key,
coupon_id int not null,
user_id int not null,
status int not null default 0,
expire_at timestamptz,
used_at timestamptz,
created_at timestamptz default current_timestamp
);
create index idx_coupon_user_coupon_id on coupon_user (coupon_id);
create index idx_coupon_user_user_id on coupon_user (user_id);
-- coupon_user表字段注释
comment on table coupon_user is '优惠券发放表';
comment on column coupon_user.id is '记录ID';
comment on column coupon_user.coupon_id is '优惠券ID';
comment on column coupon_user.user_id is '用户ID';
comment on column coupon_user.status is '使用状态0-未使用1-已使用';
comment on column coupon_user.expire_at is '过期时间';
comment on column coupon_user.used_at is '使用时间';
comment on column coupon_user.created_at is '创建时间';
-- endregion -- endregion
-- ==================== -- ====================
@@ -1185,11 +1216,13 @@ alter table bill
alter table bill alter table bill
add constraint fk_bill_refund_id foreign key (refund_id) references refund (id) on delete set null; add constraint fk_bill_refund_id foreign key (refund_id) references refund (id) on delete set null;
alter table bill alter table bill
add constraint fk_bill_coupon_id foreign key (coupon_id) references coupon (id) on delete set null; add constraint fk_bill_coupon_id foreign key (coupon_user_id) references coupon_user (id) on delete set null;
-- coupon表外键 -- coupon_user表外键
alter table coupon alter table coupon_user
add constraint fk_coupon_user_id foreign key (user_id) references "user" (id) on delete cascade; add constraint fk_coupon_user_user_id foreign key (user_id) references "user" (id) on delete cascade;
alter table coupon_user
add constraint fk_coupon_user_coupon_id foreign key (coupon_id) references coupon (id) on delete cascade;
-- product_sku表外键 -- product_sku表外键
alter table product_sku alter table product_sku

81
scripts/sql/update.sql Normal file
View File

@@ -0,0 +1,81 @@
-- ====================
-- region 套餐更新
-- ====================
-- --------------------------
-- 短效动态
-- --------------------------
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包量 3 分钟', price = 10.00, price_min = 10.00, sort = 1 where code = 'mode=quota&live=3&expire=0' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包量 5 分钟', price = 10.00, price_min = 10.00, sort = 2 where code = 'mode=quota&live=5&expire=0' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包量 10 分钟', price = 10.00, price_min = 10.00, sort = 3 where code = 'mode=quota&live=10&expire=0' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包量 15 分钟', price = 10.00, price_min = 10.00, sort = 4 where code = 'mode=quota&live=15&expire=0' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包量 30 分钟', price = 10.00, price_min = 10.00, sort = 5 where code = 'mode=quota&live=30&expire=0' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 3 分钟 7 天', price = 10.00, price_min = 10.00, sort = 6 where code = 'mode=time&live=3&expire=7' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 5 分钟 7 天', price = 10.00, price_min = 10.00, sort = 7 where code = 'mode=time&live=5&expire=7' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 10 分钟 7 天', price = 10.00, price_min = 10.00, sort = 8 where code = 'mode=time&live=10&expire=7' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 15 分钟 7 天', price = 10.00, price_min = 10.00, sort = 9 where code = 'mode=time&live=15&expire=7' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 30 分钟 7 天', price = 10.00, price_min = 10.00, sort = 10 where code = 'mode=time&live=30&expire=7' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 3 分钟 15 天', price = 10.00, price_min = 10.00, sort = 11 where code = 'mode=time&live=3&expire=15' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 5 分钟 15 天', price = 10.00, price_min = 10.00, sort = 12 where code = 'mode=time&live=5&expire=15' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 10 分钟 15 天', price = 10.00, price_min = 10.00, sort = 13 where code = 'mode=time&live=10&expire=15' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 15 分钟 15 天', price = 10.00, price_min = 10.00, sort = 14 where code = 'mode=time&live=15&expire=15' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 30 分钟 15 天', price = 10.00, price_min = 10.00, sort = 15 where code = 'mode=time&live=30&expire=15' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 3 分钟 30 天', price = 10.00, price_min = 10.00, sort = 16 where code = 'mode=time&live=3&expire=30' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 5 分钟 30 天', price = 10.00, price_min = 10.00, sort = 17 where code = 'mode=time&live=5&expire=30' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 10 分钟 30 天', price = 10.00, price_min = 10.00, sort = 18 where code = 'mode=time&live=10&expire=30' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 15 分钟 30 天', price = 10.00, price_min = 10.00, sort = 19 where code = 'mode=time&live=15&expire=30' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 30 分钟 30 天', price = 10.00, price_min = 10.00, sort = 20 where code = 'mode=time&live=30&expire=30' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 3 分钟 90 天', price = 10.00, price_min = 10.00, sort = 21 where code = 'mode=time&live=3&expire=90' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 5 分钟 90 天', price = 10.00, price_min = 10.00, sort = 22 where code = 'mode=time&live=5&expire=90' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 10 分钟 90 天', price = 10.00, price_min = 10.00, sort = 23 where code = 'mode=time&live=10&expire=90' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 15 分钟 90 天', price = 10.00, price_min = 10.00, sort = 24 where code = 'mode=time&live=15&expire=90' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 30 分钟 90 天', price = 10.00, price_min = 10.00, sort = 25 where code = 'mode=time&live=30&expire=90' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 3 分钟 180 天', price = 10.00, price_min = 10.00, sort = 26 where code = 'mode=time&live=3&expire=180' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 5 分钟 180 天', price = 10.00, price_min = 10.00, sort = 27 where code = 'mode=time&live=5&expire=180' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 10 分钟 180 天', price = 10.00, price_min = 10.00, sort = 28 where code = 'mode=time&live=10&expire=180' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 15 分钟 180 天', price = 10.00, price_min = 10.00, sort = 29 where code = 'mode=time&live=15&expire=180' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 30 分钟 180 天', price = 10.00, price_min = 10.00, sort = 30 where code = 'mode=time&live=30&expire=180' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 3 分钟 365 天', price = 10.00, price_min = 10.00, sort = 31 where code = 'mode=time&live=3&expire=365' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 5 分钟 365 天', price = 10.00, price_min = 10.00, sort = 32 where code = 'mode=time&live=5&expire=365' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 10 分钟 365 天', price = 10.00, price_min = 10.00, sort = 33 where code = 'mode=time&live=10&expire=365' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 15 分钟 365 天', price = 10.00, price_min = 10.00, sort = 34 where code = 'mode=time&live=15&expire=365' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'short' and deleted_at is null), name = '短效动态包时 30 分钟 365 天', price = 10.00, price_min = 10.00, sort = 35 where code = 'mode=time&live=30&expire=365' and deleted_at is null;
-- --------------------------
-- 长效动态
-- --------------------------
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包量 1 小时', price = 10.00, price_min = 10.00, sort = 1 where code = 'mode=quota&live=60&expire=0' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包量 4 小时', price = 10.00, price_min = 10.00, sort = 2 where code = 'mode=quota&live=240&expire=0' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包量 8 小时', price = 10.00, price_min = 10.00, sort = 3 where code = 'mode=quota&live=480&expire=0' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包量 12 小时', price = 10.00, price_min = 10.00, sort = 4 where code = 'mode=quota&live=720&expire=0' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包量 24 小时', price = 10.00, price_min = 10.00, sort = 5 where code = 'mode=quota&live=1440&expire=0' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 1 小时 7 天', price = 10.00, price_min = 10.00, sort = 6 where code = 'mode=time&live=60&expire=7' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 4 小时 7 天', price = 10.00, price_min = 10.00, sort = 7 where code = 'mode=time&live=240&expire=7' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 8 小时 7 天', price = 10.00, price_min = 10.00, sort = 8 where code = 'mode=time&live=480&expire=7' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 12 小时 7 天', price = 10.00, price_min = 10.00, sort = 9 where code = 'mode=time&live=720&expire=7' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 24 小时 7 天', price = 10.00, price_min = 10.00, sort = 10 where code = 'mode=time&live=1440&expire=7' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 1 小时 15 天', price = 10.00, price_min = 10.00, sort = 11 where code = 'mode=time&live=60&expire=15' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 4 小时 15 天', price = 10.00, price_min = 10.00, sort = 12 where code = 'mode=time&live=240&expire=15' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 8 小时 15 天', price = 10.00, price_min = 10.00, sort = 13 where code = 'mode=time&live=480&expire=15' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 12 小时 15 天', price = 10.00, price_min = 10.00, sort = 14 where code = 'mode=time&live=720&expire=15' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 24 小时 15 天', price = 10.00, price_min = 10.00, sort = 15 where code = 'mode=time&live=1440&expire=15' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 1 小时 30 天', price = 10.00, price_min = 10.00, sort = 16 where code = 'mode=time&live=60&expire=30' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 4 小时 30 天', price = 10.00, price_min = 10.00, sort = 17 where code = 'mode=time&live=240&expire=30' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 8 小时 30 天', price = 10.00, price_min = 10.00, sort = 18 where code = 'mode=time&live=480&expire=30' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 12 小时 30 天', price = 10.00, price_min = 10.00, sort = 19 where code = 'mode=time&live=720&expire=30' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 24 小时 30 天', price = 10.00, price_min = 10.00, sort = 20 where code = 'mode=time&live=1440&expire=30' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 1 小时 90 天', price = 10.00, price_min = 10.00, sort = 21 where code = 'mode=time&live=60&expire=90' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 4 小时 90 天', price = 10.00, price_min = 10.00, sort = 22 where code = 'mode=time&live=240&expire=90' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 8 小时 90 天', price = 10.00, price_min = 10.00, sort = 23 where code = 'mode=time&live=480&expire=90' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 12 小时 90 天', price = 10.00, price_min = 10.00, sort = 24 where code = 'mode=time&live=720&expire=90' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 24 小时 90 天', price = 10.00, price_min = 10.00, sort = 25 where code = 'mode=time&live=1440&expire=90' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 1 小时 180 天', price = 10.00, price_min = 10.00, sort = 26 where code = 'mode=time&live=60&expire=180' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 4 小时 180 天', price = 10.00, price_min = 10.00, sort = 27 where code = 'mode=time&live=240&expire=180' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 8 小时 180 天', price = 10.00, price_min = 10.00, sort = 28 where code = 'mode=time&live=480&expire=180' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 12 小时 180 天', price = 10.00, price_min = 10.00, sort = 29 where code = 'mode=time&live=720&expire=180' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 24 小时 180 天', price = 10.00, price_min = 10.00, sort = 30 where code = 'mode=time&live=1440&expire=180' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 1 小时 365 天', price = 10.00, price_min = 10.00, sort = 31 where code = 'mode=time&live=60&expire=365' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 4 小时 365 天', price = 10.00, price_min = 10.00, sort = 32 where code = 'mode=time&live=240&expire=365' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 8 小时 365 天', price = 10.00, price_min = 10.00, sort = 33 where code = 'mode=time&live=480&expire=365' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 12 小时 365 天', price = 10.00, price_min = 10.00, sort = 34 where code = 'mode=time&live=720&expire=365' and deleted_at is null;
update product_sku set product_id = (select id from product where code = 'long' and deleted_at is null), name = '长效动态包时 24 小时 365 天', price = 10.00, price_min = 10.00, sort = 35 where code = 'mode=time&live=1440&expire=365' and deleted_at is null;

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"errors" "errors"
"log/slog" "log/slog"
"platform/pkg/u"
"platform/web/core" "platform/web/core"
m "platform/web/models" m "platform/web/models"
q "platform/web/queries" q "platform/web/queries"
@@ -50,9 +49,8 @@ func authUser(loginType PwdLoginType, username, password string) (user *m.User,
} }
if user == nil { if user == nil {
user = &m.User{ user = &m.User{
Phone: username, Phone: username,
Username: u.P(username), Status: m.UserStatusEnabled,
Status: m.UserStatusEnabled,
} }
} }
case PwdLoginByEmail: case PwdLoginByEmail:
@@ -79,7 +77,7 @@ func authUser(loginType PwdLoginType, username, password string) (user *m.User,
func authUserBySms(tx *q.Query, username, code string) (*m.User, error) { func authUserBySms(tx *q.Query, username, code string) (*m.User, error) {
// 验证验证码 // 验证验证码
err := s.Verifier.VerifySms(context.Background(), username, code) err := s.Verifier.VerifySms(context.Background(), username, code, s.VerifierSmsPurposeLogin)
if err != nil { if err != nil {
return nil, core.NewBizErr("短信认证失败", err) return nil, core.NewBizErr("短信认证失败", err)
} }
@@ -169,6 +167,9 @@ func adminScopes(admin *m.Admin) ([]string, error) {
scopeNames := make([]string, 0, len(scopes)) scopeNames := make([]string, 0, len(scopes))
for _, scope := range scopes { for _, scope := range scopes {
if scope.Name == "" {
continue
}
scopeNames = append(scopeNames, scope.Name) scopeNames = append(scopeNames, scope.Name)
} }
return scopeNames, nil return scopeNames, nil

View File

@@ -356,6 +356,11 @@ func authPassword(c *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (*m
return nil, err return nil, err
} }
// 非锁定管理员,不允许为空权限
if !admin.Lock && (len(scopes) == 0) {
return nil, ErrAuthorizeInvalidScope // 没有配置权限
}
// 更新管理员登录时间 // 更新管理员登录时间
admin.LastLogin = u.P(time.Now()) admin.LastLogin = u.P(time.Now())
admin.LastLoginIP = ip admin.LastLoginIP = ip
@@ -532,10 +537,10 @@ func introspectUser(ctx *fiber.Ctx, authCtx *AuthCtx) error {
// 掩码敏感信息 // 掩码敏感信息
if profile.Phone != "" { if profile.Phone != "" {
profile.Phone = maskPhone(profile.Phone) profile.Phone = u.MaskPhone(profile.Phone)
} }
if profile.IDNo != nil && *profile.IDNo != "" { if profile.IDNo != nil && *profile.IDNo != "" {
profile.IDNo = u.P(maskIdNo(*profile.IDNo)) profile.IDNo = u.P(u.MaskIdNo(*profile.IDNo))
} }
return ctx.JSON(struct { return ctx.JSON(struct {
@@ -574,20 +579,6 @@ func introspectAdmin(ctx *fiber.Ctx, authCtx *AuthCtx) error {
}{profile, list}) }{profile, list})
} }
func maskPhone(phone string) string {
if len(phone) < 11 {
return phone
}
return phone[:3] + "****" + phone[7:]
}
func maskIdNo(idNo string) string {
if len(idNo) < 18 {
return idNo
}
return idNo[:3] + "*********" + idNo[14:]
}
type CodeContext struct { type CodeContext struct {
UserID int32 `json:"user_id"` UserID int32 `json:"user_id"`
ClientID int32 `json:"client_id"` ClientID int32 `json:"client_id"`

View File

@@ -12,9 +12,9 @@ type IModel interface {
} }
type Model struct { type Model struct {
ID int32 `json:"id" gorm:"column:id;primaryKey"` ID int32 `json:"id,omitzero" gorm:"column:id;primaryKey"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` CreatedAt time.Time `json:"created_at,omitzero" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"` UpdatedAt time.Time `json:"updated_at,omitzero" gorm:"column:updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"column:deleted_at"` DeletedAt gorm.DeletedAt `json:"-" gorm:"column:deleted_at"`
} }

View File

@@ -17,9 +17,10 @@ const (
ScopeProductRead = string("product:read") // 读取产品列表 ScopeProductRead = string("product:read") // 读取产品列表
ScopeProductWrite = string("product:write") // 写入产品 ScopeProductWrite = string("product:write") // 写入产品
ScopeProductSku = string("product_sku") // 产品套餐 ScopeProductSku = string("product_sku") // 产品套餐
ScopeProductSkuRead = string("product_sku:read") // 读取产品套餐列表 ScopeProductSkuRead = string("product_sku:read") // 读取产品套餐列表
ScopeProductSkuWrite = string("product_sku:write") // 写入产品套餐 ScopeProductSkuWrite = string("product_sku:write") // 写入产品套餐
ScopeProductSkuWriteStatus = string("product_sku:write:status") // 更改产品套餐状态
ScopeDiscount = string("discount") // 折扣 ScopeDiscount = string("discount") // 折扣
ScopeDiscountRead = string("discount:read") // 读取折扣列表 ScopeDiscountRead = string("discount:read") // 读取折扣列表
@@ -29,30 +30,50 @@ const (
ScopeResourceRead = string("resource:read") // 读取用户套餐列表 ScopeResourceRead = string("resource:read") // 读取用户套餐列表
ScopeResourceWrite = string("resource:write") // 写入用户套餐 ScopeResourceWrite = string("resource:write") // 写入用户套餐
ScopeUser = string("user") // 用户 ScopeResourceShort = string("resource:short") // 短效动态套餐
ScopeUserRead = string("user:read") // 读取用户列表 ScopeResourceShortRead = string("resource:short:read") // 读取用户短效动态套餐列表
ScopeUserReadOne = string("user:read:one") // 读取单个用户 ScopeResourceShortReadOfUser = string("resource:short:read:of_user") // 读取指定用户的短效动态套餐列表
ScopeUserWrite = string("user:write") // 写入用户
ScopeUserWriteBalance = string("user:write:balance") // 写入用户余额 ScopeResourceLong = string("resource:long") // 长效动态套餐
ScopeUserWriteBind = string("user:write:bind") // 用户认领 ScopeResourceLongRead = string("resource:long:read") // 读取用户长效动态套餐列表
ScopeResourceLongReadOfUser = string("resource:long:read:of_user") // 读取指定用户的长效动态套餐列表
ScopeUser = string("user") // 用户
ScopeUserRead = string("user:read") // 读取用户列表
ScopeUserReadOne = string("user:read:one") // 读取单个用户
ScopeUserReadNotBind = string("user:read:not_bind") // 读取未绑定管理员的用户列表
ScopeUserWrite = string("user:write") // 写入用户
ScopeUserWriteBalance = string("user:write:balance") // 写入用户余额
ScopeUserWriteBalanceInc = string("user:write:balance:inc") // 增加用户余额
ScopeUserWriteBalanceDec = string("user:write:balance:dec") // 减少用户余额
ScopeUserWriteBind = string("user:write:bind") // 用户认领
ScopeCoupon = string("coupon") // 优惠券 ScopeCoupon = string("coupon") // 优惠券
ScopeCouponRead = string("coupon:read") // 读取优惠券列表 ScopeCouponRead = string("coupon:read") // 读取优惠券列表
ScopeCouponWrite = string("coupon:write") // 写入优惠券 ScopeCouponWrite = string("coupon:write") // 写入优惠券
ScopeBatch = string("batch") // 批次 ScopeBatch = string("batch") // 批次
ScopeBatchRead = string("batch:read") // 读取批次列表 ScopeBatchRead = string("batch:read") // 读取批次列表
ScopeBatchWrite = string("batch:write") // 写入批次 ScopeBatchReadOfUser = string("batch:read:of_user") // 读取指定用户的批次列表
ScopeBatchWrite = string("batch:write") // 写入批次
ScopeChannel = string("channel") // IP ScopeChannel = string("channel") // IP
ScopeChannelRead = string("channel:read") // 读取 IP 列表 ScopeChannelRead = string("channel:read") // 读取 IP 列表
ScopeChannelWrite = string("channel:write") // 写入 IP ScopeChannelReadOfUser = string("channel:read:of_user") // 读取指定用户的 IP 列表
ScopeChannelWrite = string("channel:write") // 写入 IP
ScopeTrade = string("trade") // 交易 ScopeTrade = string("trade") // 交易
ScopeTradeRead = string("trade:read") // 读取交易列表 ScopeTradeRead = string("trade:read") // 读取交易列表
ScopeTradeWrite = string("trade:write") // 写入交易 ScopeTradeReadOfUser = string("trade:read:of_user") // 读取指定用户的交易列表
ScopeTradeWrite = string("trade:write") // 写入交易
ScopeTradeWriteComplete = string("trade:write:complete") // 完成交易
ScopeBill = string("bill") // 账单 ScopeBill = string("bill") // 账单
ScopeBillRead = string("bill:read") // 读取账单列表 ScopeBillRead = string("bill:read") // 读取账单列表
ScopeBillWrite = string("bill:write") // 写入账单 ScopeBillReadOfUser = string("bill:read:of_user") // 读取指定用户的账单列表
ScopeBillWrite = string("bill:write") // 写入账单
ScopeBalanceActivity = string("balance_activity") // 余额变动
ScopeBalanceActivityRead = string("balance_activity:read") // 读取余额变动列表
ScopeBalanceActivityReadOfUser = string("balance_activity:read:of_user") // 读取指定用户的余额变动列表
) )

View File

@@ -20,7 +20,7 @@ func PageAdminByAdmin(c *fiber.Ctx) error {
return err return err
} }
list, total, err := s.Admin.PageAdmins(req.PageReq) list, total, err := s.Admin.Page(req.PageReq)
if err != nil { if err != nil {
return err return err
} }
@@ -62,7 +62,7 @@ func CreateAdmin(c *fiber.Ctx) error {
return err return err
} }
if err := s.Admin.CreateAdmin(&req); err != nil { if err := s.Admin.Create(&req); err != nil {
return err return err
} }
@@ -80,7 +80,7 @@ func UpdateAdmin(c *fiber.Ctx) error {
return err return err
} }
if err := s.Admin.UpdateAdmin(&req); err != nil { if err := s.Admin.Update(&req); err != nil {
return err return err
} }
@@ -98,7 +98,7 @@ func RemoveAdmin(c *fiber.Ctx) error {
return err return err
} }
if err := s.Admin.RemoveAdmin(req.Id); err != nil { if err := s.Admin.Remove(req.Id); err != nil {
return err return err
} }

View File

@@ -0,0 +1,137 @@
package handlers
import (
"platform/pkg/u"
"platform/web/auth"
"platform/web/core"
g "platform/web/globals"
q "platform/web/queries"
"time"
"github.com/gofiber/fiber/v2"
)
// PageBalanceActivityByAdmin 分页查询所有余额变动记录
func PageBalanceActivityByAdmin(c *fiber.Ctx) error {
// 检查权限
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeBalanceActivityRead)
if err != nil {
return err
}
// 解析请求参数
req := new(PageBalanceActivityByAdminReq)
if err := g.Validator.ParseBody(c, req); err != nil {
return err
}
// 构造查询条件
do := q.BalanceActivity.Where()
if req.UserPhone != nil {
do = do.Where(q.User.As("User").Phone.Eq(*req.UserPhone))
}
if req.BillNo != nil {
do = do.Where(q.Bill.As("Bill").BillNo.Eq(*req.BillNo))
}
if req.CreatedAtStart != nil {
t := u.DateHead(*req.CreatedAtStart)
do = do.Where(q.BalanceActivity.CreatedAt.Gte(t))
}
if req.CreatedAtEnd != nil {
t := u.DateTail(*req.CreatedAtEnd)
do = do.Where(q.BalanceActivity.CreatedAt.Lte(t))
}
// 查询余额变动列表
list, total, err := q.BalanceActivity.Debug().
Joins(q.BalanceActivity.User, q.BalanceActivity.Admin, q.BalanceActivity.Bill).
Select(
q.BalanceActivity.ALL,
q.User.As("User").Phone.As("User__phone"),
q.User.As("User").Name.As("User__name"),
q.Admin.As("Admin").Name.As("Admin__name"),
q.Bill.As("Bill").BillNo.As("Bill__bill_no"),
).
Where(do).
Order(q.BalanceActivity.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return core.NewBizErr("获取数据失败", err)
}
// 返回结果
return c.JSON(core.PageResp{
List: list,
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
})
}
type PageBalanceActivityByAdminReq struct {
core.PageReq
UserPhone *string `json:"user_phone,omitempty"`
BillNo *string `json:"bill_no,omitempty"`
CreatedAtStart *time.Time `json:"created_at_start,omitempty"`
CreatedAtEnd *time.Time `json:"created_at_end,omitempty"`
}
// PageBalanceActivityOfUserByAdmin 分页查询指定用户的余额变动记录
func PageBalanceActivityOfUserByAdmin(c *fiber.Ctx) error {
// 检查权限
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeBalanceActivityReadOfUser)
if err != nil {
return err
}
// 解析请求参数
req := new(PageBalanceActivityOfUserByAdminReq)
if err := g.Validator.ParseBody(c, req); err != nil {
return err
}
// 构造查询条件
do := q.BalanceActivity.Where(q.BalanceActivity.UserID.Eq(req.UserID))
if req.BillNo != nil {
do = do.Where(q.Bill.As("Bill").BillNo.Eq(*req.BillNo))
}
if req.CreatedAtStart != nil {
t := u.DateHead(*req.CreatedAtStart)
do = do.Where(q.BalanceActivity.CreatedAt.Gte(t))
}
if req.CreatedAtEnd != nil {
t := u.DateTail(*req.CreatedAtEnd)
do = do.Where(q.BalanceActivity.CreatedAt.Lte(t))
}
// 查询余额变动列表
list, total, err := q.BalanceActivity.
Joins(q.BalanceActivity.Admin, q.BalanceActivity.Bill).
Select(
q.BalanceActivity.ALL,
q.Admin.As("Admin").Name.As("Admin__name"),
q.Bill.As("Bill").BillNo.As("Bill__bill_no"),
).
Where(do).
Order(q.BalanceActivity.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return core.NewBizErr("获取数据失败", err)
}
// 返回结果
return c.JSON(core.PageResp{
List: list,
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
})
}
type PageBalanceActivityOfUserByAdminReq struct {
core.PageReq
UserID int32 `json:"user_id" validate:"required"`
BillNo *string `json:"bill_no,omitempty"`
CreatedAtStart *time.Time `json:"created_at_start,omitempty"`
CreatedAtEnd *time.Time `json:"created_at_end,omitempty"`
}

View File

@@ -71,10 +71,10 @@ func PageBatchByAdmin(c *fiber.Ctx) error {
do := q.LogsUserUsage.Where() do := q.LogsUserUsage.Where()
if req.UserPhone != nil { if req.UserPhone != nil {
do = do.Where(q.User.Phone.Eq(*req.UserPhone)) do = do.Where(q.User.As("User").Phone.Eq(*req.UserPhone))
} }
if req.ResourceNo != nil { if req.ResourceNo != nil {
do = do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo)) do = do.Where(q.Resource.As("Resource").ResourceNo.Eq(*req.ResourceNo))
} }
if req.BatchNo != nil { if req.BatchNo != nil {
do = do.Where(q.LogsUserUsage.BatchNo.Eq(*req.BatchNo)) do = do.Where(q.LogsUserUsage.BatchNo.Eq(*req.BatchNo))
@@ -128,3 +128,75 @@ type PageBatchByAdminReq struct {
CreatedAtStart *time.Time `json:"created_at_start"` CreatedAtStart *time.Time `json:"created_at_start"`
CreatedAtEnd *time.Time `json:"created_at_end"` CreatedAtEnd *time.Time `json:"created_at_end"`
} }
// PageBatchOfUserByAdmin 分页查询指定用户的提取记录
func PageBatchOfUserByAdmin(ctx *fiber.Ctx) error {
_, err := auth.GetAuthCtx(ctx).PermitAdmin(core.ScopeBatchReadOfUser)
if err != nil {
return err
}
var req PageBatchOfUserByAdminReq
if err = g.Validator.ParseBody(ctx, &req); err != nil {
return err
}
do := q.LogsUserUsage.Where(q.LogsUserUsage.UserID.Eq(req.UserID))
if req.ResourceNo != nil {
do = do.Where(q.Resource.As("Resource").ResourceNo.Eq(*req.ResourceNo))
}
if req.BatchNo != nil {
do = do.Where(q.LogsUserUsage.BatchNo.Eq(*req.BatchNo))
}
if req.Prov != nil {
do = do.Where(q.LogsUserUsage.Prov.Eq(*req.Prov))
}
if req.City != nil {
do = do.Where(q.LogsUserUsage.City.Eq(*req.City))
}
if req.Isp != nil {
do = do.Where(q.LogsUserUsage.ISP.Eq(*req.Isp))
}
if req.CreatedAtStart != nil {
t := u.DateHead(*req.CreatedAtStart)
do = do.Where(q.LogsUserUsage.Time.Gte(t))
}
if req.CreatedAtEnd != nil {
t := u.DateTail(*req.CreatedAtEnd)
do = do.Where(q.LogsUserUsage.Time.Lte(t))
}
list, total, err := q.LogsUserUsage.
Joins(q.LogsUserUsage.User, q.LogsUserUsage.Resource).
Select(
q.LogsUserUsage.ALL,
q.User.As("User").Phone.As("User__phone"),
q.User.As("User").Name.As("User__name"),
q.Resource.As("Resource").ResourceNo.As("Resource__resource_no"),
).
Where(do).
Order(q.LogsUserUsage.Time.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return ctx.JSON(core.NewBizErr("获取数据失败", err))
}
return ctx.JSON(c.PageResp{
List: list,
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
})
}
type PageBatchOfUserByAdminReq struct {
c.PageReq
UserID int32 `json:"user_id" validate:"required"`
ResourceNo *string `json:"resource_no"`
BatchNo *string `json:"batch_no"`
Prov *string `json:"prov"`
City *string `json:"city"`
Isp *string `json:"isp"`
CreatedAtStart *time.Time `json:"created_at_start"`
CreatedAtEnd *time.Time `json:"created_at_end"`
}

View File

@@ -101,6 +101,90 @@ type PageBillByAdminReq struct {
SkuCode *string `json:"sku_code,omitempty"` SkuCode *string `json:"sku_code,omitempty"`
} }
// PageBillOfUserByAdmin 分页查询指定用户账单
func PageBillOfUserByAdmin(c *fiber.Ctx) error {
// 检查权限
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeBillReadOfUser)
if err != nil {
return err
}
// 解析请求参数
req := new(PageBillOfUserByAdminReq)
if err := g.Validator.ParseBody(c, req); err != nil {
return err
}
// 构造查询条件
do := q.Bill.Where(q.Bill.UserID.Eq(req.UserID))
if req.TradeInnerNo != nil {
do = do.Where(q.Trade.As("Trade").InnerNo.Eq(*req.TradeInnerNo))
}
if req.ResourceNo != nil {
do = do.Where(q.Resource.As("Resource").ResourceNo.Eq(*req.ResourceNo))
}
if req.BillNo != nil {
do = do.Where(q.Bill.BillNo.Eq(*req.BillNo))
}
if req.CreatedAtStart != nil {
time := u.DateHead(*req.CreatedAtStart)
do = do.Where(q.Bill.CreatedAt.Gte(time))
}
if req.CreatedAtEnd != nil {
time := u.DateHead(*req.CreatedAtEnd)
do = do.Where(q.Bill.CreatedAt.Lte(time))
}
if req.ProductCode != nil {
do = do.Where(q.Resource.As("Resource").Code.Eq(*req.ProductCode))
}
if req.SkuCode != nil {
do = do.Where(q.Bill.
Where(q.ResourceShort.As("Resource__Short").Code.Eq(*req.SkuCode)).
Or(q.ResourceLong.As("Resource__Long").Code.Eq(*req.SkuCode)))
}
// 查询账单列表
list, total, err := q.Bill.
Joins(
q.Bill.Resource,
q.Bill.Trade,
q.Bill.Resource.Short,
q.Bill.Resource.Long,
).
Select(
q.Bill.ALL,
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"),
).
Where(do).
Order(q.Bill.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return err
}
// 返回结果
return c.JSON(core.PageResp{
List: list,
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
})
}
type PageBillOfUserByAdminReq struct {
core.PageReq
UserID int32 `json:"user_id" validate:"required"`
TradeInnerNo *string `json:"trade_inner_no,omitempty"`
ResourceNo *string `json:"resource_no,omitempty"`
BillNo *string `json:"bill_no,omitempty"`
CreatedAtStart *time.Time `json:"created_at_start,omitempty"`
CreatedAtEnd *time.Time `json:"created_at_end,omitempty"`
ProductCode *string `json:"product_code,omitempty"`
SkuCode *string `json:"sku_code,omitempty"`
}
// ListBill 获取账单列表 // ListBill 获取账单列表
func ListBill(c *fiber.Ctx) error { func ListBill(c *fiber.Ctx) error {
// 检查权限 // 检查权限

View File

@@ -271,3 +271,76 @@ func RemoveChannels(c *fiber.Ctx) error {
type RemoveChannelsReq struct { type RemoveChannelsReq struct {
Batch string `json:"batch" validate:"required"` Batch string `json:"batch" validate:"required"`
} }
// PageChannelOfUserByAdmin 分页查询指定用户的通道
func PageChannelOfUserByAdmin(c *fiber.Ctx) error {
// 检查权限
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeChannelReadOfUser)
if err != nil {
return err
}
// 解析请求参数
var req PageChannelOfUserByAdminReq
if err := g.Validator.ParseBody(c, &req); err != nil {
return err
}
// 构建查询条件
do := q.Channel.Where(q.Channel.UserID.Eq(req.UserID))
if req.ResourceNo != nil {
do = do.Where(q.Resource.As("Resource").ResourceNo.Eq(*req.ResourceNo))
}
if req.BatchNo != nil {
do = do.Where(q.Channel.BatchNo.Eq(*req.BatchNo))
}
if req.ProxyHost != nil {
do = do.Where(q.Channel.Host.Eq(*req.ProxyHost))
}
if req.ProxyPort != nil {
do = do.Where(q.Channel.Port.Eq(*req.ProxyPort))
}
if req.ExpiredAtStart != nil {
t := u.DateHead(*req.ExpiredAtStart)
do = do.Where(q.Channel.ExpiredAt.Gte(t))
}
if req.ExpiredAtEnd != nil {
t := u.DateHead(*req.ExpiredAtEnd)
do = do.Where(q.Channel.ExpiredAt.Lte(t))
}
// 查询通道列表
list, total, err := q.Channel.
Joins(q.Channel.User, q.Channel.Resource).
Select(
q.Channel.ALL,
q.Resource.As("Resource").ResourceNo.As("Resource__resource_no"),
q.User.As("User").Phone.As("User__phone"),
q.User.As("User").Name.As("User__name"),
).
Where(do).
Order(q.Channel.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return err
}
// 返回结果
return c.JSON(core.PageResp{
List: list,
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
})
}
type PageChannelOfUserByAdminReq struct {
core.PageReq
UserID int32 `json:"user_id" validate:"required"`
ResourceNo *string `json:"resource_no"`
BatchNo *string `json:"batch_no"`
ProxyHost *string `json:"proxy_host"`
ProxyPort *uint16 `json:"proxy_port"`
ExpiredAtStart *time.Time `json:"expired_at_start"`
ExpiredAtEnd *time.Time `json:"expired_at_end"`
}

View File

@@ -34,6 +34,15 @@ func AllProductByAdmin(c *fiber.Ctx) error {
type AllProductsByAdminReq struct { type AllProductsByAdminReq struct {
} }
func AllProduct(c *fiber.Ctx) error {
infos, err := s.Product.AllProductSaleInfos()
if err != nil {
return err
}
return c.JSON(infos)
}
func CreateProduct(c *fiber.Ctx) error { func CreateProduct(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeProductWrite) _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeProductWrite)
if err != nil { if err != nil {
@@ -181,6 +190,32 @@ func UpdateProductSku(c *fiber.Ctx) error {
return nil return nil
} }
func UpdateProductStatusSku(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeProductSkuWrite)
if err != nil {
return err
}
type Params struct {
ID int32 `json:"id"`
Status int32 `json:"status"`
}
var req Params
if err := g.Validator.ParseBody(c, &req); err != nil {
return err
}
err = s.ProductSku.Update(s.UpdateProductSkuData{
ID: req.ID,
Status: &req.Status,
})
if err != nil {
return err
}
return nil
}
func BatchUpdateProductSkuDiscount(c *fiber.Ctx) error { func BatchUpdateProductSkuDiscount(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeProductSkuWrite) _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeProductSkuWrite)
if err != nil { if err != nil {

View File

@@ -209,7 +209,7 @@ type PageResourceLongReq struct {
// PageResourceShortByAdmin 分页查询全部短效套餐 // PageResourceShortByAdmin 分页查询全部短效套餐
func PageResourceShortByAdmin(c *fiber.Ctx) error { func PageResourceShortByAdmin(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceRead) _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceShortRead)
if err != nil { if err != nil {
return err return err
} }
@@ -303,7 +303,7 @@ type PageResourceShortByAdminReq struct {
// PageResourceLongByAdmin 分页查询全部长效套餐 // PageResourceLongByAdmin 分页查询全部长效套餐
func PageResourceLongByAdmin(c *fiber.Ctx) error { func PageResourceLongByAdmin(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceRead) _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceLongRead)
if err != nil { if err != nil {
return err return err
} }
@@ -393,6 +393,148 @@ type PageResourceLongByAdminReq struct {
Expired *bool `json:"expired" form:"expired"` Expired *bool `json:"expired" form:"expired"`
} }
// PageResourceShortOfUserByAdmin 分页查询指定用户的短效套餐
func PageResourceShortOfUserByAdmin(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceShortReadOfUser)
if err != nil {
return err
}
var req PageResourceShortOfUserByAdminReq
if err = g.Validator.ParseBody(c, &req); err != nil {
return err
}
do := q.Resource.Where(q.Resource.UserID.Eq(req.UserID))
if req.ResourceNo != nil {
do = do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo))
}
if req.Active != nil {
do = do.Where(q.Resource.Active.Is(*req.Active))
}
if req.Mode != nil {
do = do.Where(q.ResourceShort.As("Short").Type.Eq(int(*req.Mode)))
}
if req.CreatedAtStart != nil {
t := u.DateHead(*req.CreatedAtStart)
do = do.Where(q.Resource.CreatedAt.Gte(t))
}
if req.CreatedAtEnd != nil {
t := u.DateTail(*req.CreatedAtEnd)
do = do.Where(q.Resource.CreatedAt.Lte(t))
}
list, total, err := q.Resource.
Joins(q.Resource.User, q.Resource.Short, q.Resource.Short.Sku).
Select(
q.Resource.ALL,
q.User.As("User").Phone.As("User__phone"),
q.User.As("User").Name.As("User__name"),
q.ResourceShort.As("Short").Type.As("Short__type"),
q.ResourceShort.As("Short").Live.As("Short__live"),
q.ResourceShort.As("Short").Quota.As("Short__quota"),
q.ResourceShort.As("Short").Used.As("Short__used"),
q.ResourceShort.As("Short").Daily.As("Short__daily"),
q.ResourceShort.As("Short").LastAt.As("Short__last_at"),
q.ResourceShort.As("Short").ExpireAt.As("Short__expire_at"),
q.ProductSku.As("Short__Sku").Name.As("Short__Sku__name"),
).
Where(q.Resource.Type.Eq(int(m.ResourceTypeShort)), do).
Order(q.Resource.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return err
}
return c.JSON(core.PageResp{
List: list,
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
})
}
type PageResourceShortOfUserByAdminReq struct {
core.PageReq
UserID int32 `json:"user_id" validate:"required"`
ResourceNo *string `json:"resource_no"`
Active *bool `json:"active"`
Mode *int `json:"mode"`
CreatedAtStart *time.Time `json:"created_at_start"`
CreatedAtEnd *time.Time `json:"created_at_end"`
}
// PageResourceLongOfUserByAdmin 分页查询指定用户的长效套餐
func PageResourceLongOfUserByAdmin(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceLongReadOfUser)
if err != nil {
return err
}
var req PageResourceLongOfUserByAdminReq
if err = g.Validator.ParseBody(c, &req); err != nil {
return err
}
do := q.Resource.Where(q.Resource.UserID.Eq(req.UserID))
if req.ResourceNo != nil {
do = do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo))
}
if req.Active != nil {
do = do.Where(q.Resource.Active.Is(*req.Active))
}
if req.Mode != nil {
do = do.Where(q.ResourceLong.As("Long").Type.Eq(*req.Mode))
}
if req.CreatedAtStart != nil {
t := u.DateHead(*req.CreatedAtStart)
do = do.Where(q.Resource.CreatedAt.Gte(t))
}
if req.CreatedAtEnd != nil {
t := u.DateTail(*req.CreatedAtEnd)
do = do.Where(q.Resource.CreatedAt.Lte(t))
}
list, total, err := q.Resource.
Joins(q.Resource.User, q.Resource.Long, q.Resource.Long.Sku).
Select(
q.Resource.ALL,
q.User.As("User").Phone.As("User__phone"),
q.User.As("User").Name.As("User__name"),
q.ResourceLong.As("Long").Type.As("Long__type"),
q.ResourceLong.As("Long").Live.As("Long__live"),
q.ResourceLong.As("Long").Quota.As("Long__quota"),
q.ResourceLong.As("Long").Used.As("Long__used"),
q.ResourceLong.As("Long").Daily.As("Long__daily"),
q.ResourceLong.As("Long").LastAt.As("Long__last_at"),
q.ResourceLong.As("Long").ExpireAt.As("Long__expire_at"),
q.ProductSku.As("Long__Sku").Name.As("Long__Sku__name"),
).
Where(q.Resource.Type.Eq(int(m.ResourceTypeLong)), do).
Order(q.Resource.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return err
}
return c.JSON(core.PageResp{
List: list,
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
})
}
type PageResourceLongOfUserByAdminReq struct {
core.PageReq
UserID int32 `json:"user_id" validate:"required"`
ResourceNo *string `json:"resource_no"`
Active *bool `json:"active"`
Mode *int `json:"mode"`
CreatedAtStart *time.Time `json:"created_at_start"`
CreatedAtEnd *time.Time `json:"created_at_end"`
}
// AllActiveResource 所有可用套餐 // AllActiveResource 所有可用套餐
func AllActiveResource(c *fiber.Ctx) error { func AllActiveResource(c *fiber.Ctx) error {
// 检查权限 // 检查权限
@@ -449,9 +591,6 @@ func AllActiveResource(c *fiber.Ctx) error {
return c.JSON(resources) return c.JSON(resources)
} }
type AllResourceReq struct {
}
func UpdateResourceByAdmin(c *fiber.Ctx) error { func UpdateResourceByAdmin(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceWrite) _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceWrite)
if err != nil { if err != nil {
@@ -658,10 +797,7 @@ type CreateResourceReq struct {
// ResourcePrice 套餐价格 // ResourcePrice 套餐价格
func ResourcePrice(c *fiber.Ctx) error { func ResourcePrice(c *fiber.Ctx) error {
// 检查权限 // 检查权限
_, err := auth.GetAuthCtx(c).PermitSecretClient() ac := auth.GetAuthCtx(c)
if err != nil {
return err
}
// 解析请求参数 // 解析请求参数
var req = new(CreateResourceReq) var req = new(CreateResourceReq)
@@ -670,16 +806,7 @@ func ResourcePrice(c *fiber.Ctx) error {
} }
// 获取套餐价格 // 获取套餐价格
// sku, err := s.Resource.GetSku(req.CreateResourceData.Code()) detail, err := req.TradeDetail(ac.User)
// if err != nil {
// return err
// }
// _, amount, discounted, couponApplied, err := s.Resource.GetPrice(sku, req.Count(), nil, nil)
// if err != nil {
// return err
// }
detail, err := req.TradeDetail(nil)
if err != nil { if err != nil {
return err return err
} }
@@ -687,11 +814,13 @@ func ResourcePrice(c *fiber.Ctx) error {
// 计算折扣 // 计算折扣
return c.JSON(ResourcePriceResp{ return c.JSON(ResourcePriceResp{
Price: detail.Amount.StringFixed(2), Price: detail.Amount.StringFixed(2),
Discounted: detail.Actual.StringFixed(2), Discounted: detail.Discounted.StringFixed(2),
Actual: detail.Actual.StringFixed(2),
}) })
} }
type ResourcePriceResp struct { type ResourcePriceResp struct {
Price string `json:"price"` Price string `json:"price"`
Discounted string `json:"discounted_price"` Discounted string `json:"discounted"`
Actual string `json:"actual"`
} }

View File

@@ -97,6 +97,84 @@ type PageTradeByAdminReq struct {
CreatedAtEnd *time.Time `json:"created_at_end,omitempty"` CreatedAtEnd *time.Time `json:"created_at_end,omitempty"`
} }
// PageTradeOfUserByAdmin 分页查询指定用户的订单
func PageTradeOfUserByAdmin(c *fiber.Ctx) error {
// 检查权限
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeTradeReadOfUser)
if err != nil {
return err
}
// 解析请求参数
req := new(PageTradeOfUserByAdminReq)
if err := g.Validator.ParseBody(c, req); err != nil {
return err
}
// 构建查询语句
do := q.Trade.Where(q.Trade.UserID.Eq(req.UserID))
if req.InnerNo != nil {
do = do.Where(q.Trade.InnerNo.Eq(*req.InnerNo))
}
if req.OuterNo != nil {
do = do.Where(q.Trade.OuterNo.Eq(*req.OuterNo))
}
if req.Method != nil {
do = do.Where(q.Trade.Method.Eq(*req.Method))
}
if req.Platform != nil {
do = do.Where(q.Trade.Platform.Eq(*req.Platform))
}
if req.Status != nil {
do = do.Where(q.Trade.Status.Eq(*req.Status))
}
if req.CreatedAtStart != nil {
time := u.DateHead(*req.CreatedAtStart)
do = do.Where(q.Trade.CreatedAt.Gte(time))
}
if req.CreatedAtEnd != nil {
time := u.DateTail(*req.CreatedAtEnd)
do = do.Where(q.Trade.CreatedAt.Lte(time))
}
// 查询订单列表
list, total, err := q.Trade.
Joins(q.Trade.User).
Select(
q.Trade.ALL,
q.User.As("User").Phone.As("User__phone"),
q.User.As("User").Name.As("User__name"),
).
Where(do).
Order(q.Trade.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return err
}
// 返回结果
return c.JSON(core.PageResp{
List: list,
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
})
}
type PageTradeOfUserByAdminReq struct {
core.PageReq
UserID int32 `json:"user_id" validate:"required"`
InnerNo *string `json:"inner_no,omitempty"`
OuterNo *string `json:"outer_no,omitempty"`
Method *int `json:"method,omitempty"`
Platform *int `json:"platform,omitempty"`
Status *int `json:"status,omitempty"`
CreatedAtStart *time.Time `json:"created_at_start,omitempty"`
CreatedAtEnd *time.Time `json:"created_at_end,omitempty"`
}
// ============================================================
// 创建订单 // 创建订单
func TradeCreate(c *fiber.Ctx) error { func TradeCreate(c *fiber.Ctx) error {
// 检查权限 // 检查权限
@@ -143,6 +221,8 @@ type TradeCreateReq struct {
Recharge *s.UpdateBalanceData `json:"recharge,omitempty"` Recharge *s.UpdateBalanceData `json:"recharge,omitempty"`
} }
// ============================================================
// 完成订单 // 完成订单
func TradeComplete(c *fiber.Ctx) error { func TradeComplete(c *fiber.Ctx) error {
// 检查权限 // 检查权限
@@ -152,13 +232,13 @@ func TradeComplete(c *fiber.Ctx) error {
} }
// 解析请求参数 // 解析请求参数
req := new(TradeCompleteReq) var req s.TradeRef
if err := g.Validator.ParseBody(c, req); err != nil { if err := g.Validator.ParseBody(c, &req); err != nil {
return err return err
} }
// 检查订单状态 // 检查订单状态
err = s.Trade.CompleteTrade(authCtx.User, &req.TradeRef) err = s.Trade.CompleteTrade(authCtx.User, &req)
if err != nil { if err != nil {
return err return err
} }
@@ -166,10 +246,40 @@ func TradeComplete(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusNoContent) return c.SendStatus(fiber.StatusNoContent)
} }
type TradeCompleteReq struct { // 管理员完成订单
s.TradeRef func TradeCompleteByAdmin(c *fiber.Ctx) error {
// 检查权限
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeTradeWriteComplete)
if err != nil {
return err
}
// 解析请求参数
var req struct {
s.TradeRef
UserID int32 `json:"user_id" validate:"required"`
}
if err := g.Validator.ParseBody(c, &req); err != nil {
return err
}
// 获取用户信息
user, err := s.User.Get(q.Q, req.UserID)
if err != nil {
return err
}
// 完成订单
err = s.Trade.CompleteTrade(user, &req.TradeRef)
if err != nil {
return err
}
return c.SendStatus(fiber.StatusNoContent)
} }
// ============================================================
// 取消订单 // 取消订单
func TradeCancel(c *fiber.Ctx) error { func TradeCancel(c *fiber.Ctx) error {
// 检查权限 // 检查权限
@@ -198,6 +308,8 @@ type TradeCancelReq struct {
s.TradeRef s.TradeRef
} }
// ============================================================
// 检查订单 // 检查订单
func TradeCheck(c *fiber.Ctx) error { func TradeCheck(c *fiber.Ctx) error {
// 检查权限sse 接口暂时不检查权限 // 检查权限sse 接口暂时不检查权限

View File

@@ -1,6 +1,7 @@
package handlers package handlers
import ( import (
"errors"
"platform/web/auth" "platform/web/auth"
"platform/web/core" "platform/web/core"
g "platform/web/globals" g "platform/web/globals"
@@ -11,6 +12,7 @@ import (
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/shopspring/decimal" "github.com/shopspring/decimal"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"gorm.io/gen/field"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -67,7 +69,7 @@ func PageUserByAdmin(c *fiber.Ctx) error {
// 查询用户列表 // 查询用户列表
users, total, err := q.User. users, total, err := q.User.
Preload(q.User.Admin, q.User.Discount). Preload(q.User.Admin, q.User.Discount).
Omit(q.User.Password). Omit(q.User.Password, q.Admin.Password).
Where(do). Where(do).
Order(q.User.CreatedAt.Desc()). Order(q.User.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit()) FindByPage(req.GetOffset(), req.GetLimit())
@@ -76,6 +78,12 @@ func PageUserByAdmin(c *fiber.Ctx) error {
} }
for _, user := range users { for _, user := range users {
if user.IDNo != nil && len(*user.IDNo) == 18 {
var str = *user.IDNo
*user.IDNo = str[:6] + "****" + str[len(str)-2:]
}
if user.Admin != nil { if user.Admin != nil {
user.Admin = &m.Admin{ user.Admin = &m.Admin{
Name: user.Admin.Name, Name: user.Admin.Name,
@@ -133,7 +141,7 @@ func GetUserByAdmin(c *fiber.Ctx) error {
// 查询用户 // 查询用户
user, err := q.User. user, err := q.User.
Preload(q.User.Admin, q.User.Discount). Preload(q.User.Admin, q.User.Discount).
Omit(q.User.Password). Omit(q.User.Password, q.Admin.Password).
Where(do). Where(do).
Order(q.User.CreatedAt.Desc()). Order(q.User.CreatedAt.Desc()).
First() First()
@@ -298,14 +306,29 @@ func UpdateUser(c *fiber.Ctx) error {
} }
// 更新用户信息 // 更新用户信息
do := make([]field.AssignExpr, 0)
if req.Username != nil && *req.Username != "" {
do = append(do, q.User.Username.Value(*req.Username))
}
if req.Email != nil {
if *req.Email == "" {
do = append(do, q.User.Email.Null())
} else {
do = append(do, q.User.Email.Value(*req.Email))
}
}
if req.ContactQQ != nil {
do = append(do, q.User.ContactQQ.Value(*req.ContactQQ))
}
if req.ContactWechat != nil {
do = append(do, q.User.ContactWechat.Value(*req.ContactWechat))
}
_, err = q.User. _, err = q.User.
Where(q.User.ID.Eq(authCtx.User.ID)). Where(q.User.ID.Eq(authCtx.User.ID)).
Updates(m.User{ UpdateSimple(do...)
Username: &req.Username, if errors.Is(err, gorm.ErrDuplicatedKey) {
Email: &req.Email, return core.NewBizErr("用户名或邮箱已被占用")
ContactQQ: &req.ContactQQ, }
ContactWechat: &req.ContactWechat,
})
if err != nil { if err != nil {
return err return err
} }
@@ -315,10 +338,10 @@ func UpdateUser(c *fiber.Ctx) error {
} }
type UpdateUserReq struct { type UpdateUserReq struct {
Username string `json:"username" validate:"omitempty,min=3,max=20"` Username *string `json:"username" validate:"omitempty,min=3,max=20"`
Email string `json:"email" validate:"omitempty,email"` Email *string `json:"email" validate:"omitempty,email"`
ContactQQ string `json:"contact_qq" validate:"omitempty,qq"` ContactQQ *string `json:"contact_qq" validate:"omitempty,qq"`
ContactWechat string `json:"contact_wechat" validate:"omitempty,wechat"` ContactWechat *string `json:"contact_wechat" validate:"omitempty,wechat"`
} }
// 更新账号信息 // 更新账号信息
@@ -369,16 +392,14 @@ func UpdatePassword(c *fiber.Ctx) error {
return err return err
} }
// 验证手机号
if req.Phone != authCtx.User.Phone {
return fiber.NewError(fiber.StatusBadRequest, "手机号码不正确")
}
// 验证手机令牌 // 验证手机令牌
if req.Code == "" { if req.Code == "" {
return fiber.NewError(fiber.StatusBadRequest, "手机号码和验证码不能为空") return fiber.NewError(fiber.StatusBadRequest, "验证码不能为空")
}
err = s.Verifier.VerifySms(c.Context(), authCtx.User.Phone, req.Code, s.VerifierSmsPurposePassword)
if errors.Is(err, s.ErrVerifierServiceInvalid) {
return core.NewBizErr(s.ErrVerifierServiceInvalid.Error())
} }
err = s.Verifier.VerifySms(c.Context(), req.Phone, req.Code)
if err != nil { if err != nil {
return err return err
} }
@@ -401,7 +422,121 @@ func UpdatePassword(c *fiber.Ctx) error {
} }
type UpdatePasswordReq struct { type UpdatePasswordReq struct {
Phone string `json:"phone"`
Code string `json:"code"` Code string `json:"code"`
Password string `json:"password"` Password string `json:"password"`
} }
// PageUserNotBindByAdmin 分页获取未绑定管理员的用户
func PageUserNotBindByAdmin(c *fiber.Ctx) error {
// 检查权限
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserReadNotBind)
if err != nil {
return err
}
// 解析请求参数
req := new(PageUserNotBindByAdminReq)
if err := g.Validator.ParseBody(c, req); err != nil {
return err
}
// 构建查询条件(强制过滤未绑定管理员的用户)
do := q.User.Where(q.User.AdminID.IsNull())
if req.Phone != nil {
do = do.Where(q.User.Phone.Eq(*req.Phone))
}
// 查询用户列表
users, total, err := q.User.
Omit(q.User.Password, q.User.IDNo).
Where(do).
Order(q.User.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return err
}
// 返回结果
return c.JSON(core.PageResp{
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
List: users,
})
}
type PageUserNotBindByAdminReq struct {
core.PageReq
Phone *string `json:"phone,omitempty"`
}
// UpdateUserBalanceIncByAdmin 管理员增加用户余额
func UpdateUserBalanceIncByAdmin(c *fiber.Ctx) error {
authCtx, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWriteBalance)
if err != nil {
return err
}
var req UpdateUserBalanceChangeByAdminData
if err := g.Validator.ParseBody(c, &req); err != nil {
return err
}
amount, err := decimal.NewFromString(req.Amount)
if err != nil {
return err
}
if !amount.IsPositive() {
return core.NewBizErr("金额必须为正数")
}
user, err := s.User.Get(q.Q, req.UserID)
if err != nil {
return err
}
newBalance := user.Balance.Add(amount)
if err := s.User.UpdateBalanceByAdmin(user, newBalance, &authCtx.Admin.ID); err != nil {
return err
}
return c.JSON(nil)
}
// UpdateUserBalanceDecByAdmin 管理员减少用户余额
func UpdateUserBalanceDecByAdmin(c *fiber.Ctx) error {
authCtx, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWriteBalance)
if err != nil {
return err
}
var req UpdateUserBalanceChangeByAdminData
if err := g.Validator.ParseBody(c, &req); err != nil {
return err
}
amount, err := decimal.NewFromString(req.Amount)
if err != nil {
return err
}
if !amount.IsPositive() {
return core.NewBizErr("金额必须为正数")
}
user, err := s.User.Get(q.Q, req.UserID)
if err != nil {
return err
}
newBalance := user.Balance.Sub(amount)
if err := s.User.UpdateBalanceByAdmin(user, newBalance, &authCtx.Admin.ID); err != nil {
return err
}
return c.JSON(nil)
}
type UpdateUserBalanceChangeByAdminData struct {
UserID int32 `json:"user_id" validate:"required"`
Amount string `json:"amount" validate:"required"`
}

View File

@@ -5,6 +5,7 @@ import (
"platform/pkg/env" "platform/pkg/env"
"platform/web/auth" "platform/web/auth"
"platform/web/services" "platform/web/services"
s "platform/web/services"
"regexp" "regexp"
"strconv" "strconv"
@@ -13,12 +14,11 @@ import (
) )
type VerifierReq struct { type VerifierReq struct {
Purpose services.VerifierSmsPurpose `json:"purpose"` Purpose s.VerifierSmsPurpose `json:"purpose"`
Phone string `json:"phone"` Phone string `json:"phone"`
} }
func SmsCode(c *fiber.Ctx) error { func SendSmsCode(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitOfficialClient() _, err := auth.GetAuthCtx(c).PermitOfficialClient()
if err != nil { if err != nil {
return err return err
@@ -38,9 +38,9 @@ func SmsCode(c *fiber.Ctx) error {
} }
// 发送身份验证码 // 发送身份验证码
err = services.Verifier.SendSms(c.Context(), req.Phone, req.Purpose) err = s.Verifier.SendSms(c.Context(), req.Phone, req.Purpose)
if err != nil { if err != nil {
var sErr services.VerifierServiceSendLimitErr var sErr s.VerifierServiceSendLimitErr
if errors.As(err, &sErr) { if errors.As(err, &sErr) {
return fiber.NewError(fiber.StatusTooManyRequests, strconv.Itoa(int(sErr))) return fiber.NewError(fiber.StatusTooManyRequests, strconv.Itoa(int(sErr)))
} }
@@ -51,6 +51,23 @@ func SmsCode(c *fiber.Ctx) error {
return nil return nil
} }
func SendSmsCodeForPassword(c *fiber.Ctx) error {
ac, err := auth.GetAuthCtx(c).PermitUser()
if err != nil {
return err
}
if err := s.Verifier.SendSms(c.Context(), ac.User.Phone, s.VerifierSmsPurposePassword); err != nil {
var sErr s.VerifierServiceSendLimitErr
if errors.As(err, &sErr) {
return fiber.NewError(fiber.StatusTooManyRequests, strconv.Itoa(int(sErr)))
}
return err
}
return nil
}
func DebugGetSmsCode(c *fiber.Ctx) error { func DebugGetSmsCode(c *fiber.Ctx) error {
if env.RunMode != env.RunModeDev { if env.RunMode != env.RunModeDev {
return fiber.NewError(fiber.StatusForbidden, "not allowed") return fiber.NewError(fiber.StatusForbidden, "not allowed")

View File

@@ -1,6 +1,7 @@
package handlers package handlers
import ( import (
"errors"
"platform/pkg/env" "platform/pkg/env"
"platform/pkg/u" "platform/pkg/u"
"platform/web/auth" "platform/web/auth"
@@ -92,7 +93,7 @@ func CreateWhitelist(c *fiber.Ctx) error {
ip, err := secureAddr(req.Host) ip, err := secureAddr(req.Host)
if err != nil { if err != nil {
return err return core.NewBizErr("IP 地址无效", err)
} }
// 创建白名单 // 创建白名单
@@ -132,7 +133,7 @@ func UpdateWhitelist(c *fiber.Ctx) error {
ip, err := secureAddr(req.Host) ip, err := secureAddr(req.Host)
if err != nil { if err != nil {
return err return core.NewBizErr("IP 地址无效", err)
} }
// 更新白名单 // 更新白名单
@@ -201,7 +202,7 @@ func secureAddr(str string) (*orm.Inet, error) {
return nil, err return nil, err
} }
if !ip.IsGlobalUnicast() && env.RunMode != env.RunModeDev { if !ip.IsGlobalUnicast() && env.RunMode != env.RunModeDev {
return nil, fiber.NewError(fiber.StatusBadRequest, "IP 地址不可用") return nil, errors.New("IP 地址不可用")
} }
return ip, nil return ip, nil
} }

View File

@@ -11,7 +11,7 @@ import (
type Admin struct { type Admin struct {
core.Model core.Model
Username string `json:"username" gorm:"column:username"` // 用户名 Username string `json:"username" gorm:"column:username"` // 用户名
Password string `json:"password" gorm:"column:password"` // 密码 Password string `json:"-" gorm:"column:password"` // 密码
Name *string `json:"name,omitempty" gorm:"column:name"` // 真实姓名 Name *string `json:"name,omitempty" gorm:"column:name"` // 真实姓名
Avatar *string `json:"avatar,omitempty" gorm:"column:avatar"` // 头像URL Avatar *string `json:"avatar,omitempty" gorm:"column:avatar"` // 头像URL
Phone *string `json:"phone,omitempty" gorm:"column:phone"` // 手机号码 Phone *string `json:"phone,omitempty" gorm:"column:phone"` // 手机号码
@@ -20,6 +20,7 @@ type Admin struct {
LastLogin *time.Time `json:"last_login,omitempty" gorm:"column:last_login"` // 最后登录时间 LastLogin *time.Time `json:"last_login,omitempty" gorm:"column:last_login"` // 最后登录时间
LastLoginIP *orm.Inet `json:"last_login_ip,omitempty" gorm:"column:last_login_ip"` // 最后登录地址 LastLoginIP *orm.Inet `json:"last_login_ip,omitempty" gorm:"column:last_login_ip"` // 最后登录地址
LastLoginUA *string `json:"last_login_ua,omitempty" gorm:"column:last_login_ua"` // 最后登录代理 LastLoginUA *string `json:"last_login_ua,omitempty" gorm:"column:last_login_ua"` // 最后登录代理
Lock bool `json:"lock" gorm:"column:lock"` // 是否锁定编辑
Roles []*AdminRole `json:"roles" gorm:"many2many:link_admin_role"` Roles []*AdminRole `json:"roles" gorm:"many2many:link_admin_role"`
} }

View File

@@ -16,7 +16,7 @@ type BalanceActivity struct {
Remark *string `json:"remark,omitempty" gorm:"column:remark"` // 备注 Remark *string `json:"remark,omitempty" gorm:"column:remark"` // 备注
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` // 创建时间 CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` // 创建时间
User *User `json:"user,omitempty" gorm:"foreignKey:UserID"` User *User `json:"user,omitempty" gorm:"foreignKey:UserID"`
Bill *Bill `json:"bill,omitempty" gorm:"foreignKey:BillID"` Bill *Bill `json:"bill,omitempty" gorm:"foreignKey:BillID"`
Admin *User `json:"admin,omitempty" gorm:"foreignKey:AdminID"` Admin *Admin `json:"admin,omitempty" gorm:"foreignKey:AdminID"`
} }

View File

@@ -9,21 +9,22 @@ import (
// Bill 账单表 // Bill 账单表
type Bill struct { type Bill struct {
core.Model core.Model
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
TradeID *int32 `json:"trade_id,omitempty" gorm:"column:trade_id"` // 订单ID TradeID *int32 `json:"trade_id,omitempty" gorm:"column:trade_id"` // 订单ID
ResourceID *int32 `json:"resource_id,omitempty" gorm:"column:resource_id"` // 套餐ID ResourceID *int32 `json:"resource_id,omitempty" gorm:"column:resource_id"` // 套餐ID
RefundID *int32 `json:"refund_id,omitempty" gorm:"column:refund_id"` // 退款ID RefundID *int32 `json:"refund_id,omitempty" gorm:"column:refund_id"` // 退款ID
CouponID *int32 `json:"coupon_id,omitempty" gorm:"column:coupon_id"` // 优惠券ID CouponUserID *int32 `json:"coupon_user_id,omitempty" gorm:"column:coupon_user_id"` // 优惠券发放ID
BillNo string `json:"bill_no" gorm:"column:bill_no"` // 易读账单号 BillNo string `json:"bill_no" gorm:"column:bill_no"` // 易读账单号
Info *string `json:"info,omitempty" gorm:"column:info"` // 产品可读信息 Info *string `json:"info,omitempty" gorm:"column:info"` // 产品可读信息
Type BillType `json:"type" gorm:"column:type"` // 账单类型1-消费2-退款3-充值 Type BillType `json:"type" gorm:"column:type"` // 账单类型1-消费2-退款3-充值
Amount decimal.Decimal `json:"amount" gorm:"column:amount"` // 应付金额 Amount decimal.Decimal `json:"amount" gorm:"column:amount"` // 应付金额
Actual decimal.Decimal `json:"actual" gorm:"column:actual"` // 实付金额 Actual decimal.Decimal `json:"actual" gorm:"column:actual"` // 实付金额
User *User `json:"user,omitempty" gorm:"foreignKey:UserID"` User *User `json:"user,omitempty" gorm:"foreignKey:UserID"`
Trade *Trade `json:"trade,omitempty" gorm:"foreignKey:TradeID"` Trade *Trade `json:"trade,omitempty" gorm:"foreignKey:TradeID"`
Resource *Resource `json:"resource,omitempty" gorm:"foreignKey:ResourceID"` Resource *Resource `json:"resource,omitempty" gorm:"foreignKey:ResourceID"`
Refund *Refund `json:"refund,omitempty" gorm:"foreignKey:RefundID"` Refund *Refund `json:"refund,omitempty" gorm:"foreignKey:RefundID"`
CouponUser *CouponUser `json:"coupon,omitempty" gorm:"foreignKey:CouponUserID"`
} }
// BillType 账单类型枚举 // BillType 账单类型枚举

View File

@@ -8,7 +8,7 @@ import (
type Client struct { type Client struct {
core.Model core.Model
ClientID string `json:"client_id" gorm:"column:client_id"` // OAuth2客户端标识符 ClientID string `json:"client_id" gorm:"column:client_id"` // OAuth2客户端标识符
ClientSecret string `json:"client_secret" gorm:"column:client_secret"` // OAuth2客户端密钥 ClientSecret string `json:"-" gorm:"column:client_secret"` // OAuth2客户端密钥
RedirectURI *string `json:"redirect_uri,omitempty" gorm:"column:redirect_uri"` // OAuth2 重定向URI RedirectURI *string `json:"redirect_uri,omitempty" gorm:"column:redirect_uri"` // OAuth2 重定向URI
Spec ClientSpec `json:"spec" gorm:"column:spec"` // 安全规范1-native2-browser3-web4-api Spec ClientSpec `json:"spec" gorm:"column:spec"` // 安全规范1-native2-browser3-web4-api
Name string `json:"name" gorm:"column:name"` // 名称 Name string `json:"name" gorm:"column:name"` // 名称

View File

@@ -10,20 +10,29 @@ import (
// Coupon 优惠券表 // Coupon 优惠券表
type Coupon struct { type Coupon struct {
core.Model core.Model
UserID *int32 `json:"user_id,omitempty" gorm:"column:user_id"` // 用户ID Name string `json:"name" gorm:"column:name"` // 优惠券名称
Code string `json:"code" gorm:"column:code"` // 优惠券代码 Amount decimal.Decimal `json:"amount" gorm:"column:amount"` // 优惠券金额
Remark *string `json:"remark,omitempty" gorm:"column:remark"` // 优惠券备注 MinAmount decimal.Decimal `json:"min_amount" gorm:"column:min_amount"` // 最低消费金额
Amount decimal.Decimal `json:"amount" gorm:"column:amount"` // 优惠券金额 Count int32 `json:"count" gorm:"column:count"` // 优惠券数量
MinAmount decimal.Decimal `json:"min_amount" gorm:"column:min_amount"` // 最低消费金额 Status CouponStatus `json:"status" gorm:"column:status"` // 优惠券状态0-禁用1-正常
Status CouponStatus `json:"status" gorm:"column:status"` // 优惠券状态0-未使用1-已使用2-已过期 ExpireType CouponExpireType `json:"expire_type" gorm:"column:expire_type"` // 过期类型0-不过期1-固定日期2-相对日期(从发放时间算起)
ExpireAt *time.Time `json:"expire_at,omitempty" gorm:"column:expire_at"` // 过期时间 ExpireAt *time.Time `json:"expire_at,omitempty" gorm:"column:expire_at"` // 过期时间,固定日期必填
ExpireIn *int `json:"expire_in,omitempty" gorm:"column:expire_in"` // 过期时长(天),相对日期必填
} }
// CouponStatus 优惠券状态枚举 // CouponStatus 优惠券使用状态枚举
type CouponStatus int type CouponStatus int
const ( const (
CouponStatusUnused CouponStatus = 0 // 未使 CouponStatusDisabled CouponStatus = 0 //
CouponStatusUsed CouponStatus = 1 // 已使用 CouponStatusEnabled CouponStatus = 1 // 正常
CouponStatusExpired CouponStatus = 2 // 已过期 )
// CouponExpireType 优惠券过期类型枚举
type CouponExpireType int
const (
CouponExpireTypeNever CouponExpireType = 0 // 不过期
CouponExpireTypeFixed CouponExpireType = 1 // 固定日期
CouponExpireTypeRelative CouponExpireType = 2 // 相对日期
) )

25
web/models/coupon_user.go Normal file
View File

@@ -0,0 +1,25 @@
package models
import "time"
// CouponUser 优惠券发放表
type CouponUser struct {
ID int32 `json:"id" gorm:"column:id;primaryKey"` // 记录ID
CouponID int32 `json:"coupon_id" gorm:"column:coupon_id"` // 优惠券ID
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
Status CouponStatus `json:"status" gorm:"column:status"` // 使用状态0-未使用1-已使用
ExpireAt *time.Time `json:"expire_at,omitempty" gorm:"column:expire_at"` // 过期时间
UsedAt *time.Time `json:"used_at,omitempty" gorm:"column:used_at"` // 使用时间
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` // 创建时间
Coupon *Coupon `json:"coupon,omitempty" gorm:"foreignKey:CouponID"`
User *User `json:"user,omitempty" gorm:"foreignKey:UserID"`
}
// CouponUserStatus 优惠券发放状态枚举
type CouponUserStatus int
const (
CouponUserStatusUnused CouponUserStatus = 0 // 未使用
CouponUserStatusUsed CouponUserStatus = 1 // 已使用
)

View File

@@ -12,6 +12,8 @@ type Product struct {
Description *string `json:"description,omitempty" gorm:"column:description"` // 产品描述 Description *string `json:"description,omitempty" gorm:"column:description"` // 产品描述
Sort int32 `json:"sort" gorm:"column:sort"` // 排序 Sort int32 `json:"sort" gorm:"column:sort"` // 排序
Status ProductStatus `json:"status" gorm:"column:status"` // 产品状态0-禁用1-正常 Status ProductStatus `json:"status" gorm:"column:status"` // 产品状态0-禁用1-正常
Skus []*ProductSku `json:"skus,omitempty" gorm:"foreignKey:ProductID"` // 产品包含的SKU列表
} }
// ProductStatus 产品状态枚举 // ProductStatus 产品状态枚举

View File

@@ -14,7 +14,18 @@ type ProductSku struct {
Code string `json:"code" gorm:"column:code"` // SSKU 代码:格式为 key=value,key=value,...其中key:value 是 SKU 的属性,多个属性用逗号分隔 Code string `json:"code" gorm:"column:code"` // SSKU 代码:格式为 key=value,key=value,...其中key:value 是 SKU 的属性,多个属性用逗号分隔
Name string `json:"name" gorm:"column:name"` // SKU 可读名称 Name string `json:"name" gorm:"column:name"` // SKU 可读名称
Price decimal.Decimal `json:"price" gorm:"column:price"` // 定价 Price decimal.Decimal `json:"price" gorm:"column:price"` // 定价
PriceMin decimal.Decimal `json:"price_min" gorm:"column:price_min"` // 最低价格
Status SkuStatus `json:"status" gorm:"column:status"` // SKU 状态0-禁用1-正常
Sort int32 `json:"sort" gorm:"column:sort"` // 排序
Product *Product `json:"product,omitempty" gorm:"foreignKey:ProductID"` Product *Product `json:"product,omitempty" gorm:"foreignKey:ProductID"`
Discount *ProductDiscount `json:"discount,omitempty" gorm:"foreignKey:DiscountId"` Discount *ProductDiscount `json:"discount,omitempty" gorm:"foreignKey:DiscountId"`
} }
// SkuStatus SKU 状态
type SkuStatus int32
const (
SkuStatusDisabled SkuStatus = 0 // 禁用
SkuStatusEnabled SkuStatus = 1 // 正常
)

View File

@@ -16,7 +16,7 @@ type User struct {
Phone string `json:"phone" gorm:"column:phone"` // 手机号码 Phone string `json:"phone" gorm:"column:phone"` // 手机号码
Username *string `json:"username,omitempty" gorm:"column:username"` // 用户名 Username *string `json:"username,omitempty" gorm:"column:username"` // 用户名
Email *string `json:"email,omitempty" gorm:"column:email"` // 邮箱 Email *string `json:"email,omitempty" gorm:"column:email"` // 邮箱
Password *string `json:"password,omitempty" gorm:"column:password"` // 用户密码 Password *string `json:"-" gorm:"column:password"` // 用户密码
Source *UserSource `json:"source,omitempty" gorm:"column:source"` // 用户来源0-官网注册1-管理员添加2-代理商注册3-代理商添加 Source *UserSource `json:"source,omitempty" gorm:"column:source"` // 用户来源0-官网注册1-管理员添加2-代理商注册3-代理商添加
Name *string `json:"name,omitempty" gorm:"column:name"` // 真实姓名 Name *string `json:"name,omitempty" gorm:"column:name"` // 真实姓名
Avatar *string `json:"avatar,omitempty" gorm:"column:avatar"` // 头像URL Avatar *string `json:"avatar,omitempty" gorm:"column:avatar"` // 头像URL

View File

@@ -41,6 +41,7 @@ func newAdmin(db *gorm.DB, opts ...gen.DOOption) admin {
_admin.LastLogin = field.NewTime(tableName, "last_login") _admin.LastLogin = field.NewTime(tableName, "last_login")
_admin.LastLoginIP = field.NewField(tableName, "last_login_ip") _admin.LastLoginIP = field.NewField(tableName, "last_login_ip")
_admin.LastLoginUA = field.NewString(tableName, "last_login_ua") _admin.LastLoginUA = field.NewString(tableName, "last_login_ua")
_admin.Lock = field.NewBool(tableName, "lock")
_admin.Roles = adminManyToManyRoles{ _admin.Roles = adminManyToManyRoles{
db: db.Session(&gorm.Session{}), db: db.Session(&gorm.Session{}),
@@ -91,6 +92,7 @@ type admin struct {
LastLogin field.Time LastLogin field.Time
LastLoginIP field.Field LastLoginIP field.Field
LastLoginUA field.String LastLoginUA field.String
Lock field.Bool
Roles adminManyToManyRoles Roles adminManyToManyRoles
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
@@ -122,6 +124,7 @@ func (a *admin) updateTableName(table string) *admin {
a.LastLogin = field.NewTime(table, "last_login") a.LastLogin = field.NewTime(table, "last_login")
a.LastLoginIP = field.NewField(table, "last_login_ip") a.LastLoginIP = field.NewField(table, "last_login_ip")
a.LastLoginUA = field.NewString(table, "last_login_ua") a.LastLoginUA = field.NewString(table, "last_login_ua")
a.Lock = field.NewBool(table, "lock")
a.fillFieldMap() a.fillFieldMap()
@@ -138,7 +141,7 @@ func (a *admin) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
} }
func (a *admin) fillFieldMap() { func (a *admin) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 15) a.fieldMap = make(map[string]field.Expr, 16)
a.fieldMap["id"] = a.ID a.fieldMap["id"] = a.ID
a.fieldMap["created_at"] = a.CreatedAt a.fieldMap["created_at"] = a.CreatedAt
a.fieldMap["updated_at"] = a.UpdatedAt a.fieldMap["updated_at"] = a.UpdatedAt
@@ -153,6 +156,7 @@ func (a *admin) fillFieldMap() {
a.fieldMap["last_login"] = a.LastLogin a.fieldMap["last_login"] = a.LastLogin
a.fieldMap["last_login_ip"] = a.LastLoginIP a.fieldMap["last_login_ip"] = a.LastLoginIP
a.fieldMap["last_login_ua"] = a.LastLoginUA a.fieldMap["last_login_ua"] = a.LastLoginUA
a.fieldMap["lock"] = a.Lock
} }

View File

@@ -36,10 +36,10 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
_balanceActivity.BalanceCurr = field.NewString(tableName, "balance_curr") _balanceActivity.BalanceCurr = field.NewString(tableName, "balance_curr")
_balanceActivity.Remark = field.NewString(tableName, "remark") _balanceActivity.Remark = field.NewString(tableName, "remark")
_balanceActivity.CreatedAt = field.NewTime(tableName, "created_at") _balanceActivity.CreatedAt = field.NewTime(tableName, "created_at")
_balanceActivity.Admin = balanceActivityHasOneAdmin{ _balanceActivity.User = balanceActivityBelongsToUser{
db: db.Session(&gorm.Session{}), db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Admin", "models.User"), RelationField: field.NewRelation("User", "models.User"),
Admin: struct { Admin: struct {
field.RelationField field.RelationField
Roles struct { Roles struct {
@@ -55,7 +55,7 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
} }
} }
}{ }{
RelationField: field.NewRelation("Admin.Admin", "models.Admin"), RelationField: field.NewRelation("User.Admin", "models.Admin"),
Roles: struct { Roles: struct {
field.RelationField field.RelationField
Permissions struct { Permissions struct {
@@ -68,7 +68,7 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
} }
} }
}{ }{
RelationField: field.NewRelation("Admin.Admin.Roles", "models.AdminRole"), RelationField: field.NewRelation("User.Admin.Roles", "models.AdminRole"),
Permissions: struct { Permissions: struct {
field.RelationField field.RelationField
Parent struct { Parent struct {
@@ -78,16 +78,16 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
field.RelationField field.RelationField
} }
}{ }{
RelationField: field.NewRelation("Admin.Admin.Roles.Permissions", "models.Permission"), RelationField: field.NewRelation("User.Admin.Roles.Permissions", "models.Permission"),
Parent: struct { Parent: struct {
field.RelationField field.RelationField
}{ }{
RelationField: field.NewRelation("Admin.Admin.Roles.Permissions.Parent", "models.Permission"), RelationField: field.NewRelation("User.Admin.Roles.Permissions.Parent", "models.Permission"),
}, },
Children: struct { Children: struct {
field.RelationField field.RelationField
}{ }{
RelationField: field.NewRelation("Admin.Admin.Roles.Permissions.Children", "models.Permission"), RelationField: field.NewRelation("User.Admin.Roles.Permissions.Children", "models.Permission"),
}, },
}, },
}, },
@@ -95,7 +95,7 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
Discount: struct { Discount: struct {
field.RelationField field.RelationField
}{ }{
RelationField: field.NewRelation("Admin.Discount", "models.ProductDiscount"), RelationField: field.NewRelation("User.Discount", "models.ProductDiscount"),
}, },
Roles: struct { Roles: struct {
field.RelationField field.RelationField
@@ -103,21 +103,15 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
field.RelationField field.RelationField
} }
}{ }{
RelationField: field.NewRelation("Admin.Roles", "models.UserRole"), RelationField: field.NewRelation("User.Roles", "models.UserRole"),
Permissions: struct { Permissions: struct {
field.RelationField field.RelationField
}{ }{
RelationField: field.NewRelation("Admin.Roles.Permissions", "models.Permission"), RelationField: field.NewRelation("User.Roles.Permissions", "models.Permission"),
}, },
}, },
} }
_balanceActivity.User = balanceActivityBelongsToUser{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("User", "models.User"),
}
_balanceActivity.Bill = balanceActivityBelongsToBill{ _balanceActivity.Bill = balanceActivityBelongsToBill{
db: db.Session(&gorm.Session{}), db: db.Session(&gorm.Session{}),
@@ -151,6 +145,9 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -179,6 +176,9 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -190,6 +190,9 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -198,8 +201,16 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
RelationField: field.NewRelation("Bill.Resource.Short.Sku", "models.ProductSku"), RelationField: field.NewRelation("Bill.Resource.Short.Sku", "models.ProductSku"),
Product: struct { Product: struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
}{ }{
RelationField: field.NewRelation("Bill.Resource.Short.Sku.Product", "models.Product"), RelationField: field.NewRelation("Bill.Resource.Short.Sku.Product", "models.Product"),
Skus: struct {
field.RelationField
}{
RelationField: field.NewRelation("Bill.Resource.Short.Sku.Product.Skus", "models.ProductSku"),
},
}, },
Discount: struct { Discount: struct {
field.RelationField field.RelationField
@@ -232,6 +243,33 @@ func newBalanceActivity(db *gorm.DB, opts ...gen.DOOption) balanceActivity {
}{ }{
RelationField: field.NewRelation("Bill.Refund", "models.Refund"), RelationField: field.NewRelation("Bill.Refund", "models.Refund"),
}, },
CouponUser: struct {
field.RelationField
Coupon struct {
field.RelationField
}
User struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Bill.CouponUser", "models.CouponUser"),
Coupon: struct {
field.RelationField
}{
RelationField: field.NewRelation("Bill.CouponUser.Coupon", "models.Coupon"),
},
User: struct {
field.RelationField
}{
RelationField: field.NewRelation("Bill.CouponUser.User", "models.User"),
},
},
}
_balanceActivity.Admin = balanceActivityBelongsToAdmin{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Admin", "models.Admin"),
} }
_balanceActivity.fillFieldMap() _balanceActivity.fillFieldMap()
@@ -252,12 +290,12 @@ type balanceActivity struct {
BalanceCurr field.String BalanceCurr field.String
Remark field.String Remark field.String
CreatedAt field.Time CreatedAt field.Time
Admin balanceActivityHasOneAdmin User balanceActivityBelongsToUser
User balanceActivityBelongsToUser
Bill balanceActivityBelongsToBill Bill balanceActivityBelongsToBill
Admin balanceActivityBelongsToAdmin
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
} }
@@ -313,24 +351,24 @@ func (b *balanceActivity) fillFieldMap() {
func (b balanceActivity) clone(db *gorm.DB) balanceActivity { func (b balanceActivity) clone(db *gorm.DB) balanceActivity {
b.balanceActivityDo.ReplaceConnPool(db.Statement.ConnPool) 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 = db.Session(&gorm.Session{Initialized: true})
b.User.db.Statement.ConnPool = db.Statement.ConnPool b.User.db.Statement.ConnPool = db.Statement.ConnPool
b.Bill.db = db.Session(&gorm.Session{Initialized: true}) b.Bill.db = db.Session(&gorm.Session{Initialized: true})
b.Bill.db.Statement.ConnPool = db.Statement.ConnPool b.Bill.db.Statement.ConnPool = db.Statement.ConnPool
b.Admin.db = db.Session(&gorm.Session{Initialized: true})
b.Admin.db.Statement.ConnPool = db.Statement.ConnPool
return b return b
} }
func (b balanceActivity) replaceDB(db *gorm.DB) balanceActivity { func (b balanceActivity) replaceDB(db *gorm.DB) balanceActivity {
b.balanceActivityDo.ReplaceDB(db) b.balanceActivityDo.ReplaceDB(db)
b.Admin.db = db.Session(&gorm.Session{})
b.User.db = db.Session(&gorm.Session{}) b.User.db = db.Session(&gorm.Session{})
b.Bill.db = db.Session(&gorm.Session{}) b.Bill.db = db.Session(&gorm.Session{})
b.Admin.db = db.Session(&gorm.Session{})
return b return b
} }
type balanceActivityHasOneAdmin struct { type balanceActivityBelongsToUser struct {
db *gorm.DB db *gorm.DB
field.RelationField field.RelationField
@@ -361,87 +399,6 @@ type balanceActivityHasOneAdmin struct {
} }
} }
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 { func (a balanceActivityBelongsToUser) Where(conds ...field.Expr) *balanceActivityBelongsToUser {
if len(conds) == 0 { if len(conds) == 0 {
return &a return &a
@@ -542,6 +499,9 @@ type balanceActivityBelongsToBill struct {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -561,6 +521,15 @@ type balanceActivityBelongsToBill struct {
Refund struct { Refund struct {
field.RelationField field.RelationField
} }
CouponUser struct {
field.RelationField
Coupon struct {
field.RelationField
}
User struct {
field.RelationField
}
}
} }
func (a balanceActivityBelongsToBill) Where(conds ...field.Expr) *balanceActivityBelongsToBill { func (a balanceActivityBelongsToBill) Where(conds ...field.Expr) *balanceActivityBelongsToBill {
@@ -638,6 +607,87 @@ func (a balanceActivityBelongsToBillTx) Unscoped() *balanceActivityBelongsToBill
return &a return &a
} }
type balanceActivityBelongsToAdmin struct {
db *gorm.DB
field.RelationField
}
func (a balanceActivityBelongsToAdmin) Where(conds ...field.Expr) *balanceActivityBelongsToAdmin {
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 balanceActivityBelongsToAdmin) WithContext(ctx context.Context) *balanceActivityBelongsToAdmin {
a.db = a.db.WithContext(ctx)
return &a
}
func (a balanceActivityBelongsToAdmin) Session(session *gorm.Session) *balanceActivityBelongsToAdmin {
a.db = a.db.Session(session)
return &a
}
func (a balanceActivityBelongsToAdmin) Model(m *models.BalanceActivity) *balanceActivityBelongsToAdminTx {
return &balanceActivityBelongsToAdminTx{a.db.Model(m).Association(a.Name())}
}
func (a balanceActivityBelongsToAdmin) Unscoped() *balanceActivityBelongsToAdmin {
a.db = a.db.Unscoped()
return &a
}
type balanceActivityBelongsToAdminTx struct{ tx *gorm.Association }
func (a balanceActivityBelongsToAdminTx) Find() (result *models.Admin, err error) {
return result, a.tx.Find(&result)
}
func (a balanceActivityBelongsToAdminTx) Append(values ...*models.Admin) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a balanceActivityBelongsToAdminTx) Replace(values ...*models.Admin) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a balanceActivityBelongsToAdminTx) Delete(values ...*models.Admin) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a balanceActivityBelongsToAdminTx) Clear() error {
return a.tx.Clear()
}
func (a balanceActivityBelongsToAdminTx) Count() int64 {
return a.tx.Count()
}
func (a balanceActivityBelongsToAdminTx) Unscoped() *balanceActivityBelongsToAdminTx {
a.tx = a.tx.Unscoped()
return &a
}
type balanceActivityDo struct{ gen.DO } type balanceActivityDo struct{ gen.DO }
func (b balanceActivityDo) Debug() *balanceActivityDo { func (b balanceActivityDo) Debug() *balanceActivityDo {

View File

@@ -35,7 +35,7 @@ func newBill(db *gorm.DB, opts ...gen.DOOption) bill {
_bill.TradeID = field.NewInt32(tableName, "trade_id") _bill.TradeID = field.NewInt32(tableName, "trade_id")
_bill.ResourceID = field.NewInt32(tableName, "resource_id") _bill.ResourceID = field.NewInt32(tableName, "resource_id")
_bill.RefundID = field.NewInt32(tableName, "refund_id") _bill.RefundID = field.NewInt32(tableName, "refund_id")
_bill.CouponID = field.NewInt32(tableName, "coupon_id") _bill.CouponUserID = field.NewInt32(tableName, "coupon_user_id")
_bill.BillNo = field.NewString(tableName, "bill_no") _bill.BillNo = field.NewString(tableName, "bill_no")
_bill.Info = field.NewString(tableName, "info") _bill.Info = field.NewString(tableName, "info")
_bill.Type = field.NewInt(tableName, "type") _bill.Type = field.NewInt(tableName, "type")
@@ -143,6 +143,9 @@ func newBill(db *gorm.DB, opts ...gen.DOOption) bill {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -154,6 +157,9 @@ func newBill(db *gorm.DB, opts ...gen.DOOption) bill {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -162,8 +168,16 @@ func newBill(db *gorm.DB, opts ...gen.DOOption) bill {
RelationField: field.NewRelation("Resource.Short.Sku", "models.ProductSku"), RelationField: field.NewRelation("Resource.Short.Sku", "models.ProductSku"),
Product: struct { Product: struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
}{ }{
RelationField: field.NewRelation("Resource.Short.Sku.Product", "models.Product"), RelationField: field.NewRelation("Resource.Short.Sku.Product", "models.Product"),
Skus: struct {
field.RelationField
}{
RelationField: field.NewRelation("Resource.Short.Sku.Product.Skus", "models.ProductSku"),
},
}, },
Discount: struct { Discount: struct {
field.RelationField field.RelationField
@@ -198,6 +212,22 @@ func newBill(db *gorm.DB, opts ...gen.DOOption) bill {
RelationField: field.NewRelation("Refund", "models.Refund"), RelationField: field.NewRelation("Refund", "models.Refund"),
} }
_bill.CouponUser = billBelongsToCouponUser{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("CouponUser", "models.CouponUser"),
Coupon: struct {
field.RelationField
}{
RelationField: field.NewRelation("CouponUser.Coupon", "models.Coupon"),
},
User: struct {
field.RelationField
}{
RelationField: field.NewRelation("CouponUser.User", "models.User"),
},
}
_bill.fillFieldMap() _bill.fillFieldMap()
return _bill return _bill
@@ -206,22 +236,22 @@ func newBill(db *gorm.DB, opts ...gen.DOOption) bill {
type bill struct { type bill struct {
billDo billDo
ALL field.Asterisk ALL field.Asterisk
ID field.Int32 ID field.Int32
CreatedAt field.Time CreatedAt field.Time
UpdatedAt field.Time UpdatedAt field.Time
DeletedAt field.Field DeletedAt field.Field
UserID field.Int32 UserID field.Int32
TradeID field.Int32 TradeID field.Int32
ResourceID field.Int32 ResourceID field.Int32
RefundID field.Int32 RefundID field.Int32
CouponID field.Int32 CouponUserID field.Int32
BillNo field.String BillNo field.String
Info field.String Info field.String
Type field.Int Type field.Int
Amount field.Field Amount field.Field
Actual field.Field Actual field.Field
User billBelongsToUser User billBelongsToUser
Trade billBelongsToTrade Trade billBelongsToTrade
@@ -229,6 +259,8 @@ type bill struct {
Refund billBelongsToRefund Refund billBelongsToRefund
CouponUser billBelongsToCouponUser
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
} }
@@ -252,7 +284,7 @@ func (b *bill) updateTableName(table string) *bill {
b.TradeID = field.NewInt32(table, "trade_id") b.TradeID = field.NewInt32(table, "trade_id")
b.ResourceID = field.NewInt32(table, "resource_id") b.ResourceID = field.NewInt32(table, "resource_id")
b.RefundID = field.NewInt32(table, "refund_id") b.RefundID = field.NewInt32(table, "refund_id")
b.CouponID = field.NewInt32(table, "coupon_id") b.CouponUserID = field.NewInt32(table, "coupon_user_id")
b.BillNo = field.NewString(table, "bill_no") b.BillNo = field.NewString(table, "bill_no")
b.Info = field.NewString(table, "info") b.Info = field.NewString(table, "info")
b.Type = field.NewInt(table, "type") b.Type = field.NewInt(table, "type")
@@ -274,7 +306,7 @@ func (b *bill) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
} }
func (b *bill) fillFieldMap() { func (b *bill) fillFieldMap() {
b.fieldMap = make(map[string]field.Expr, 18) b.fieldMap = make(map[string]field.Expr, 19)
b.fieldMap["id"] = b.ID b.fieldMap["id"] = b.ID
b.fieldMap["created_at"] = b.CreatedAt b.fieldMap["created_at"] = b.CreatedAt
b.fieldMap["updated_at"] = b.UpdatedAt b.fieldMap["updated_at"] = b.UpdatedAt
@@ -283,7 +315,7 @@ func (b *bill) fillFieldMap() {
b.fieldMap["trade_id"] = b.TradeID b.fieldMap["trade_id"] = b.TradeID
b.fieldMap["resource_id"] = b.ResourceID b.fieldMap["resource_id"] = b.ResourceID
b.fieldMap["refund_id"] = b.RefundID b.fieldMap["refund_id"] = b.RefundID
b.fieldMap["coupon_id"] = b.CouponID b.fieldMap["coupon_user_id"] = b.CouponUserID
b.fieldMap["bill_no"] = b.BillNo b.fieldMap["bill_no"] = b.BillNo
b.fieldMap["info"] = b.Info b.fieldMap["info"] = b.Info
b.fieldMap["type"] = b.Type b.fieldMap["type"] = b.Type
@@ -302,6 +334,8 @@ func (b bill) clone(db *gorm.DB) bill {
b.Resource.db.Statement.ConnPool = db.Statement.ConnPool b.Resource.db.Statement.ConnPool = db.Statement.ConnPool
b.Refund.db = db.Session(&gorm.Session{Initialized: true}) b.Refund.db = db.Session(&gorm.Session{Initialized: true})
b.Refund.db.Statement.ConnPool = db.Statement.ConnPool b.Refund.db.Statement.ConnPool = db.Statement.ConnPool
b.CouponUser.db = db.Session(&gorm.Session{Initialized: true})
b.CouponUser.db.Statement.ConnPool = db.Statement.ConnPool
return b return b
} }
@@ -311,6 +345,7 @@ func (b bill) replaceDB(db *gorm.DB) bill {
b.Trade.db = db.Session(&gorm.Session{}) b.Trade.db = db.Session(&gorm.Session{})
b.Resource.db = db.Session(&gorm.Session{}) b.Resource.db = db.Session(&gorm.Session{})
b.Refund.db = db.Session(&gorm.Session{}) b.Refund.db = db.Session(&gorm.Session{})
b.CouponUser.db = db.Session(&gorm.Session{})
return b return b
} }
@@ -519,6 +554,9 @@ type billBelongsToResource struct {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -692,6 +730,94 @@ func (a billBelongsToRefundTx) Unscoped() *billBelongsToRefundTx {
return &a return &a
} }
type billBelongsToCouponUser struct {
db *gorm.DB
field.RelationField
Coupon struct {
field.RelationField
}
User struct {
field.RelationField
}
}
func (a billBelongsToCouponUser) Where(conds ...field.Expr) *billBelongsToCouponUser {
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 billBelongsToCouponUser) WithContext(ctx context.Context) *billBelongsToCouponUser {
a.db = a.db.WithContext(ctx)
return &a
}
func (a billBelongsToCouponUser) Session(session *gorm.Session) *billBelongsToCouponUser {
a.db = a.db.Session(session)
return &a
}
func (a billBelongsToCouponUser) Model(m *models.Bill) *billBelongsToCouponUserTx {
return &billBelongsToCouponUserTx{a.db.Model(m).Association(a.Name())}
}
func (a billBelongsToCouponUser) Unscoped() *billBelongsToCouponUser {
a.db = a.db.Unscoped()
return &a
}
type billBelongsToCouponUserTx struct{ tx *gorm.Association }
func (a billBelongsToCouponUserTx) Find() (result *models.CouponUser, err error) {
return result, a.tx.Find(&result)
}
func (a billBelongsToCouponUserTx) Append(values ...*models.CouponUser) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a billBelongsToCouponUserTx) Replace(values ...*models.CouponUser) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a billBelongsToCouponUserTx) Delete(values ...*models.CouponUser) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a billBelongsToCouponUserTx) Clear() error {
return a.tx.Clear()
}
func (a billBelongsToCouponUserTx) Count() int64 {
return a.tx.Count()
}
func (a billBelongsToCouponUserTx) Unscoped() *billBelongsToCouponUserTx {
a.tx = a.tx.Unscoped()
return &a
}
type billDo struct{ gen.DO } type billDo struct{ gen.DO }
func (b billDo) Debug() *billDo { func (b billDo) Debug() *billDo {

View File

@@ -138,6 +138,9 @@ func newChannel(db *gorm.DB, opts ...gen.DOOption) channel {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -149,6 +152,9 @@ func newChannel(db *gorm.DB, opts ...gen.DOOption) channel {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -157,8 +163,16 @@ func newChannel(db *gorm.DB, opts ...gen.DOOption) channel {
RelationField: field.NewRelation("Resource.Short.Sku", "models.ProductSku"), RelationField: field.NewRelation("Resource.Short.Sku", "models.ProductSku"),
Product: struct { Product: struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
}{ }{
RelationField: field.NewRelation("Resource.Short.Sku.Product", "models.Product"), RelationField: field.NewRelation("Resource.Short.Sku.Product", "models.Product"),
Skus: struct {
field.RelationField
}{
RelationField: field.NewRelation("Resource.Short.Sku.Product.Skus", "models.ProductSku"),
},
}, },
Discount: struct { Discount: struct {
field.RelationField field.RelationField
@@ -490,6 +504,9 @@ type channelBelongsToResource struct {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField

View File

@@ -31,13 +31,14 @@ func newCoupon(db *gorm.DB, opts ...gen.DOOption) coupon {
_coupon.CreatedAt = field.NewTime(tableName, "created_at") _coupon.CreatedAt = field.NewTime(tableName, "created_at")
_coupon.UpdatedAt = field.NewTime(tableName, "updated_at") _coupon.UpdatedAt = field.NewTime(tableName, "updated_at")
_coupon.DeletedAt = field.NewField(tableName, "deleted_at") _coupon.DeletedAt = field.NewField(tableName, "deleted_at")
_coupon.UserID = field.NewInt32(tableName, "user_id") _coupon.Name = field.NewString(tableName, "name")
_coupon.Code = field.NewString(tableName, "code")
_coupon.Remark = field.NewString(tableName, "remark")
_coupon.Amount = field.NewField(tableName, "amount") _coupon.Amount = field.NewField(tableName, "amount")
_coupon.MinAmount = field.NewField(tableName, "min_amount") _coupon.MinAmount = field.NewField(tableName, "min_amount")
_coupon.Count_ = field.NewInt32(tableName, "count")
_coupon.Status = field.NewInt(tableName, "status") _coupon.Status = field.NewInt(tableName, "status")
_coupon.ExpireType = field.NewInt(tableName, "expire_type")
_coupon.ExpireAt = field.NewTime(tableName, "expire_at") _coupon.ExpireAt = field.NewTime(tableName, "expire_at")
_coupon.ExpireIn = field.NewInt(tableName, "expire_in")
_coupon.fillFieldMap() _coupon.fillFieldMap()
@@ -47,18 +48,19 @@ func newCoupon(db *gorm.DB, opts ...gen.DOOption) coupon {
type coupon struct { type coupon struct {
couponDo couponDo
ALL field.Asterisk ALL field.Asterisk
ID field.Int32 ID field.Int32
CreatedAt field.Time CreatedAt field.Time
UpdatedAt field.Time UpdatedAt field.Time
DeletedAt field.Field DeletedAt field.Field
UserID field.Int32 Name field.String
Code field.String Amount field.Field
Remark field.String MinAmount field.Field
Amount field.Field Count_ field.Int32
MinAmount field.Field Status field.Int
Status field.Int ExpireType field.Int
ExpireAt field.Time ExpireAt field.Time
ExpireIn field.Int
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
} }
@@ -79,13 +81,14 @@ func (c *coupon) updateTableName(table string) *coupon {
c.CreatedAt = field.NewTime(table, "created_at") c.CreatedAt = field.NewTime(table, "created_at")
c.UpdatedAt = field.NewTime(table, "updated_at") c.UpdatedAt = field.NewTime(table, "updated_at")
c.DeletedAt = field.NewField(table, "deleted_at") c.DeletedAt = field.NewField(table, "deleted_at")
c.UserID = field.NewInt32(table, "user_id") c.Name = field.NewString(table, "name")
c.Code = field.NewString(table, "code")
c.Remark = field.NewString(table, "remark")
c.Amount = field.NewField(table, "amount") c.Amount = field.NewField(table, "amount")
c.MinAmount = field.NewField(table, "min_amount") c.MinAmount = field.NewField(table, "min_amount")
c.Count_ = field.NewInt32(table, "count")
c.Status = field.NewInt(table, "status") c.Status = field.NewInt(table, "status")
c.ExpireType = field.NewInt(table, "expire_type")
c.ExpireAt = field.NewTime(table, "expire_at") c.ExpireAt = field.NewTime(table, "expire_at")
c.ExpireIn = field.NewInt(table, "expire_in")
c.fillFieldMap() c.fillFieldMap()
@@ -102,18 +105,19 @@ func (c *coupon) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
} }
func (c *coupon) fillFieldMap() { func (c *coupon) fillFieldMap() {
c.fieldMap = make(map[string]field.Expr, 11) c.fieldMap = make(map[string]field.Expr, 12)
c.fieldMap["id"] = c.ID c.fieldMap["id"] = c.ID
c.fieldMap["created_at"] = c.CreatedAt c.fieldMap["created_at"] = c.CreatedAt
c.fieldMap["updated_at"] = c.UpdatedAt c.fieldMap["updated_at"] = c.UpdatedAt
c.fieldMap["deleted_at"] = c.DeletedAt c.fieldMap["deleted_at"] = c.DeletedAt
c.fieldMap["user_id"] = c.UserID c.fieldMap["name"] = c.Name
c.fieldMap["code"] = c.Code
c.fieldMap["remark"] = c.Remark
c.fieldMap["amount"] = c.Amount c.fieldMap["amount"] = c.Amount
c.fieldMap["min_amount"] = c.MinAmount c.fieldMap["min_amount"] = c.MinAmount
c.fieldMap["count"] = c.Count_
c.fieldMap["status"] = c.Status c.fieldMap["status"] = c.Status
c.fieldMap["expire_type"] = c.ExpireType
c.fieldMap["expire_at"] = c.ExpireAt c.fieldMap["expire_at"] = c.ExpireAt
c.fieldMap["expire_in"] = c.ExpireIn
} }
func (c coupon) clone(db *gorm.DB) coupon { func (c coupon) clone(db *gorm.DB) coupon {

View File

@@ -0,0 +1,621 @@
// 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 newCouponUser(db *gorm.DB, opts ...gen.DOOption) couponUser {
_couponUser := couponUser{}
_couponUser.couponUserDo.UseDB(db, opts...)
_couponUser.couponUserDo.UseModel(&models.CouponUser{})
tableName := _couponUser.couponUserDo.TableName()
_couponUser.ALL = field.NewAsterisk(tableName)
_couponUser.ID = field.NewInt32(tableName, "id")
_couponUser.CouponID = field.NewInt32(tableName, "coupon_id")
_couponUser.UserID = field.NewInt32(tableName, "user_id")
_couponUser.Status = field.NewInt(tableName, "status")
_couponUser.ExpireAt = field.NewTime(tableName, "expire_at")
_couponUser.UsedAt = field.NewTime(tableName, "used_at")
_couponUser.CreatedAt = field.NewTime(tableName, "created_at")
_couponUser.Coupon = couponUserBelongsToCoupon{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Coupon", "models.Coupon"),
}
_couponUser.User = couponUserBelongsToUser{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("User", "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("User.Admin", "models.Admin"),
Roles: struct {
field.RelationField
Permissions struct {
field.RelationField
Parent struct {
field.RelationField
}
Children struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Admin.Roles", "models.AdminRole"),
Permissions: struct {
field.RelationField
Parent struct {
field.RelationField
}
Children struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Admin.Roles.Permissions", "models.Permission"),
Parent: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Admin.Roles.Permissions.Parent", "models.Permission"),
},
Children: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Admin.Roles.Permissions.Children", "models.Permission"),
},
},
},
},
Discount: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Discount", "models.ProductDiscount"),
},
Roles: struct {
field.RelationField
Permissions struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Roles", "models.UserRole"),
Permissions: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Roles.Permissions", "models.Permission"),
},
},
}
_couponUser.fillFieldMap()
return _couponUser
}
type couponUser struct {
couponUserDo
ALL field.Asterisk
ID field.Int32
CouponID field.Int32
UserID field.Int32
Status field.Int
ExpireAt field.Time
UsedAt field.Time
CreatedAt field.Time
Coupon couponUserBelongsToCoupon
User couponUserBelongsToUser
fieldMap map[string]field.Expr
}
func (c couponUser) Table(newTableName string) *couponUser {
c.couponUserDo.UseTable(newTableName)
return c.updateTableName(newTableName)
}
func (c couponUser) As(alias string) *couponUser {
c.couponUserDo.DO = *(c.couponUserDo.As(alias).(*gen.DO))
return c.updateTableName(alias)
}
func (c *couponUser) updateTableName(table string) *couponUser {
c.ALL = field.NewAsterisk(table)
c.ID = field.NewInt32(table, "id")
c.CouponID = field.NewInt32(table, "coupon_id")
c.UserID = field.NewInt32(table, "user_id")
c.Status = field.NewInt(table, "status")
c.ExpireAt = field.NewTime(table, "expire_at")
c.UsedAt = field.NewTime(table, "used_at")
c.CreatedAt = field.NewTime(table, "created_at")
c.fillFieldMap()
return c
}
func (c *couponUser) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := c.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (c *couponUser) fillFieldMap() {
c.fieldMap = make(map[string]field.Expr, 9)
c.fieldMap["id"] = c.ID
c.fieldMap["coupon_id"] = c.CouponID
c.fieldMap["user_id"] = c.UserID
c.fieldMap["status"] = c.Status
c.fieldMap["expire_at"] = c.ExpireAt
c.fieldMap["used_at"] = c.UsedAt
c.fieldMap["created_at"] = c.CreatedAt
}
func (c couponUser) clone(db *gorm.DB) couponUser {
c.couponUserDo.ReplaceConnPool(db.Statement.ConnPool)
c.Coupon.db = db.Session(&gorm.Session{Initialized: true})
c.Coupon.db.Statement.ConnPool = db.Statement.ConnPool
c.User.db = db.Session(&gorm.Session{Initialized: true})
c.User.db.Statement.ConnPool = db.Statement.ConnPool
return c
}
func (c couponUser) replaceDB(db *gorm.DB) couponUser {
c.couponUserDo.ReplaceDB(db)
c.Coupon.db = db.Session(&gorm.Session{})
c.User.db = db.Session(&gorm.Session{})
return c
}
type couponUserBelongsToCoupon struct {
db *gorm.DB
field.RelationField
}
func (a couponUserBelongsToCoupon) Where(conds ...field.Expr) *couponUserBelongsToCoupon {
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 couponUserBelongsToCoupon) WithContext(ctx context.Context) *couponUserBelongsToCoupon {
a.db = a.db.WithContext(ctx)
return &a
}
func (a couponUserBelongsToCoupon) Session(session *gorm.Session) *couponUserBelongsToCoupon {
a.db = a.db.Session(session)
return &a
}
func (a couponUserBelongsToCoupon) Model(m *models.CouponUser) *couponUserBelongsToCouponTx {
return &couponUserBelongsToCouponTx{a.db.Model(m).Association(a.Name())}
}
func (a couponUserBelongsToCoupon) Unscoped() *couponUserBelongsToCoupon {
a.db = a.db.Unscoped()
return &a
}
type couponUserBelongsToCouponTx struct{ tx *gorm.Association }
func (a couponUserBelongsToCouponTx) Find() (result *models.Coupon, err error) {
return result, a.tx.Find(&result)
}
func (a couponUserBelongsToCouponTx) Append(values ...*models.Coupon) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a couponUserBelongsToCouponTx) Replace(values ...*models.Coupon) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a couponUserBelongsToCouponTx) Delete(values ...*models.Coupon) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a couponUserBelongsToCouponTx) Clear() error {
return a.tx.Clear()
}
func (a couponUserBelongsToCouponTx) Count() int64 {
return a.tx.Count()
}
func (a couponUserBelongsToCouponTx) Unscoped() *couponUserBelongsToCouponTx {
a.tx = a.tx.Unscoped()
return &a
}
type couponUserBelongsToUser 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 couponUserBelongsToUser) Where(conds ...field.Expr) *couponUserBelongsToUser {
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 couponUserBelongsToUser) WithContext(ctx context.Context) *couponUserBelongsToUser {
a.db = a.db.WithContext(ctx)
return &a
}
func (a couponUserBelongsToUser) Session(session *gorm.Session) *couponUserBelongsToUser {
a.db = a.db.Session(session)
return &a
}
func (a couponUserBelongsToUser) Model(m *models.CouponUser) *couponUserBelongsToUserTx {
return &couponUserBelongsToUserTx{a.db.Model(m).Association(a.Name())}
}
func (a couponUserBelongsToUser) Unscoped() *couponUserBelongsToUser {
a.db = a.db.Unscoped()
return &a
}
type couponUserBelongsToUserTx struct{ tx *gorm.Association }
func (a couponUserBelongsToUserTx) Find() (result *models.User, err error) {
return result, a.tx.Find(&result)
}
func (a couponUserBelongsToUserTx) 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 couponUserBelongsToUserTx) 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 couponUserBelongsToUserTx) 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 couponUserBelongsToUserTx) Clear() error {
return a.tx.Clear()
}
func (a couponUserBelongsToUserTx) Count() int64 {
return a.tx.Count()
}
func (a couponUserBelongsToUserTx) Unscoped() *couponUserBelongsToUserTx {
a.tx = a.tx.Unscoped()
return &a
}
type couponUserDo struct{ gen.DO }
func (c couponUserDo) Debug() *couponUserDo {
return c.withDO(c.DO.Debug())
}
func (c couponUserDo) WithContext(ctx context.Context) *couponUserDo {
return c.withDO(c.DO.WithContext(ctx))
}
func (c couponUserDo) ReadDB() *couponUserDo {
return c.Clauses(dbresolver.Read)
}
func (c couponUserDo) WriteDB() *couponUserDo {
return c.Clauses(dbresolver.Write)
}
func (c couponUserDo) Session(config *gorm.Session) *couponUserDo {
return c.withDO(c.DO.Session(config))
}
func (c couponUserDo) Clauses(conds ...clause.Expression) *couponUserDo {
return c.withDO(c.DO.Clauses(conds...))
}
func (c couponUserDo) Returning(value interface{}, columns ...string) *couponUserDo {
return c.withDO(c.DO.Returning(value, columns...))
}
func (c couponUserDo) Not(conds ...gen.Condition) *couponUserDo {
return c.withDO(c.DO.Not(conds...))
}
func (c couponUserDo) Or(conds ...gen.Condition) *couponUserDo {
return c.withDO(c.DO.Or(conds...))
}
func (c couponUserDo) Select(conds ...field.Expr) *couponUserDo {
return c.withDO(c.DO.Select(conds...))
}
func (c couponUserDo) Where(conds ...gen.Condition) *couponUserDo {
return c.withDO(c.DO.Where(conds...))
}
func (c couponUserDo) Order(conds ...field.Expr) *couponUserDo {
return c.withDO(c.DO.Order(conds...))
}
func (c couponUserDo) Distinct(cols ...field.Expr) *couponUserDo {
return c.withDO(c.DO.Distinct(cols...))
}
func (c couponUserDo) Omit(cols ...field.Expr) *couponUserDo {
return c.withDO(c.DO.Omit(cols...))
}
func (c couponUserDo) Join(table schema.Tabler, on ...field.Expr) *couponUserDo {
return c.withDO(c.DO.Join(table, on...))
}
func (c couponUserDo) LeftJoin(table schema.Tabler, on ...field.Expr) *couponUserDo {
return c.withDO(c.DO.LeftJoin(table, on...))
}
func (c couponUserDo) RightJoin(table schema.Tabler, on ...field.Expr) *couponUserDo {
return c.withDO(c.DO.RightJoin(table, on...))
}
func (c couponUserDo) Group(cols ...field.Expr) *couponUserDo {
return c.withDO(c.DO.Group(cols...))
}
func (c couponUserDo) Having(conds ...gen.Condition) *couponUserDo {
return c.withDO(c.DO.Having(conds...))
}
func (c couponUserDo) Limit(limit int) *couponUserDo {
return c.withDO(c.DO.Limit(limit))
}
func (c couponUserDo) Offset(offset int) *couponUserDo {
return c.withDO(c.DO.Offset(offset))
}
func (c couponUserDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *couponUserDo {
return c.withDO(c.DO.Scopes(funcs...))
}
func (c couponUserDo) Unscoped() *couponUserDo {
return c.withDO(c.DO.Unscoped())
}
func (c couponUserDo) Create(values ...*models.CouponUser) error {
if len(values) == 0 {
return nil
}
return c.DO.Create(values)
}
func (c couponUserDo) CreateInBatches(values []*models.CouponUser, batchSize int) error {
return c.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 (c couponUserDo) Save(values ...*models.CouponUser) error {
if len(values) == 0 {
return nil
}
return c.DO.Save(values)
}
func (c couponUserDo) First() (*models.CouponUser, error) {
if result, err := c.DO.First(); err != nil {
return nil, err
} else {
return result.(*models.CouponUser), nil
}
}
func (c couponUserDo) Take() (*models.CouponUser, error) {
if result, err := c.DO.Take(); err != nil {
return nil, err
} else {
return result.(*models.CouponUser), nil
}
}
func (c couponUserDo) Last() (*models.CouponUser, error) {
if result, err := c.DO.Last(); err != nil {
return nil, err
} else {
return result.(*models.CouponUser), nil
}
}
func (c couponUserDo) Find() ([]*models.CouponUser, error) {
result, err := c.DO.Find()
return result.([]*models.CouponUser), err
}
func (c couponUserDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.CouponUser, err error) {
buf := make([]*models.CouponUser, 0, batchSize)
err = c.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 (c couponUserDo) FindInBatches(result *[]*models.CouponUser, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return c.DO.FindInBatches(result, batchSize, fc)
}
func (c couponUserDo) Attrs(attrs ...field.AssignExpr) *couponUserDo {
return c.withDO(c.DO.Attrs(attrs...))
}
func (c couponUserDo) Assign(attrs ...field.AssignExpr) *couponUserDo {
return c.withDO(c.DO.Assign(attrs...))
}
func (c couponUserDo) Joins(fields ...field.RelationField) *couponUserDo {
for _, _f := range fields {
c = *c.withDO(c.DO.Joins(_f))
}
return &c
}
func (c couponUserDo) Preload(fields ...field.RelationField) *couponUserDo {
for _, _f := range fields {
c = *c.withDO(c.DO.Preload(_f))
}
return &c
}
func (c couponUserDo) FirstOrInit() (*models.CouponUser, error) {
if result, err := c.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*models.CouponUser), nil
}
}
func (c couponUserDo) FirstOrCreate() (*models.CouponUser, error) {
if result, err := c.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*models.CouponUser), nil
}
}
func (c couponUserDo) FindByPage(offset int, limit int) (result []*models.CouponUser, count int64, err error) {
result, err = c.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 = c.Offset(-1).Limit(-1).Count()
return
}
func (c couponUserDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = c.Count()
if err != nil {
return
}
err = c.Offset(offset).Limit(limit).Scan(result)
return
}
func (c couponUserDo) Scan(result interface{}) (err error) {
return c.DO.Scan(result)
}
func (c couponUserDo) Delete(models ...*models.CouponUser) (result gen.ResultInfo, err error) {
return c.DO.Delete(models)
}
func (c *couponUserDo) withDO(do gen.Dao) *couponUserDo {
c.DO = *do.(*gen.DO)
return c
}

View File

@@ -25,6 +25,7 @@ var (
Channel *channel Channel *channel
Client *client Client *client
Coupon *coupon Coupon *coupon
CouponUser *couponUser
Edge *edge Edge *edge
Inquiry *inquiry Inquiry *inquiry
LinkAdminRole *linkAdminRole LinkAdminRole *linkAdminRole
@@ -63,6 +64,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
Channel = &Q.Channel Channel = &Q.Channel
Client = &Q.Client Client = &Q.Client
Coupon = &Q.Coupon Coupon = &Q.Coupon
CouponUser = &Q.CouponUser
Edge = &Q.Edge Edge = &Q.Edge
Inquiry = &Q.Inquiry Inquiry = &Q.Inquiry
LinkAdminRole = &Q.LinkAdminRole LinkAdminRole = &Q.LinkAdminRole
@@ -102,6 +104,7 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
Channel: newChannel(db, opts...), Channel: newChannel(db, opts...),
Client: newClient(db, opts...), Client: newClient(db, opts...),
Coupon: newCoupon(db, opts...), Coupon: newCoupon(db, opts...),
CouponUser: newCouponUser(db, opts...),
Edge: newEdge(db, opts...), Edge: newEdge(db, opts...),
Inquiry: newInquiry(db, opts...), Inquiry: newInquiry(db, opts...),
LinkAdminRole: newLinkAdminRole(db, opts...), LinkAdminRole: newLinkAdminRole(db, opts...),
@@ -142,6 +145,7 @@ type Query struct {
Channel channel Channel channel
Client client Client client
Coupon coupon Coupon coupon
CouponUser couponUser
Edge edge Edge edge
Inquiry inquiry Inquiry inquiry
LinkAdminRole linkAdminRole LinkAdminRole linkAdminRole
@@ -183,6 +187,7 @@ func (q *Query) clone(db *gorm.DB) *Query {
Channel: q.Channel.clone(db), Channel: q.Channel.clone(db),
Client: q.Client.clone(db), Client: q.Client.clone(db),
Coupon: q.Coupon.clone(db), Coupon: q.Coupon.clone(db),
CouponUser: q.CouponUser.clone(db),
Edge: q.Edge.clone(db), Edge: q.Edge.clone(db),
Inquiry: q.Inquiry.clone(db), Inquiry: q.Inquiry.clone(db),
LinkAdminRole: q.LinkAdminRole.clone(db), LinkAdminRole: q.LinkAdminRole.clone(db),
@@ -231,6 +236,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
Channel: q.Channel.replaceDB(db), Channel: q.Channel.replaceDB(db),
Client: q.Client.replaceDB(db), Client: q.Client.replaceDB(db),
Coupon: q.Coupon.replaceDB(db), Coupon: q.Coupon.replaceDB(db),
CouponUser: q.CouponUser.replaceDB(db),
Edge: q.Edge.replaceDB(db), Edge: q.Edge.replaceDB(db),
Inquiry: q.Inquiry.replaceDB(db), Inquiry: q.Inquiry.replaceDB(db),
LinkAdminRole: q.LinkAdminRole.replaceDB(db), LinkAdminRole: q.LinkAdminRole.replaceDB(db),
@@ -269,6 +275,7 @@ type queryCtx struct {
Channel *channelDo Channel *channelDo
Client *clientDo Client *clientDo
Coupon *couponDo Coupon *couponDo
CouponUser *couponUserDo
Edge *edgeDo Edge *edgeDo
Inquiry *inquiryDo Inquiry *inquiryDo
LinkAdminRole *linkAdminRoleDo LinkAdminRole *linkAdminRoleDo
@@ -307,6 +314,7 @@ func (q *Query) WithContext(ctx context.Context) *queryCtx {
Channel: q.Channel.WithContext(ctx), Channel: q.Channel.WithContext(ctx),
Client: q.Client.WithContext(ctx), Client: q.Client.WithContext(ctx),
Coupon: q.Coupon.WithContext(ctx), Coupon: q.Coupon.WithContext(ctx),
CouponUser: q.CouponUser.WithContext(ctx),
Edge: q.Edge.WithContext(ctx), Edge: q.Edge.WithContext(ctx),
Inquiry: q.Inquiry.WithContext(ctx), Inquiry: q.Inquiry.WithContext(ctx),
LinkAdminRole: q.LinkAdminRole.WithContext(ctx), LinkAdminRole: q.LinkAdminRole.WithContext(ctx),

View File

@@ -128,6 +128,9 @@ func newLogsUserUsage(db *gorm.DB, opts ...gen.DOOption) logsUserUsage {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -139,6 +142,9 @@ func newLogsUserUsage(db *gorm.DB, opts ...gen.DOOption) logsUserUsage {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -147,8 +153,16 @@ func newLogsUserUsage(db *gorm.DB, opts ...gen.DOOption) logsUserUsage {
RelationField: field.NewRelation("Resource.Short.Sku", "models.ProductSku"), RelationField: field.NewRelation("Resource.Short.Sku", "models.ProductSku"),
Product: struct { Product: struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
}{ }{
RelationField: field.NewRelation("Resource.Short.Sku.Product", "models.Product"), RelationField: field.NewRelation("Resource.Short.Sku.Product", "models.Product"),
Skus: struct {
field.RelationField
}{
RelationField: field.NewRelation("Resource.Short.Sku.Product.Skus", "models.ProductSku"),
},
}, },
Discount: struct { Discount: struct {
field.RelationField field.RelationField
@@ -391,6 +405,9 @@ type logsUserUsageBelongsToResource struct {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField

View File

@@ -36,6 +36,29 @@ func newProduct(db *gorm.DB, opts ...gen.DOOption) product {
_product.Description = field.NewString(tableName, "description") _product.Description = field.NewString(tableName, "description")
_product.Sort = field.NewInt32(tableName, "sort") _product.Sort = field.NewInt32(tableName, "sort")
_product.Status = field.NewInt(tableName, "status") _product.Status = field.NewInt(tableName, "status")
_product.Skus = productHasManySkus{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Skus", "models.ProductSku"),
Product: struct {
field.RelationField
Skus struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Skus.Product", "models.Product"),
Skus: struct {
field.RelationField
}{
RelationField: field.NewRelation("Skus.Product.Skus", "models.ProductSku"),
},
},
Discount: struct {
field.RelationField
}{
RelationField: field.NewRelation("Skus.Discount", "models.ProductDiscount"),
},
}
_product.fillFieldMap() _product.fillFieldMap()
@@ -55,6 +78,7 @@ type product struct {
Description field.String Description field.String
Sort field.Int32 Sort field.Int32
Status field.Int Status field.Int
Skus productHasManySkus
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
} }
@@ -96,7 +120,7 @@ func (p *product) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
} }
func (p *product) fillFieldMap() { func (p *product) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 9) p.fieldMap = make(map[string]field.Expr, 10)
p.fieldMap["id"] = p.ID p.fieldMap["id"] = p.ID
p.fieldMap["created_at"] = p.CreatedAt p.fieldMap["created_at"] = p.CreatedAt
p.fieldMap["updated_at"] = p.UpdatedAt p.fieldMap["updated_at"] = p.UpdatedAt
@@ -106,18 +130,113 @@ func (p *product) fillFieldMap() {
p.fieldMap["description"] = p.Description p.fieldMap["description"] = p.Description
p.fieldMap["sort"] = p.Sort p.fieldMap["sort"] = p.Sort
p.fieldMap["status"] = p.Status p.fieldMap["status"] = p.Status
} }
func (p product) clone(db *gorm.DB) product { func (p product) clone(db *gorm.DB) product {
p.productDo.ReplaceConnPool(db.Statement.ConnPool) p.productDo.ReplaceConnPool(db.Statement.ConnPool)
p.Skus.db = db.Session(&gorm.Session{Initialized: true})
p.Skus.db.Statement.ConnPool = db.Statement.ConnPool
return p return p
} }
func (p product) replaceDB(db *gorm.DB) product { func (p product) replaceDB(db *gorm.DB) product {
p.productDo.ReplaceDB(db) p.productDo.ReplaceDB(db)
p.Skus.db = db.Session(&gorm.Session{})
return p return p
} }
type productHasManySkus struct {
db *gorm.DB
field.RelationField
Product struct {
field.RelationField
Skus struct {
field.RelationField
}
}
Discount struct {
field.RelationField
}
}
func (a productHasManySkus) Where(conds ...field.Expr) *productHasManySkus {
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 productHasManySkus) WithContext(ctx context.Context) *productHasManySkus {
a.db = a.db.WithContext(ctx)
return &a
}
func (a productHasManySkus) Session(session *gorm.Session) *productHasManySkus {
a.db = a.db.Session(session)
return &a
}
func (a productHasManySkus) Model(m *models.Product) *productHasManySkusTx {
return &productHasManySkusTx{a.db.Model(m).Association(a.Name())}
}
func (a productHasManySkus) Unscoped() *productHasManySkus {
a.db = a.db.Unscoped()
return &a
}
type productHasManySkusTx struct{ tx *gorm.Association }
func (a productHasManySkusTx) Find() (result []*models.ProductSku, err error) {
return result, a.tx.Find(&result)
}
func (a productHasManySkusTx) Append(values ...*models.ProductSku) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a productHasManySkusTx) Replace(values ...*models.ProductSku) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a productHasManySkusTx) Delete(values ...*models.ProductSku) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a productHasManySkusTx) Clear() error {
return a.tx.Clear()
}
func (a productHasManySkusTx) Count() int64 {
return a.tx.Count()
}
func (a productHasManySkusTx) Unscoped() *productHasManySkusTx {
a.tx = a.tx.Unscoped()
return &a
}
type productDo struct{ gen.DO } type productDo struct{ gen.DO }
func (p productDo) Debug() *productDo { func (p productDo) Debug() *productDo {

View File

@@ -36,10 +36,34 @@ func newProductSku(db *gorm.DB, opts ...gen.DOOption) productSku {
_productSku.Code = field.NewString(tableName, "code") _productSku.Code = field.NewString(tableName, "code")
_productSku.Name = field.NewString(tableName, "name") _productSku.Name = field.NewString(tableName, "name")
_productSku.Price = field.NewField(tableName, "price") _productSku.Price = field.NewField(tableName, "price")
_productSku.PriceMin = field.NewField(tableName, "price_min")
_productSku.Status = field.NewInt32(tableName, "status")
_productSku.Sort = field.NewInt32(tableName, "sort")
_productSku.Product = productSkuBelongsToProduct{ _productSku.Product = productSkuBelongsToProduct{
db: db.Session(&gorm.Session{}), db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Product", "models.Product"), RelationField: field.NewRelation("Product", "models.Product"),
Skus: struct {
field.RelationField
Product struct {
field.RelationField
}
Discount struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Product.Skus", "models.ProductSku"),
Product: struct {
field.RelationField
}{
RelationField: field.NewRelation("Product.Skus.Product", "models.Product"),
},
Discount: struct {
field.RelationField
}{
RelationField: field.NewRelation("Product.Skus.Discount", "models.ProductDiscount"),
},
},
} }
_productSku.Discount = productSkuBelongsToDiscount{ _productSku.Discount = productSkuBelongsToDiscount{
@@ -66,6 +90,9 @@ type productSku struct {
Code field.String Code field.String
Name field.String Name field.String
Price field.Field Price field.Field
PriceMin field.Field
Status field.Int32
Sort field.Int32
Product productSkuBelongsToProduct Product productSkuBelongsToProduct
Discount productSkuBelongsToDiscount Discount productSkuBelongsToDiscount
@@ -94,6 +121,9 @@ func (p *productSku) updateTableName(table string) *productSku {
p.Code = field.NewString(table, "code") p.Code = field.NewString(table, "code")
p.Name = field.NewString(table, "name") p.Name = field.NewString(table, "name")
p.Price = field.NewField(table, "price") p.Price = field.NewField(table, "price")
p.PriceMin = field.NewField(table, "price_min")
p.Status = field.NewInt32(table, "status")
p.Sort = field.NewInt32(table, "sort")
p.fillFieldMap() p.fillFieldMap()
@@ -110,7 +140,7 @@ func (p *productSku) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
} }
func (p *productSku) fillFieldMap() { func (p *productSku) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 11) p.fieldMap = make(map[string]field.Expr, 14)
p.fieldMap["id"] = p.ID p.fieldMap["id"] = p.ID
p.fieldMap["created_at"] = p.CreatedAt p.fieldMap["created_at"] = p.CreatedAt
p.fieldMap["updated_at"] = p.UpdatedAt p.fieldMap["updated_at"] = p.UpdatedAt
@@ -120,6 +150,9 @@ func (p *productSku) fillFieldMap() {
p.fieldMap["code"] = p.Code p.fieldMap["code"] = p.Code
p.fieldMap["name"] = p.Name p.fieldMap["name"] = p.Name
p.fieldMap["price"] = p.Price p.fieldMap["price"] = p.Price
p.fieldMap["price_min"] = p.PriceMin
p.fieldMap["status"] = p.Status
p.fieldMap["sort"] = p.Sort
} }
@@ -143,6 +176,16 @@ type productSkuBelongsToProduct struct {
db *gorm.DB db *gorm.DB
field.RelationField field.RelationField
Skus struct {
field.RelationField
Product struct {
field.RelationField
}
Discount struct {
field.RelationField
}
}
} }
func (a productSkuBelongsToProduct) Where(conds ...field.Expr) *productSkuBelongsToProduct { func (a productSkuBelongsToProduct) Where(conds ...field.Expr) *productSkuBelongsToProduct {

View File

@@ -115,8 +115,16 @@ func newProductSkuUser(db *gorm.DB, opts ...gen.DOOption) productSkuUser {
RelationField: field.NewRelation("ProductSku", "models.ProductSku"), RelationField: field.NewRelation("ProductSku", "models.ProductSku"),
Product: struct { Product: struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
}{ }{
RelationField: field.NewRelation("ProductSku.Product", "models.Product"), RelationField: field.NewRelation("ProductSku.Product", "models.Product"),
Skus: struct {
field.RelationField
}{
RelationField: field.NewRelation("ProductSku.Product.Skus", "models.ProductSku"),
},
}, },
Discount: struct { Discount: struct {
field.RelationField field.RelationField
@@ -331,6 +339,9 @@ type productSkuUserBelongsToProductSku struct {
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField

View File

@@ -153,6 +153,9 @@ func newProxy(db *gorm.DB, opts ...gen.DOOption) proxy {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -181,6 +184,9 @@ func newProxy(db *gorm.DB, opts ...gen.DOOption) proxy {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -192,6 +198,9 @@ func newProxy(db *gorm.DB, opts ...gen.DOOption) proxy {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -200,8 +209,16 @@ func newProxy(db *gorm.DB, opts ...gen.DOOption) proxy {
RelationField: field.NewRelation("Channels.Resource.Short.Sku", "models.ProductSku"), RelationField: field.NewRelation("Channels.Resource.Short.Sku", "models.ProductSku"),
Product: struct { Product: struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
}{ }{
RelationField: field.NewRelation("Channels.Resource.Short.Sku.Product", "models.Product"), RelationField: field.NewRelation("Channels.Resource.Short.Sku.Product", "models.Product"),
Skus: struct {
field.RelationField
}{
RelationField: field.NewRelation("Channels.Resource.Short.Sku.Product.Skus", "models.ProductSku"),
},
}, },
Discount: struct { Discount: struct {
field.RelationField field.RelationField
@@ -387,6 +404,9 @@ type proxyHasManyChannels struct {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField

View File

@@ -44,6 +44,9 @@ func newResource(db *gorm.DB, opts ...gen.DOOption) resource {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField
@@ -52,8 +55,16 @@ func newResource(db *gorm.DB, opts ...gen.DOOption) resource {
RelationField: field.NewRelation("Short.Sku", "models.ProductSku"), RelationField: field.NewRelation("Short.Sku", "models.ProductSku"),
Product: struct { Product: struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
}{ }{
RelationField: field.NewRelation("Short.Sku.Product", "models.Product"), RelationField: field.NewRelation("Short.Sku.Product", "models.Product"),
Skus: struct {
field.RelationField
}{
RelationField: field.NewRelation("Short.Sku.Product.Skus", "models.ProductSku"),
},
}, },
Discount: struct { Discount: struct {
field.RelationField field.RelationField
@@ -266,6 +277,9 @@ type resourceHasOneShort struct {
field.RelationField field.RelationField
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField

View File

@@ -43,8 +43,16 @@ func newResourceLong(db *gorm.DB, opts ...gen.DOOption) resourceLong {
RelationField: field.NewRelation("Sku", "models.ProductSku"), RelationField: field.NewRelation("Sku", "models.ProductSku"),
Product: struct { Product: struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
}{ }{
RelationField: field.NewRelation("Sku.Product", "models.Product"), RelationField: field.NewRelation("Sku.Product", "models.Product"),
Skus: struct {
field.RelationField
}{
RelationField: field.NewRelation("Sku.Product.Skus", "models.ProductSku"),
},
}, },
Discount: struct { Discount: struct {
field.RelationField field.RelationField
@@ -149,6 +157,9 @@ type resourceLongHasOneSku struct {
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField

View File

@@ -43,8 +43,16 @@ func newResourceShort(db *gorm.DB, opts ...gen.DOOption) resourceShort {
RelationField: field.NewRelation("Sku", "models.ProductSku"), RelationField: field.NewRelation("Sku", "models.ProductSku"),
Product: struct { Product: struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
}{ }{
RelationField: field.NewRelation("Sku.Product", "models.Product"), RelationField: field.NewRelation("Sku.Product", "models.Product"),
Skus: struct {
field.RelationField
}{
RelationField: field.NewRelation("Sku.Product.Skus", "models.ProductSku"),
},
}, },
Discount: struct { Discount: struct {
field.RelationField field.RelationField
@@ -149,6 +157,9 @@ type resourceShortHasOneSku struct {
Product struct { Product struct {
field.RelationField field.RelationField
Skus struct {
field.RelationField
}
} }
Discount struct { Discount struct {
field.RelationField field.RelationField

View File

@@ -109,6 +109,14 @@ func userRouter(api fiber.Router) {
// 前台 // 前台
inquiry := api.Group("/inquiry") inquiry := api.Group("/inquiry")
inquiry.Post("/create", handlers.CreateInquiry) inquiry.Post("/create", handlers.CreateInquiry)
// 产品
product := api.Group("/product")
product.Post("/list", handlers.AllProduct)
// 认证
verify := api.Group("/verify")
verify.Post("/sms/password", handlers.SendSmsCodeForPassword)
} }
// 客户端接口路由 // 客户端接口路由
@@ -116,7 +124,7 @@ func clientRouter(api fiber.Router) {
client := api client := api
// 验证短信令牌 // 验证短信令牌
client.Post("/verify/sms", handlers.SmsCode) client.Post("/verify/sms", handlers.SendSmsCode)
// 套餐定价查询 // 套餐定价查询
resource := client.Group("/resource") resource := client.Group("/resource")
@@ -159,35 +167,50 @@ 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("/page/not-bind", handlers.PageUserNotBindByAdmin)
user.Post("/get", handlers.GetUserByAdmin) 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("/update/bind", handlers.BindAdmin)
user.Post("/update/balance", handlers.UpdateUserBalanceByAdmin) user.Post("/update/balance", handlers.UpdateUserBalanceByAdmin)
user.Post("/update/balance-inc", handlers.UpdateUserBalanceIncByAdmin)
user.Post("/update/balance-dec", handlers.UpdateUserBalanceDecByAdmin)
// resource 套餐 // resource 套餐
var resource = api.Group("/resource") var resource = api.Group("/resource")
resource.Post("/short/page", handlers.PageResourceShortByAdmin) resource.Post("/short/page", handlers.PageResourceShortByAdmin)
resource.Post("/short/page/of-user", handlers.PageResourceShortOfUserByAdmin)
resource.Post("/long/page", handlers.PageResourceLongByAdmin) resource.Post("/long/page", handlers.PageResourceLongByAdmin)
resource.Post("/long/page/of-user", handlers.PageResourceLongOfUserByAdmin)
resource.Post("/update", handlers.UpdateResourceByAdmin) resource.Post("/update", handlers.UpdateResourceByAdmin)
// batch 批次 // batch 批次
var batch = api.Group("/batch") var batch = api.Group("/batch")
batch.Post("/page", handlers.PageBatchByAdmin) batch.Post("/page", handlers.PageBatchByAdmin)
batch.Post("/page/of-user", handlers.PageBatchOfUserByAdmin)
// channel 通道 // channel 通道
var channel = api.Group("/channel") var channel = api.Group("/channel")
channel.Post("/page", handlers.PageChannelByAdmin) channel.Post("/page", handlers.PageChannelByAdmin)
channel.Post("/page/of-user", handlers.PageChannelOfUserByAdmin)
// trade 交易 // trade 交易
var trade = api.Group("/trade") var trade = api.Group("/trade")
trade.Post("/page", handlers.PageTradeByAdmin) trade.Post("/page", handlers.PageTradeByAdmin)
trade.Post("/page/of-user", handlers.PageTradeOfUserByAdmin)
trade.Post("/complete", handlers.TradeCompleteByAdmin)
// bill 账单 // bill 账单
var bill = api.Group("/bill") var bill = api.Group("/bill")
bill.Post("/page", handlers.PageBillByAdmin) bill.Post("/page", handlers.PageBillByAdmin)
bill.Post("/page/of-user", handlers.PageBillOfUserByAdmin)
// balance-activity 余额变动
var balanceActivity = api.Group("/balance-activity")
balanceActivity.Post("/page", handlers.PageBalanceActivityByAdmin)
balanceActivity.Post("/page/of-user", handlers.PageBalanceActivityOfUserByAdmin)
// product 产品 // product 产品
var product = api.Group("/product") var product = api.Group("/product")
@@ -200,6 +223,7 @@ func adminRouter(api fiber.Router) {
product.Post("/sku/page", handlers.PageProductSkuByAdmin) product.Post("/sku/page", handlers.PageProductSkuByAdmin)
product.Post("/sku/create", handlers.CreateProductSku) product.Post("/sku/create", handlers.CreateProductSku)
product.Post("/sku/update", handlers.UpdateProductSku) product.Post("/sku/update", handlers.UpdateProductSku)
product.Post("/sku/update/status", handlers.UpdateProductStatusSku)
product.Post("/sku/remove", handlers.DeleteProductSku) product.Post("/sku/remove", handlers.DeleteProductSku)
product.Post("/sku/update/discount/batch", handlers.BatchUpdateProductSkuDiscount) product.Post("/sku/update/discount/batch", handlers.BatchUpdateProductSkuDiscount)

View File

@@ -15,7 +15,7 @@ var Admin = &adminService{}
type adminService struct{} type adminService struct{}
func (s *adminService) PageAdmins(req core.PageReq) (result []*m.Admin, count int64, err error) { func (s *adminService) Page(req core.PageReq) (result []*m.Admin, count int64, err error) {
return q.Admin. return q.Admin.
Preload(q.Admin.Roles). Preload(q.Admin.Roles).
Omit(q.Admin.Password). Omit(q.Admin.Password).
@@ -30,25 +30,14 @@ func (s *adminService) All() (result []*m.Admin, err error) {
Find() Find()
} }
type CreateAdmin struct { func (s *adminService) Create(create *CreateAdmin) error {
Username string `json:"username" validate:"required,min=3,max=50"`
Password string `json:"password" validate:"required,min=6,max=50"`
Name *string `json:"name"`
Avatar *string `json:"avatar"`
Phone *string `json:"phone"`
Email *string `json:"email"`
Status *m.AdminStatus `json:"status"`
Roles []int32 `json:"roles"`
}
func (s *adminService) CreateAdmin(create *CreateAdmin) error {
// 哈希密码 // 哈希密码
hash, err := bcrypt.GenerateFromPassword([]byte(create.Password), bcrypt.DefaultCost) hash, err := bcrypt.GenerateFromPassword([]byte(create.Password), bcrypt.DefaultCost)
if err != nil { if err != nil {
return core.NewServErr("密码加密失败", err) return core.NewServErr("密码加密失败", err)
} }
return q.Q.Transaction(func(tx *q.Query) error { return q.Q.Transaction(func(q *q.Query) error {
// 创建管理员 // 创建管理员
admin := &m.Admin{ admin := &m.Admin{
Username: create.Username, Username: create.Username,
@@ -59,7 +48,7 @@ func (s *adminService) CreateAdmin(create *CreateAdmin) error {
Email: create.Email, Email: create.Email,
Status: u.Else(create.Status, m.AdminStatusEnabled), Status: u.Else(create.Status, m.AdminStatusEnabled),
} }
if err := tx.Admin.Create(admin); err != nil { if err := q.Admin.Create(admin); err != nil {
return err return err
} }
@@ -72,7 +61,7 @@ func (s *adminService) CreateAdmin(create *CreateAdmin) error {
RoleID: roleID, RoleID: roleID,
} }
} }
if err := tx.LinkAdminRole.CreateInBatches(links, 1000); err != nil { if err := q.LinkAdminRole.CreateInBatches(links, 1000); err != nil {
return err return err
} }
} }
@@ -81,18 +70,18 @@ func (s *adminService) CreateAdmin(create *CreateAdmin) error {
}) })
} }
type UpdateAdmin struct { type CreateAdmin struct {
Id int32 `json:"id" validate:"required"` Username string `json:"username" validate:"required,min=3,max=50"`
Password *string `json:"password"` Password string `json:"password" validate:"required,min=6,max=50"`
Name *string `json:"name"` Name *string `json:"name"`
Avatar *string `json:"avatar"` Avatar *string `json:"avatar"`
Phone *string `json:"phone"` Phone *string `json:"phone"`
Email *string `json:"email"` Email *string `json:"email"`
Status *m.AdminStatus `json:"status"` Status *m.AdminStatus `json:"status"`
Roles *[]int32 `json:"roles"` Roles []int32 `json:"roles"`
} }
func (s *adminService) UpdateAdmin(update *UpdateAdmin) error { func (s *adminService) Update(update *UpdateAdmin) error {
simples := make([]field.AssignExpr, 0) simples := make([]field.AssignExpr, 0)
if update.Password != nil { if update.Password != nil {
@@ -118,11 +107,14 @@ func (s *adminService) UpdateAdmin(update *UpdateAdmin) error {
simples = append(simples, q.Admin.Status.Value(int(*update.Status))) simples = append(simples, q.Admin.Status.Value(int(*update.Status)))
} }
return q.Q.Transaction(func(tx *q.Query) error { return q.Q.Transaction(func(q *q.Query) error {
// 更新管理员基本信息 // 更新管理员基本信息
if len(simples) > 0 { if len(simples) > 0 {
_, err := tx.Admin. _, err := q.Admin.
Where(tx.Admin.ID.Eq(update.Id), tx.Admin.Username.Neq("admin")). Where(
q.Admin.ID.Eq(update.Id),
q.Admin.Lock.Is(false),
).
UpdateSimple(simples...) UpdateSimple(simples...)
if err != nil { if err != nil {
return err return err
@@ -132,7 +124,7 @@ func (s *adminService) UpdateAdmin(update *UpdateAdmin) error {
// 更新角色关联 // 更新角色关联
if update.Roles != nil { if update.Roles != nil {
roles := *update.Roles roles := *update.Roles
if _, err := tx.LinkAdminRole.Where(tx.LinkAdminRole.AdminID.Eq(update.Id)).Delete(); err != nil { if _, err := q.LinkAdminRole.Where(q.LinkAdminRole.AdminID.Eq(update.Id)).Delete(); err != nil {
return err return err
} }
if len(roles) > 0 { if len(roles) > 0 {
@@ -143,7 +135,7 @@ func (s *adminService) UpdateAdmin(update *UpdateAdmin) error {
RoleID: roleID, RoleID: roleID,
} }
} }
if err := tx.LinkAdminRole.CreateInBatches(links, 1000); err != nil { if err := q.LinkAdminRole.CreateInBatches(links, 1000); err != nil {
return err return err
} }
} }
@@ -153,7 +145,23 @@ func (s *adminService) UpdateAdmin(update *UpdateAdmin) error {
}) })
} }
func (s *adminService) RemoveAdmin(id int32) error { type UpdateAdmin struct {
_, err := q.Admin.Where(q.Admin.ID.Eq(id), q.Admin.Username.Neq("admin")).UpdateColumn(q.Admin.DeletedAt, time.Now()) Id int32 `json:"id" validate:"required"`
Password *string `json:"password"`
Name *string `json:"name"`
Avatar *string `json:"avatar"`
Phone *string `json:"phone"`
Email *string `json:"email"`
Status *m.AdminStatus `json:"status"`
Roles *[]int32 `json:"roles"`
}
func (s *adminService) Remove(id int32) error {
_, err := q.Admin.
Where(
q.Admin.ID.Eq(id),
q.Admin.Lock.Is(false),
).
UpdateColumn(q.Admin.DeletedAt, time.Now())
return err return err
} }

View File

@@ -9,28 +9,42 @@ var Bill = &billService{}
type billService struct{} type billService struct{}
func (s *billService) CreateForBalance(q *q.Query, uid, tradeId int32, detail *TradeDetail) error { func (s *billService) CreateForBalance(q *q.Query, uid, tradeId int32, detail *TradeDetail) (*m.Bill, error) {
return q.Bill.Create(&m.Bill{ bill := &m.Bill{
UserID: uid, UserID: uid,
BillNo: ID.GenReadable("bil"), BillNo: ID.GenReadable("bil"),
TradeID: &tradeId, TradeID: &tradeId,
Type: m.BillTypeRecharge, Type: m.BillTypeRecharge,
Info: &detail.Subject, Info: &detail.Subject,
Amount: detail.Amount, Amount: detail.Discounted,
Actual: detail.Actual, Actual: detail.Actual,
}) }
err := q.Bill.Create(bill)
if err != nil {
return nil, err
}
return bill, nil
} }
func (s *billService) CreateForResource(q *q.Query, uid, resourceId int32, tradeId *int32, detail *TradeDetail) error { func (s *billService) CreateForResource(q *q.Query, uid, resourceId int32, tradeId *int32, detail *TradeDetail) (*m.Bill, error) {
return q.Bill.Create(&m.Bill{ bill := &m.Bill{
UserID: uid, UserID: uid,
BillNo: ID.GenReadable("bil"), BillNo: ID.GenReadable("bil"),
ResourceID: &resourceId, ResourceID: &resourceId,
TradeID: tradeId, TradeID: tradeId,
CouponID: detail.CouponId, CouponUserID: detail.CouponUserId,
Type: m.BillTypeConsume, Type: m.BillTypeConsume,
Info: &detail.Subject, Info: &detail.Subject,
Amount: detail.Amount, Amount: detail.Discounted,
Actual: detail.Actual, Actual: detail.Actual,
}) }
err := q.Bill.Create(bill)
if err != nil {
return nil, err
}
return bill, nil
} }

View File

@@ -94,7 +94,7 @@ func findResource(resourceId int32, now time.Time) (*ResourceView, error) {
var sub = resource.Short var sub = resource.Short
info.ShortId = &sub.ID info.ShortId = &sub.ID
info.ExpireAt = sub.ExpireAt info.ExpireAt = sub.ExpireAt
info.Live = time.Duration(sub.Live) * time.Second info.Live = time.Duration(sub.Live) * time.Minute
info.Mode = sub.Type info.Mode = sub.Type
info.Quota = sub.Quota info.Quota = sub.Quota
info.Used = sub.Used info.Used = sub.Used

View File

@@ -229,7 +229,7 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
// 提交配置 // 提交配置
secret := strings.Split(u.Z(proxy.Secret), ":") secret := strings.Split(u.Z(proxy.Secret), ":")
gateway := g.NewGateway(proxy.IP.String(), secret[0], secret[1]) gateway := g.NewGateway(proxy.IP.String(), secret[0], secret[1])
if env.DebugExternalChange { if env.RunMode == env.RunModeProd {
// 连接节点到网关 // 连接节点到网关
err = g.Cloud.CloudConnect(&g.CloudConnectReq{ err = g.Cloud.CloudConnect(&g.CloudConnectReq{
@@ -292,7 +292,8 @@ func (s *channelBaiyinProvider) RemoveChannels(batch string) error {
} }
// 提交配置 // 提交配置
if env.DebugExternalChange { if env.RunMode == env.RunModeProd {
// 断开节点连接 // 断开节点连接
g.Cloud.CloudDisconnect(&g.CloudDisconnectReq{ g.Cloud.CloudDisconnect(&g.CloudDisconnectReq{
Uuid: proxy.Mac, Uuid: proxy.Mac,

View File

@@ -3,6 +3,7 @@ package services
import ( import (
"errors" "errors"
"fmt" "fmt"
"platform/pkg/u"
"platform/web/core" "platform/web/core"
m "platform/web/models" m "platform/web/models"
q "platform/web/queries" q "platform/web/queries"
@@ -27,36 +28,32 @@ func (s *couponService) Page(req *core.PageReq) (result []*m.Coupon, count int64
func (s *couponService) Create(data CreateCouponData) error { func (s *couponService) Create(data CreateCouponData) error {
return q.Coupon.Create(&m.Coupon{ return q.Coupon.Create(&m.Coupon{
UserID: data.UserID, Name: data.Name,
Code: data.Code, Amount: data.Amount,
Remark: data.Remark, MinAmount: data.MinAmount,
Amount: data.Amount, Count: int32(u.Else(data.Count, 1)),
MinAmount: data.MinAmount, Status: u.Else(data.Status, m.CouponStatusEnabled),
Status: m.CouponStatusUnused, ExpireType: u.Else(data.ExpireType, m.CouponExpireTypeNever),
ExpireAt: data.ExpireAt, ExpireAt: data.ExpireAt,
ExpireIn: data.ExpireIn,
}) })
} }
type CreateCouponData struct { type CreateCouponData struct {
UserID *int32 `json:"user_id"` Name string `json:"name" validate:"required"`
Code string `json:"code" validate:"required"` Amount decimal.Decimal `json:"amount" validate:"required"`
Remark *string `json:"remark"` MinAmount decimal.Decimal `json:"min_amount"`
Amount decimal.Decimal `json:"amount" validate:"required"` Count *int `json:"count"`
MinAmount decimal.Decimal `json:"min_amount"` Status *m.CouponStatus `json:"status"`
ExpireAt *time.Time `json:"expire_at"` ExpireType *m.CouponExpireType `json:"expire_type"`
ExpireAt *time.Time `json:"expire_at"`
ExpireIn *int `json:"expire_in"`
} }
func (s *couponService) Update(data UpdateCouponData) error { func (s *couponService) Update(data UpdateCouponData) error {
do := make([]field.AssignExpr, 0) do := make([]field.AssignExpr, 0)
if data.Name != nil {
if data.UserID != nil { do = append(do, q.Coupon.Name.Value(*data.Name))
do = append(do, q.Coupon.UserID.Value(*data.UserID))
}
if data.Code != nil {
do = append(do, q.Coupon.Code.Value(*data.Code))
}
if data.Remark != nil {
do = append(do, q.Coupon.Remark.Value(*data.Remark))
} }
if data.Amount != nil { if data.Amount != nil {
do = append(do, q.Coupon.Amount.Value(*data.Amount)) do = append(do, q.Coupon.Amount.Value(*data.Amount))
@@ -64,26 +61,36 @@ func (s *couponService) Update(data UpdateCouponData) error {
if data.MinAmount != nil { if data.MinAmount != nil {
do = append(do, q.Coupon.MinAmount.Value(*data.MinAmount)) do = append(do, q.Coupon.MinAmount.Value(*data.MinAmount))
} }
if data.Count != nil {
do = append(do, q.Coupon.Count_.Value(int32(*data.Count)))
}
if data.Status != nil { if data.Status != nil {
do = append(do, q.Coupon.Status.Value(int(*data.Status))) do = append(do, q.Coupon.Status.Value(int(*data.Status)))
} }
if data.ExpireType != nil {
do = append(do, q.Coupon.ExpireType.Value(int(*data.ExpireType)))
}
if data.ExpireAt != nil { if data.ExpireAt != nil {
do = append(do, q.Coupon.ExpireAt.Value(*data.ExpireAt)) do = append(do, q.Coupon.ExpireAt.Value(*data.ExpireAt))
} }
if data.ExpireIn != nil {
do = append(do, q.Coupon.ExpireIn.Value(*data.ExpireIn))
}
_, err := q.Coupon.Where(q.Coupon.ID.Eq(data.ID)).UpdateSimple(do...) _, err := q.Coupon.Where(q.Coupon.ID.Eq(data.ID)).UpdateSimple(do...)
return err return err
} }
type UpdateCouponData struct { type UpdateCouponData struct {
ID int32 `json:"id" validate:"required"` ID int32 `json:"id" validate:"required"`
UserID *int32 `json:"user_id"` Name *string `json:"name"`
Code *string `json:"code"` Amount *decimal.Decimal `json:"amount"`
Remark *string `json:"remark"` MinAmount *decimal.Decimal `json:"min_amount"`
Amount *decimal.Decimal `json:"amount"` Count *int `json:"count"`
MinAmount *decimal.Decimal `json:"min_amount"` Status *m.CouponStatus `json:"status"`
Status *m.CouponStatus `json:"status"` ExpireType *m.CouponExpireType `json:"expire_type"`
ExpireAt *time.Time `json:"expire_at"` ExpireAt *time.Time `json:"expire_at"`
ExpireIn *int `json:"expire_in"`
} }
func (s *couponService) Delete(id int32) error { func (s *couponService) Delete(id int32) error {
@@ -91,14 +98,14 @@ func (s *couponService) Delete(id int32) error {
return err return err
} }
func (s *couponService) GetCouponAvailableByCode(code string, amount decimal.Decimal, uid *int32) (*m.Coupon, error) { // GetUserCoupon 获取用户的指定优惠券
func (s *couponService) GetUserCoupon(uid int32, cuid int32, amount decimal.Decimal) (*m.CouponUser, error) {
// 获取优惠券 // 获取优惠券
coupon, err := q.Coupon.Where( assigned, err := q.CouponUser.Joins(q.CouponUser.Coupon).Where(
q.Coupon.Code.Eq(code), q.CouponUser.ID.Eq(cuid),
q.Coupon.Status.Eq(int(m.CouponStatusUnused)), q.CouponUser.UserID.Eq(uid),
q.Coupon. q.CouponUser.Status.Eq(int(m.CouponUserStatusUnused)),
Where(q.Coupon.ExpireAt.Gt(time.Now())). q.CouponUser.ExpireAt.Gt(time.Now()),
Or(q.Coupon.ExpireAt.IsNull()),
).Take() ).Take()
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, core.NewBizErr("优惠券不存在或已失效") return nil, core.NewBizErr("优惠券不存在或已失效")
@@ -108,32 +115,22 @@ func (s *couponService) GetCouponAvailableByCode(code string, amount decimal.Dec
} }
// 检查最小使用额度 // 检查最小使用额度
if amount.Cmp(coupon.MinAmount) < 0 { if amount.Cmp(assigned.Coupon.MinAmount) < 0 {
return nil, core.NewBizErr(fmt.Sprintf("使用此优惠券的最小额度为 %s", coupon.MinAmount)) return nil, core.NewBizErr(fmt.Sprintf("使用此优惠券的最小额度为 %s", assigned.Coupon.MinAmount))
} }
// 检查所属 return assigned, nil
if coupon.UserID != nil {
if uid == nil {
return nil, core.NewBizErr("检查优惠券所属用户失败")
}
if *coupon.UserID != *uid {
return nil, core.NewBizErr("优惠券不属于当前用户")
}
}
return coupon, nil
} }
func (s *couponService) UseCoupon(q *q.Query, id int32) error { func (s *couponService) UseCoupon(q *q.Query, cuid int32) error {
_, err := q.Coupon. _, err := q.CouponUser.
Where( Where(
q.Coupon.ID.Eq(id), q.CouponUser.ID.Eq(cuid),
q.Coupon.Status.Eq(int(m.CouponStatusUnused)), q.CouponUser.Status.Eq(int(m.CouponUserStatusUnused)),
q.Coupon.ExpireAt.Gt(time.Now()),
). ).
UpdateSimple( UpdateSimple(
q.Coupon.Status.Value(int(m.CouponStatusUsed)), q.CouponUser.Status.Value(int(m.CouponUserStatusUsed)),
q.CouponUser.UsedAt.Value(time.Now()),
) )
return err return err
} }

View File

@@ -13,11 +13,6 @@ var Product = &productService{}
type productService struct{} type productService struct{}
// 获取产品价格
func (s *productService) GetPrice(code string) {
q.ProductSku.Where(q.ProductSku.Code.Eq(code)).Find()
}
// 获取所有产品 // 获取所有产品
func (s *productService) AllProducts() ([]*m.Product, error) { func (s *productService) AllProducts() ([]*m.Product, error) {
return q.Product. return q.Product.
@@ -25,6 +20,61 @@ func (s *productService) AllProducts() ([]*m.Product, error) {
Find() Find()
} }
func (s *productService) AllProductSaleInfos() ([]*m.Product, error) {
products, err := q.Product.
Select(
q.Product.ID,
q.Product.Code,
q.Product.Name,
q.Product.Description,
q.Product.Sort,
).
Where(
q.Product.Status.Eq(int(m.ProductStatusEnabled)),
).
Order(q.Product.Sort).
Find()
if err != nil {
return nil, err
}
pids := make([]int32, len(products))
for i, p := range products {
pids[i] = p.ID
}
skus, err := q.ProductSku.
Select(
q.ProductSku.ID,
q.ProductSku.ProductID,
q.ProductSku.Name,
q.ProductSku.Code,
q.ProductSku.Price,
).
Where(
q.ProductSku.ProductID.In(pids...),
q.ProductSku.Status.Eq(int32(m.SkuStatusEnabled)),
).
Order(q.ProductSku.Sort).
Find()
if err != nil {
return nil, err
}
pmap := make(map[int32]*m.Product, len(products))
for _, p := range products {
pmap[p.ID] = p
p.Skus = make([]*m.ProductSku, 0)
}
for _, s := range skus {
if p, ok := pmap[s.ProductID]; ok {
p.Skus = append(p.Skus, s)
}
}
return products, nil
}
// 新增产品 // 新增产品
func (s *productService) CreateProduct(create *CreateProductData) error { func (s *productService) CreateProduct(create *CreateProductData) error {
return q.Product.Create(&m.Product{ return q.Product.Create(&m.Product{

View File

@@ -20,7 +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()). Order(q.ProductSku.Sort).
Find() Find()
} }
@@ -30,9 +30,9 @@ func (s *productSkuService) Page(req *core.PageReq, productId *int32) (result []
do = append(do, q.ProductSku.ProductID.Eq(*productId)) do = append(do, q.ProductSku.ProductID.Eq(*productId))
} }
return q.ProductSku. return q.ProductSku.
Joins(q.ProductSku.Discount). Joins(q.ProductSku.Discount, q.ProductSku.Product).
Where(do...). Where(do...).
Order(q.ProductSku.CreatedAt.Desc()). Order(q.ProductSku.Sort).
FindByPage(req.GetOffset(), req.GetLimit()) FindByPage(req.GetOffset(), req.GetLimit())
} }
@@ -42,12 +42,18 @@ func (s *productSkuService) Create(create CreateProductSkuData) (err error) {
return core.NewBizErr("产品价格的格式不正确", err) return core.NewBizErr("产品价格的格式不正确", err)
} }
priceMin, err := decimal.NewFromString(create.PriceMin)
if err != nil {
return core.NewBizErr("产品最低价格的格式不正确", err)
}
return q.ProductSku.Create(&m.ProductSku{ return q.ProductSku.Create(&m.ProductSku{
ProductID: create.ProductID, ProductID: create.ProductID,
DiscountId: create.DiscountID, DiscountId: create.DiscountID,
Code: create.Code, Code: create.Code,
Name: create.Name, Name: create.Name,
Price: price, Price: price,
PriceMin: priceMin,
}) })
} }
@@ -57,6 +63,7 @@ type CreateProductSkuData struct {
Code string `json:"code"` Code string `json:"code"`
Name string `json:"name"` Name string `json:"name"`
Price string `json:"price"` Price string `json:"price"`
PriceMin string `json:"price_min"`
} }
func (s *productSkuService) Update(update UpdateProductSkuData) (err error) { func (s *productSkuService) Update(update UpdateProductSkuData) (err error) {
@@ -69,6 +76,13 @@ func (s *productSkuService) Update(update UpdateProductSkuData) (err error) {
} }
do = append(do, q.ProductSku.Price.Value(price)) do = append(do, q.ProductSku.Price.Value(price))
} }
if update.PriceMin != "" {
priceMin, err := decimal.NewFromString(update.PriceMin)
if err != nil {
return core.NewBizErr("产品最低价格的格式不正确", err)
}
do = append(do, q.ProductSku.PriceMin.Value(priceMin))
}
if update.DiscountID != nil { if update.DiscountID != nil {
do = append(do, q.ProductSku.DiscountId.Value(*update.DiscountID)) do = append(do, q.ProductSku.DiscountId.Value(*update.DiscountID))
} }
@@ -78,6 +92,9 @@ func (s *productSkuService) Update(update UpdateProductSkuData) (err error) {
if update.Name != nil { if update.Name != nil {
do = append(do, q.ProductSku.Name.Value(*update.Name)) do = append(do, q.ProductSku.Name.Value(*update.Name))
} }
if update.Status != nil {
do = append(do, q.ProductSku.Status.Value(*update.Status))
}
_, err = q.ProductSku.Where(q.ProductSku.ID.Eq(update.ID)).UpdateSimple(do...) _, err = q.ProductSku.Where(q.ProductSku.ID.Eq(update.ID)).UpdateSimple(do...)
return err return err
@@ -89,6 +106,8 @@ type UpdateProductSkuData struct {
Code *string `json:"code"` Code *string `json:"code"`
Name *string `json:"name"` Name *string `json:"name"`
Price *string `json:"price"` Price *string `json:"price"`
PriceMin string `json:"price_min"`
Status *int32 `json:"status"`
} }
func (s *productSkuService) Delete(id int32) (err error) { func (s *productSkuService) Delete(id int32) (err error) {

View File

@@ -28,11 +28,6 @@ func (s *resourceService) CreateResourceByBalance(user *m.User, data *CreateReso
return q.Q.Transaction(func(q *q.Query) error { return q.Q.Transaction(func(q *q.Query) error {
// 更新用户余额
if err := User.UpdateBalance(q, user, detail.Actual.Neg(), "余额购买产品", nil); err != nil {
return core.NewServErr("更新用户余额失败", err)
}
// 保存套餐 // 保存套餐
resource, err := s.Create(q, user.ID, now, data) resource, err := s.Create(q, user.ID, now, data)
if err != nil { if err != nil {
@@ -40,14 +35,19 @@ func (s *resourceService) CreateResourceByBalance(user *m.User, data *CreateReso
} }
// 生成账单 // 生成账单
err = Bill.CreateForResource(q, user.ID, resource.ID, nil, detail) bill, err := Bill.CreateForResource(q, user.ID, resource.ID, nil, detail)
if err != nil { if err != nil {
return core.NewServErr("生成账单失败", err) return core.NewServErr("生成账单失败", err)
} }
// 更新用户余额
if err := User.UpdateBalance(q, user, detail.Actual.Neg(), "余额购买产品", nil, &bill.ID); err != nil {
return core.NewServErr("更新用户余额失败", err)
}
// 核销优惠券 // 核销优惠券
if detail.CouponId != nil { if detail.CouponUserId != nil {
err = Coupon.UseCoupon(q, *detail.CouponId) err = Coupon.UseCoupon(q, *detail.CouponUserId)
if err != nil { if err != nil {
return core.NewServErr("核销优惠券失败", err) return core.NewServErr("核销优惠券失败", err)
} }
@@ -144,35 +144,35 @@ type UpdateResourceData struct {
Active *bool `json:"active"` Active *bool `json:"active"`
} }
func (s *resourceService) CalcPrice(skuCode string, count int32, user *m.User, couponCode *string) (*m.ProductSku, *m.ProductDiscount, *m.Coupon, decimal.Decimal, decimal.Decimal, error) { func (s *resourceService) CalcPrice(skuCode string, count int32, user *m.User, cuid *int32) (*m.ProductSku, *m.ProductDiscount, *m.CouponUser, decimal.Decimal, decimal.Decimal, decimal.Decimal, error) {
sku, err := q.ProductSku. sku, err := q.ProductSku.
Joins(q.ProductSku.Discount). Joins(q.ProductSku.Discount).
Where(q.ProductSku.Code.Eq(skuCode)). Where(q.ProductSku.Code.Eq(skuCode), q.ProductSku.Status.Eq(int32(m.SkuStatusEnabled))).
Take() Take()
if err != nil { if err != nil {
return nil, nil, nil, decimal.Zero, decimal.Zero, core.NewServErr("产品不可用", err) return nil, nil, nil, decimal.Zero, decimal.Zero, decimal.Zero, core.NewServErr(fmt.Sprintf("产品不可用 %s", skuCode), err)
} }
// 原价 // 原价
price := sku.Price amountMin := sku.PriceMin.Mul(decimal.NewFromInt32(count))
amount := price.Mul(decimal.NewFromInt32(count)) amount := sku.Price.Mul(decimal.NewFromInt32(count))
// 折扣价 // 折扣价
discount := sku.Discount discount := sku.Discount
if discount == nil { if discount == nil {
return nil, nil, nil, decimal.Zero, decimal.Zero, core.NewServErr("价格查询失败", err) return nil, nil, nil, decimal.Zero, decimal.Zero, decimal.Zero, core.NewServErr("价格查询失败", err)
} }
discountRate := discount.Rate() discountRate := discount.Rate()
if user != nil && user.DiscountID != nil { // 用户特殊优惠 if user != nil && user.DiscountID != nil { // 用户特殊优惠
uDiscount, err := q.ProductDiscount.Where(q.ProductDiscount.ID.Eq(*user.DiscountID)).Take() uDiscount, err := q.ProductDiscount.Where(q.ProductDiscount.ID.Eq(*user.DiscountID)).Take()
if err != nil { if err != nil {
return nil, nil, nil, decimal.Zero, decimal.Zero, core.NewServErr("客户特殊价查询失败", err) return nil, nil, nil, decimal.Zero, decimal.Zero, decimal.Zero, core.NewServErr("客户特殊价查询失败", err)
} }
uDiscountRate := uDiscount.Rate() uDiscountRate := uDiscount.Rate()
if uDiscountRate.Cmp(discountRate) > 0 { if uDiscountRate.Cmp(discountRate) < 0 {
discountRate = uDiscountRate discountRate = uDiscountRate
discount = uDiscount discount = uDiscount
} }
@@ -180,30 +180,33 @@ func (s *resourceService) CalcPrice(skuCode string, count int32, user *m.User, c
discounted := amount.Mul(discountRate) discounted := amount.Mul(discountRate)
// 优惠价 // 优惠价
uid := (*int32)(nil) coupon := (*m.CouponUser)(nil)
if user != nil {
uid = &user.ID
}
coupon := (*m.Coupon)(nil)
couponApplied := discounted.Copy() couponApplied := discounted.Copy()
if couponCode != nil { if user != nil && cuid != nil {
var err error var err error
coupon, err = Coupon.GetCouponAvailableByCode(*couponCode, discounted, uid) coupon, err = Coupon.GetUserCoupon(user.ID, *cuid, discounted)
if err != nil { if err != nil {
return nil, nil, nil, decimal.Zero, decimal.Zero, err return nil, nil, nil, decimal.Zero, decimal.Zero, decimal.Zero, err
} }
couponApplied = discounted.Sub(coupon.Amount) couponApplied = discounted.Sub(coupon.Coupon.Amount)
} }
return sku, discount, coupon, discounted, couponApplied, nil // 约束到最低价格
if discounted.Cmp(amountMin) < 0 {
discounted = amountMin.Copy()
}
if couponApplied.Cmp(amountMin) < 0 {
couponApplied = amountMin.Copy()
}
return sku, discount, coupon, amount, discounted, couponApplied, nil
} }
type CreateResourceData struct { type CreateResourceData struct {
Type m.ResourceType `json:"type" validate:"required"` Type m.ResourceType `json:"type" validate:"required"`
Short *CreateShortResourceData `json:"short,omitempty"` Short *CreateShortResourceData `json:"short,omitempty"`
Long *CreateLongResourceData `json:"long,omitempty"` Long *CreateLongResourceData `json:"long,omitempty"`
CouponCode *string `json:"coupon,omitempty"` CouponId *int32 `json:"coupon,omitempty"`
} }
type CreateShortResourceData struct { type CreateShortResourceData struct {
@@ -244,20 +247,20 @@ func (data *CreateResourceData) Code() string {
case data.Type == m.ResourceTypeShort && data.Short != nil: case data.Type == m.ResourceTypeShort && data.Short != nil:
return fmt.Sprintf( return fmt.Sprintf(
"mode=%s,live=%d,expire=%d", "mode=%s&live=%d&expire=%d",
data.Short.Mode.Code(), data.Short.Live, u.Else(data.Short.Expire, 0), data.Short.Mode.Code(), data.Short.Live, u.Else(data.Short.Expire, 0),
) )
case data.Type == m.ResourceTypeLong && data.Long != nil: case data.Type == m.ResourceTypeLong && data.Long != nil:
return fmt.Sprintf( return fmt.Sprintf(
"mode=%s,live=%d,expire=%d", "mode=%s&live=%d&expire=%d",
data.Long.Mode.Code(), data.Long.Live, u.Else(data.Long.Expire, 0), data.Long.Mode.Code(), data.Long.Live, u.Else(data.Long.Expire, 0),
) )
} }
} }
func (data *CreateResourceData) TradeDetail(user *m.User) (*TradeDetail, error) { func (data *CreateResourceData) TradeDetail(user *m.User) (*TradeDetail, error) {
sku, discount, coupon, amount, actual, err := Resource.CalcPrice(data.Code(), data.Count(), user, data.CouponCode) sku, discount, coupon, amount, discounted, actual, err := Resource.CalcPrice(data.Code(), data.Count(), user, data.CouponId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -266,17 +269,16 @@ func (data *CreateResourceData) TradeDetail(user *m.User) (*TradeDetail, error)
if discount != nil { if discount != nil {
discountId = &discount.ID discountId = &discount.ID
} }
var couponId *int32 = nil var couponUserId *int32 = nil
if coupon != nil { if coupon != nil {
couponId = &coupon.ID couponUserId = &coupon.ID
} }
return &TradeDetail{ return &TradeDetail{
data, data,
m.TradeTypePurchase, m.TradeTypePurchase,
sku.Name, sku.Name,
amount, actual, amount, discounted, actual,
discountId, discount, discountId, couponUserId,
couponId, coupon,
}, nil }, nil
} }

View File

@@ -302,17 +302,18 @@ 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, "充值余额", nil); err != nil {
return err
}
// 生成账单 // 生成账单
err = Bill.CreateForBalance(q, user.ID, trade.ID, &detail) bill, err := Bill.CreateForBalance(q, user.ID, trade.ID, &detail)
if err != nil { if err != nil {
return core.NewServErr("生成账单失败", err) return core.NewServErr("生成账单失败", err)
} }
// 更新用户余额
if err := User.UpdateBalance(q, user, detail.Actual, "充值余额", nil, &bill.ID); err != nil {
return err
}
case m.TradeTypePurchase: case m.TradeTypePurchase:
data, ok := detail.Product.(*CreateResourceData) data, ok := detail.Product.(*CreateResourceData)
if !ok { if !ok {
@@ -326,14 +327,14 @@ func (s *tradeService) OnCompleteTrade(user *m.User, interNo string, outerNo str
} }
// 生成账单 // 生成账单
err = Bill.CreateForResource(q, user.ID, resource.ID, &trade.ID, &detail) _, err = Bill.CreateForResource(q, user.ID, resource.ID, &trade.ID, &detail)
if err != nil { if err != nil {
return core.NewServErr("生成账单失败", err) return core.NewServErr("生成账单失败", err)
} }
// 核销优惠券 // 核销优惠券
if detail.CouponId != nil { if detail.CouponUserId != nil {
err = Coupon.UseCoupon(q, *detail.CouponId) err = Coupon.UseCoupon(q, *detail.CouponUserId)
if err != nil { if err != nil {
return core.NewServErr("核销优惠券失败", err) return core.NewServErr("核销优惠券失败", err)
} }
@@ -614,15 +615,14 @@ type ProductData interface {
} }
type TradeDetail struct { type TradeDetail struct {
Product ProductData `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"`
Actual decimal.Decimal `json:"actual"` Discounted decimal.Decimal `json:"discounted"`
DiscountId *int32 `json:"discount_id,omitempty"` Actual decimal.Decimal `json:"actual"`
Discount *m.ProductDiscount `json:"-"` // 不应缓存 DiscountId *int32 `json:"discount_id,omitempty"`
CouponId *int32 `json:"coupon_id,omitempty"` CouponUserId *int32 `json:"coupon_id,omitempty"`
Coupon *m.Coupon `json:"-"` // 不应缓存
} }
type TradeErr string type TradeErr string

View File

@@ -39,11 +39,11 @@ func (s *userService) UpdateBalanceByAdmin(user *m.User, newBalance decimal.Deci
} }
return q.Q.Transaction(func(q *q.Query) error { return q.Q.Transaction(func(q *q.Query) error {
return s.UpdateBalance(q, user, amount, "管理员修改余额", adminId) return s.UpdateBalance(q, user, amount, "管理员修改余额", adminId, nil)
}) })
} }
func (s *userService) UpdateBalance(q *q.Query, user *m.User, amount decimal.Decimal, remark string, adminId *int32) error { func (s *userService) UpdateBalance(q *q.Query, user *m.User, amount decimal.Decimal, remark string, adminId *int32, billId *int32) error {
balance := user.Balance.Add(amount) balance := user.Balance.Add(amount)
if balance.IsNegative() { if balance.IsNegative() {
return core.NewServErr("用户余额不足") return core.NewServErr("用户余额不足")
@@ -66,6 +66,7 @@ func (s *userService) UpdateBalance(q *q.Query, user *m.User, amount decimal.Dec
err = q.BalanceActivity.Create(&m.BalanceActivity{ err = q.BalanceActivity.Create(&m.BalanceActivity{
UserID: user.ID, UserID: user.ID,
AdminID: adminId, AdminID: adminId,
BillID: billId,
Amount: amount.StringFixed(2), Amount: amount.StringFixed(2),
BalancePrev: user.Balance.StringFixed(2), BalancePrev: user.Balance.StringFixed(2),
BalanceCurr: balance.StringFixed(2), BalanceCurr: balance.StringFixed(2),
@@ -92,8 +93,7 @@ func (data *UpdateBalanceData) TradeDetail(user *m.User) (*TradeDetail, error) {
data, data,
m.TradeTypeRecharge, m.TradeTypeRecharge,
fmt.Sprintf("账户充值 - %s元", amount.StringFixed(2)), fmt.Sprintf("账户充值 - %s元", amount.StringFixed(2)),
amount, amount, amount, amount, amount,
nil, nil,
nil, nil, nil, nil,
}, nil }, nil
} }
@@ -118,7 +118,6 @@ func (s *userService) CreateByAdmin(data CreateUserByAdminData) error {
Email: data.Email, Email: data.Email,
Password: hashedPwd, Password: hashedPwd,
Source: &source, Source: &source,
Name: data.Name,
Avatar: data.Avatar, Avatar: data.Avatar,
Status: u.Else(data.Status, m.UserStatusEnabled), Status: u.Else(data.Status, m.UserStatusEnabled),
ContactQQ: data.ContactQQ, ContactQQ: data.ContactQQ,
@@ -141,7 +140,6 @@ type CreateUserByAdminData struct {
Username *string `json:"username"` Username *string `json:"username"`
Email *string `json:"email"` Email *string `json:"email"`
Password *string `json:"password"` Password *string `json:"password"`
Name *string `json:"name"`
Avatar *string `json:"avatar"` Avatar *string `json:"avatar"`
Status *m.UserStatus `json:"status"` Status *m.UserStatus `json:"status"`
ContactQQ *string `json:"contact_qq"` ContactQQ *string `json:"contact_qq"`

View File

@@ -55,7 +55,7 @@ func (s *verifierService) SendSms(ctx context.Context, phone string, purpose Ver
code := rand.Intn(900000) + 100000 // 6-digit code between 100000-999999 code := rand.Intn(900000) + 100000 // 6-digit code between 100000-999999
// 发送短信验证码 // 发送短信验证码
if env.DebugExternalChange { if env.RunMode == env.RunModeProd {
params, err := json.Marshal(map[string]string{ params, err := json.Marshal(map[string]string{
"code": strconv.Itoa(code), "code": strconv.Itoa(code),
}) })
@@ -89,8 +89,8 @@ func (s *verifierService) SendSms(ctx context.Context, phone string, purpose Ver
return nil return nil
} }
func (s *verifierService) VerifySms(ctx context.Context, phone, code string) error { func (s *verifierService) VerifySms(ctx context.Context, phone, code string, purpose VerifierSmsPurpose) error {
key := smsKey(phone, VerifierSmsPurposeLogin) key := smsKey(phone, purpose)
keyLock := key + ":lock" keyLock := key + ":lock"
err := g.Redis.Watch(ctx, func(tx *redis.Tx) error { err := g.Redis.Watch(ctx, func(tx *redis.Tx) error {
@@ -146,7 +146,8 @@ func smsKey(phone string, purpose VerifierSmsPurpose) string {
type VerifierSmsPurpose int type VerifierSmsPurpose int
const ( const (
VerifierSmsPurposeLogin VerifierSmsPurpose = iota // 登录 VerifierSmsPurposeLogin VerifierSmsPurpose = iota // 登录
VerifierSmsPurposePassword // 修改密码
) )
// region 服务异常 // region 服务异常