优化表结构,重构模型,重新实现基于白银网关的提取节点流程
This commit is contained in:
73
README.md
73
README.md
@@ -1,12 +1,48 @@
|
|||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
日志记录,使用任务来实现
|
限制提取单次最大量
|
||||||
|
|
||||||
支付后事件,需要检测是否已完成操作
|
支付后异步任务,到时间后需要尝试完成订单,如果无法完成再关闭
|
||||||
|
|
||||||
|
重新实现接口 proxy 注册与注销接口:
|
||||||
|
- 注册时向 redis ports 可用池中加入端口
|
||||||
|
- 注销时需要同时移除可用池与租约池中的端口(需要考虑具体实现,考虑正在使用的节点归还问题)
|
||||||
|
|
||||||
|
otel 检查接口性能
|
||||||
|
|
||||||
|
trade/create 性能问题,缩短事务时间,考虑其他方式实现可靠分布式事务
|
||||||
|
|
||||||
|
需要确认以下 ID.GenSerial 的分布式并发安全性
|
||||||
|
|
||||||
### 长期
|
### 长期
|
||||||
|
|
||||||
模型字段修改,特定枚举字段使用自定义类型代替通用 int32
|
分离 task 的客户端,支持多进程(prefork 必要!)
|
||||||
|
|
||||||
|
调整目录结构:
|
||||||
|
|
||||||
|
```
|
||||||
|
- /core 核心概念
|
||||||
|
- /util 工具函数
|
||||||
|
|
||||||
|
- /models 模型
|
||||||
|
- /queries 数据库层
|
||||||
|
- /clients 三方依赖的客户端实例
|
||||||
|
|
||||||
|
- /services 服务层
|
||||||
|
- /auth 认证相关,特化服务
|
||||||
|
|
||||||
|
- /app 应用相关,初始化日志,环境变量等
|
||||||
|
- /http 协议层,http 服务
|
||||||
|
- /cmd 主函数
|
||||||
|
|
||||||
|
逐层向上依赖
|
||||||
|
cmd 调用 app, http 的初始化函数
|
||||||
|
http 调用 clients 的初始化函数
|
||||||
|
```
|
||||||
|
|
||||||
|
考虑一个方案限制接口请求速率,无侵入更好
|
||||||
|
|
||||||
|
冷数据迁移方案
|
||||||
|
|
||||||
proxy 网关更新接口可以传输更结构化的数据,直接区分不同类型以加快更新速度
|
proxy 网关更新接口可以传输更结构化的数据,直接区分不同类型以加快更新速度
|
||||||
|
|
||||||
@@ -14,19 +50,36 @@ proxy 网关更新接口可以传输更结构化的数据,直接区分不同
|
|||||||
|
|
||||||
### 订单关闭的几种方式
|
### 订单关闭的几种方式
|
||||||
|
|
||||||
1. 创建订单后推送异步任务,到时间后尝试关闭订单
|
1. 创建订单后推送异步任务,到时间后尝试完成订单或关闭订单
|
||||||
2. sse 接口推送订单状态,轮询尝试完成订单
|
2. sse 接口推送订单状态,轮询尝试完成订单
|
||||||
3. 异步回调事件,收到支付成功事件后自动完成订单
|
3. 异步回调事件,收到支付成功事件后自动完成订单
|
||||||
|
4. 用户退出支付界面,客户端主动发起关闭订单
|
||||||
|
|
||||||
### 产品字典表
|
### 产品字典表
|
||||||
|
|
||||||
| 代码 | 产品 |
|
| 代码 | 产品 |
|
||||||
|-------|------|
|
| ----- | ------------ |
|
||||||
| short | 短效代理 |
|
| short | 短效动态代理 |
|
||||||
| long | 长效代理 |
|
| long | 长效动态代理 |
|
||||||
|
|
||||||
## 问题备忘录
|
### 节点分配与存储逻辑
|
||||||
|
|
||||||
### 商福通支付接口的同步跳转参数
|
添加:
|
||||||
|
- 检查用户 ip 是否在白名单内
|
||||||
|
- 取用端口,不够则返回失败
|
||||||
|
- 将分配结果转写成配置发送到网关
|
||||||
|
- 保存通道信息和分配记录,其中通道信息以网关为主体,分配记录以用户为主体
|
||||||
|
- 添加异步任务,当时间结束后释放取用的端口并清空网关配置
|
||||||
|
|
||||||
部分通道支持这个参数,银盛和汇付不支持这个参数
|
删除:
|
||||||
|
- 如果传入用户信息,检查要删除的连接是否属于该用户
|
||||||
|
- 释放可用端口
|
||||||
|
- redis 脚本中检查,如果端口所属节点已下线则直接忽略
|
||||||
|
- 提交清空配置到网关
|
||||||
|
|
||||||
|
缩扩容:
|
||||||
|
- 通过调度任务实现缩扩容
|
||||||
|
- 每 n 秒检查一次全部配置,按代理分组
|
||||||
|
- 获取所有代理后备配置
|
||||||
|
- 后备配置/当前配置
|
||||||
|
- 当比例 < 1.5 或 > 3 时,重新更新为 2 倍
|
||||||
|
|||||||
172
cmd/gen/main.go
172
cmd/gen/main.go
@@ -1,11 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
m "platform/web/models"
|
||||||
|
|
||||||
"gorm.io/driver/postgres"
|
"gorm.io/driver/postgres"
|
||||||
"gorm.io/gen"
|
"gorm.io/gen"
|
||||||
"gorm.io/gen/field"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/schema"
|
"gorm.io/gorm/schema"
|
||||||
)
|
)
|
||||||
@@ -26,149 +25,42 @@ func main() {
|
|||||||
|
|
||||||
g = gen.NewGenerator(gen.Config{
|
g = gen.NewGenerator(gen.Config{
|
||||||
OutPath: "web/queries",
|
OutPath: "web/queries",
|
||||||
ModelPkgPath: "models",
|
|
||||||
FieldNullable: true,
|
FieldNullable: true,
|
||||||
FieldSignable: true,
|
FieldSignable: true,
|
||||||
FieldWithTypeTag: true,
|
FieldWithTypeTag: true,
|
||||||
Mode: gen.WithDefaultQuery | gen.WithoutContext,
|
Mode: gen.WithDefaultQuery | gen.WithoutContext,
|
||||||
})
|
})
|
||||||
g.UseDB(db)
|
g.UseDB(db)
|
||||||
|
g.ApplyBasic(
|
||||||
// 公共参数
|
m.Admin{},
|
||||||
common := []gen.ModelOpt{
|
m.AdminRole{},
|
||||||
gen.FieldModify(func(field gen.Field) gen.Field {
|
m.Announcement{},
|
||||||
switch {
|
m.Bill{},
|
||||||
case field.Type == "*time.Time":
|
m.Channel{},
|
||||||
field.Type = "*orm.LocalDateTime"
|
m.Client{},
|
||||||
case field.Type == "time.Time":
|
m.Coupon{},
|
||||||
field.Type = "orm.LocalDateTime"
|
m.Edge{},
|
||||||
case strings.Contains(field.Tags(), "numeric"):
|
m.LinkAdminRole{},
|
||||||
field.Type = "decimal.Decimal"
|
m.LinkAdminRolePermission{},
|
||||||
}
|
m.LinkClientPermission{},
|
||||||
return field
|
m.LinkUserRole{},
|
||||||
}),
|
m.LinkUserRolePermission{},
|
||||||
gen.FieldRename("contact_qq", "ContactQQ"),
|
m.LogsLogin{},
|
||||||
gen.FieldRename("ua", "UA"),
|
m.LogsRequest{},
|
||||||
}
|
m.LogsUserBandwidth{},
|
||||||
|
m.LogsUserUsage{},
|
||||||
// 生成模型
|
m.Permission{},
|
||||||
customs := make(map[string]any)
|
m.Product{},
|
||||||
|
m.Proxy{},
|
||||||
// resource
|
m.Refund{},
|
||||||
resourceShort := g.GenerateModel("resource_short", common...)
|
m.Resource{},
|
||||||
customs["resource_short"] = resourceShort
|
m.ResourceLong{},
|
||||||
|
m.ResourceShort{},
|
||||||
resourceLong := g.GenerateModel("resource_long", common...)
|
m.Session{},
|
||||||
customs["resource_long"] = resourceLong
|
m.Trade{},
|
||||||
|
m.User{},
|
||||||
resource := g.GenerateModel("resource", append(common,
|
m.UserRole{},
|
||||||
gen.FieldRelate(field.HasOne, "Short", resourceShort, &field.RelateConfig{
|
m.Whitelist{},
|
||||||
RelatePointer: true,
|
)
|
||||||
GORMTag: field.GormTag{
|
|
||||||
"foreignKey": []string{"ResourceID"},
|
|
||||||
"references": []string{"ID"},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
gen.FieldRelate(field.HasOne, "Long", resourceLong, &field.RelateConfig{
|
|
||||||
RelatePointer: true,
|
|
||||||
GORMTag: field.GormTag{
|
|
||||||
"foreignKey": []string{"ResourceID"},
|
|
||||||
"references": []string{"ID"},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)...)
|
|
||||||
customs["resource"] = resource
|
|
||||||
|
|
||||||
// trade
|
|
||||||
trade := g.GenerateModel("trade", common...)
|
|
||||||
customs["trade"] = trade
|
|
||||||
|
|
||||||
refund := g.GenerateModel("refund", common...)
|
|
||||||
customs["refund"] = refund
|
|
||||||
|
|
||||||
bill := g.GenerateModel("bill", append(common,
|
|
||||||
gen.FieldRelate(field.BelongsTo, "Trade", trade, &field.RelateConfig{
|
|
||||||
RelatePointer: true,
|
|
||||||
GORMTag: field.GormTag{
|
|
||||||
"foreignKey": []string{"TradeID"},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
gen.FieldRelate(field.BelongsTo, "Refund", refund, &field.RelateConfig{
|
|
||||||
RelatePointer: true,
|
|
||||||
GORMTag: field.GormTag{
|
|
||||||
"foreignKey": []string{"RefundID"},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
gen.FieldRelate(field.BelongsTo, "Resource", resource, &field.RelateConfig{
|
|
||||||
RelatePointer: true,
|
|
||||||
GORMTag: field.GormTag{
|
|
||||||
"foreignKey": []string{"ResourceID"},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)...)
|
|
||||||
customs["bill"] = bill
|
|
||||||
|
|
||||||
// proxy
|
|
||||||
edge := g.GenerateModel("edge", common...)
|
|
||||||
customs["edge"] = edge
|
|
||||||
|
|
||||||
proxy := g.GenerateModel("proxy", append(common,
|
|
||||||
gen.FieldRelate(field.HasMany, "Edges", edge, &field.RelateConfig{
|
|
||||||
GORMTag: field.GormTag{
|
|
||||||
"foreignKey": []string{"ProxyID"},
|
|
||||||
"references": []string{"ID"},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)...)
|
|
||||||
customs["proxy"] = proxy
|
|
||||||
|
|
||||||
// session
|
|
||||||
user := g.GenerateModel("user", common...)
|
|
||||||
customs["user"] = user
|
|
||||||
|
|
||||||
admin := g.GenerateModel("admin", common...)
|
|
||||||
customs["admin"] = admin
|
|
||||||
|
|
||||||
client := g.GenerateModel("client", common...)
|
|
||||||
customs["client"] = client
|
|
||||||
|
|
||||||
session := g.GenerateModel("session", append(common,
|
|
||||||
gen.FieldRelate(field.BelongsTo, "User", user, &field.RelateConfig{
|
|
||||||
RelatePointer: true,
|
|
||||||
GORMTag: field.GormTag{
|
|
||||||
"foreignKey": []string{"UserID"},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
gen.FieldRelate(field.BelongsTo, "Admin", admin, &field.RelateConfig{
|
|
||||||
RelatePointer: true,
|
|
||||||
GORMTag: field.GormTag{
|
|
||||||
"foreignKey": []string{"AdminID"},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
gen.FieldRelate(field.BelongsTo, "Client", client, &field.RelateConfig{
|
|
||||||
RelatePointer: true,
|
|
||||||
GORMTag: field.GormTag{
|
|
||||||
"foreignKey": []string{"ClientID"},
|
|
||||||
"belongsTo": []string{"ID"},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)...)
|
|
||||||
customs["session"] = session
|
|
||||||
|
|
||||||
// 生成表结构
|
|
||||||
tables, _ := db.Migrator().GetTables()
|
|
||||||
models := make([]any, len(tables))
|
|
||||||
for i, name := range tables {
|
|
||||||
if customs[name] != nil {
|
|
||||||
models[i] = customs[name]
|
|
||||||
} else {
|
|
||||||
models[i] = g.GenerateModel(name, common...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g.ApplyBasic(models...)
|
|
||||||
|
|
||||||
// 生成查询
|
|
||||||
|
|
||||||
g.Execute()
|
g.Execute()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
name: server-dev
|
name: lanhu
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
@@ -11,6 +11,7 @@ services:
|
|||||||
- "${DB_PORT}:5432"
|
- "${DB_PORT}:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
- ./scripts/sql/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
|
|||||||
86
pkg/u/u.go
86
pkg/u/u.go
@@ -5,11 +5,36 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// P 是一个工具函数,用于在表达式内原地创建一个指针
|
// ====================
|
||||||
|
// 逻辑
|
||||||
|
// ====================
|
||||||
|
|
||||||
|
func Else[T any](v *T, or T) T {
|
||||||
|
if v == nil {
|
||||||
|
return or
|
||||||
|
} else {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ElseTo[A any, B any](a *A, f func(A) B) *B {
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return P(f(*a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
// 指针
|
||||||
|
// ====================
|
||||||
|
|
||||||
|
// P 原地创建值的指针
|
||||||
func P[T any](v T) *T {
|
func P[T any](v T) *T {
|
||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Z 转换值为不可空,如果值为 nil,则返回其零值
|
||||||
func Z[T any](v *T) T {
|
func Z[T any](v *T) T {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
var zero T
|
var zero T
|
||||||
@@ -18,6 +43,7 @@ func Z[T any](v *T) T {
|
|||||||
return *v
|
return *v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X 转换值为可空,如果值为零值,则返回 nil
|
||||||
func X[T comparable](v T) *T {
|
func X[T comparable](v T) *T {
|
||||||
var zero T
|
var zero T
|
||||||
if v == zero {
|
if v == zero {
|
||||||
@@ -26,28 +52,50 @@ func X[T comparable](v T) *T {
|
|||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
func Today() time.Time {
|
// ====================
|
||||||
var now = time.Now()
|
// 数组
|
||||||
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
// ====================
|
||||||
}
|
|
||||||
|
|
||||||
func Date(date time.Time) time.Time {
|
func Map[T any, R any](src []T, convert func(T) R) []R {
|
||||||
return time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
|
dst := make([]R, len(src))
|
||||||
}
|
for i, item := range src {
|
||||||
|
dst[i] = convert(item)
|
||||||
func SameDate(date time.Time) bool {
|
|
||||||
var now = time.Now()
|
|
||||||
return date.Year() == now.Year() && date.Month() == now.Month() && date.Day() == now.Day()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Or[T any](v *T, or T) T {
|
|
||||||
if v == nil {
|
|
||||||
return or
|
|
||||||
} else {
|
|
||||||
return *v
|
|
||||||
}
|
}
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
// 时间
|
||||||
|
// ====================
|
||||||
|
|
||||||
|
func DateHead(date time.Time) time.Time {
|
||||||
|
var y, m, d = date.Date()
|
||||||
|
return time.Date(y, m, d, 0, 0, 0, 0, date.Location())
|
||||||
|
}
|
||||||
|
|
||||||
|
func DateFoot(date time.Time) time.Time {
|
||||||
|
var y, m, d = date.Date()
|
||||||
|
return time.Date(y, m, d, 23, 59, 59, 999999999, date.Location())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Today() time.Time {
|
||||||
|
return DateHead(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsSameDate(date1, date2 time.Time) bool {
|
||||||
|
var y1, m1, d1 = date1.Date()
|
||||||
|
var y2, m2, d2 = date2.Date()
|
||||||
|
return y1 == y2 && m1 == m2 && d1 == d2
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsToday(date time.Time) bool {
|
||||||
|
return IsSameDate(date, time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
// 错误
|
||||||
|
// ====================
|
||||||
|
|
||||||
func CombineErrors(errs []error) error {
|
func CombineErrors(errs []error) error {
|
||||||
var combinedErr error = nil
|
var combinedErr error = nil
|
||||||
for _, err := range errs {
|
for _, err := range errs {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"platform/web/core"
|
"platform/web/core"
|
||||||
client2 "platform/web/domains/client"
|
|
||||||
m "platform/web/models"
|
m "platform/web/models"
|
||||||
q "platform/web/queries"
|
q "platform/web/queries"
|
||||||
s "platform/web/services"
|
s "platform/web/services"
|
||||||
@@ -86,8 +85,8 @@ func authBearer(_ context.Context, token string) (*AuthCtx, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scopes := []string{}
|
scopes := []string{}
|
||||||
if session.Scopes_ != nil {
|
if session.Scopes != nil {
|
||||||
scopes = strings.Split(*session.Scopes_, " ")
|
scopes = strings.Split(*session.Scopes, " ")
|
||||||
}
|
}
|
||||||
return &AuthCtx{
|
return &AuthCtx{
|
||||||
User: session.User,
|
User: session.User,
|
||||||
@@ -138,8 +137,7 @@ func authClient(clientId, clientSecret string) (*m.Client, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查客户端密钥
|
// 检查客户端密钥
|
||||||
spec := client2.Spec(client.Spec)
|
if client.Spec == m.ClientSpecWeb || client.Spec == m.ClientSpecAPI {
|
||||||
if spec == client2.SpecWeb || spec == client2.SpecApi {
|
|
||||||
if bcrypt.CompareHashAndPassword([]byte(client.ClientSecret), []byte(clientSecret)) != nil {
|
if bcrypt.CompareHashAndPassword([]byte(client.ClientSecret), []byte(clientSecret)) != nil {
|
||||||
return nil, errors.New("客户端密钥错误")
|
return nil, errors.New("客户端密钥错误")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"platform/pkg/env"
|
"platform/pkg/env"
|
||||||
"platform/pkg/u"
|
"platform/pkg/u"
|
||||||
"platform/web/core"
|
"platform/web/core"
|
||||||
user2 "platform/web/domains/user"
|
|
||||||
g "platform/web/globals"
|
g "platform/web/globals"
|
||||||
"platform/web/globals/orm"
|
"platform/web/globals/orm"
|
||||||
m "platform/web/models"
|
m "platform/web/models"
|
||||||
@@ -162,7 +161,7 @@ func Token(c *fiber.Ctx) error {
|
|||||||
AccessToken: session.AccessToken,
|
AccessToken: session.AccessToken,
|
||||||
RefreshToken: u.Z(session.RefreshToken),
|
RefreshToken: u.Z(session.RefreshToken),
|
||||||
ExpiresIn: int(time.Time(session.AccessTokenExpires).Sub(now).Seconds()),
|
ExpiresIn: int(time.Time(session.AccessTokenExpires).Sub(now).Seconds()),
|
||||||
Scope: u.Z(session.Scopes_),
|
Scope: u.Z(session.Scopes),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +201,7 @@ func authAuthorizationCode(ctx *fiber.Ctx, auth *AuthCtx, req *TokenReq, now tim
|
|||||||
|
|
||||||
user, err := q.User.Where(
|
user, err := q.User.Where(
|
||||||
q.User.ID.Eq(codeCtx.UserID),
|
q.User.ID.Eq(codeCtx.UserID),
|
||||||
q.User.Status.Eq(int32(user2.StatusEnabled)),
|
q.User.Status.Eq(int(m.UserStatusEnabled)),
|
||||||
).First()
|
).First()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -211,18 +210,20 @@ func authAuthorizationCode(ctx *fiber.Ctx, auth *AuthCtx, req *TokenReq, now tim
|
|||||||
// todo 检查 scope
|
// todo 检查 scope
|
||||||
|
|
||||||
// 生成会话
|
// 生成会话
|
||||||
|
ip, _ := orm.ParseInet(ctx.Get(core.HeaderUserIP))
|
||||||
|
ua := ctx.Get(core.HeaderUserUA)
|
||||||
session := &m.Session{
|
session := &m.Session{
|
||||||
IP: u.X(ctx.IP()),
|
IP: ip,
|
||||||
UA: u.X(ctx.Get(fiber.HeaderUserAgent)),
|
UA: u.X(ua),
|
||||||
UserID: &user.ID,
|
UserID: &user.ID,
|
||||||
ClientID: &auth.Client.ID,
|
ClientID: &auth.Client.ID,
|
||||||
Scopes_: u.P(strings.Join(codeCtx.Scopes, " ")),
|
Scopes: u.P(strings.Join(codeCtx.Scopes, " ")),
|
||||||
AccessToken: uuid.NewString(),
|
AccessToken: uuid.NewString(),
|
||||||
AccessTokenExpires: orm.LocalDateTime(now.Add(time.Duration(env.SessionAccessExpire) * time.Second)),
|
AccessTokenExpires: now.Add(time.Duration(env.SessionAccessExpire) * time.Second),
|
||||||
}
|
}
|
||||||
if codeCtx.Remember {
|
if codeCtx.Remember {
|
||||||
session.RefreshToken = u.P(uuid.NewString())
|
session.RefreshToken = u.P(uuid.NewString())
|
||||||
session.RefreshTokenExpires = u.P(orm.LocalDateTime(now.Add(time.Duration(env.SessionRefreshExpire) * time.Second)))
|
session.RefreshTokenExpires = u.P(now.Add(time.Duration(env.SessionRefreshExpire) * time.Second))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = SaveSession(session)
|
err = SaveSession(session)
|
||||||
@@ -237,12 +238,14 @@ func authClientCredential(ctx *fiber.Ctx, auth *AuthCtx, _ *TokenReq, now time.T
|
|||||||
// todo 检查 scope
|
// todo 检查 scope
|
||||||
|
|
||||||
// 生成会话
|
// 生成会话
|
||||||
|
ip, _ := orm.ParseInet(ctx.Get(core.HeaderUserIP))
|
||||||
|
ua := ctx.Get(core.HeaderUserUA)
|
||||||
session := &m.Session{
|
session := &m.Session{
|
||||||
IP: u.X(ctx.IP()),
|
IP: ip,
|
||||||
UA: u.X(ctx.Get(fiber.HeaderUserAgent)),
|
UA: u.X(ua),
|
||||||
ClientID: &auth.Client.ID,
|
ClientID: &auth.Client.ID,
|
||||||
AccessToken: uuid.NewString(),
|
AccessToken: uuid.NewString(),
|
||||||
AccessTokenExpires: orm.LocalDateTime(now.Add(time.Duration(env.SessionAccessExpire) * time.Second)),
|
AccessTokenExpires: now.Add(time.Duration(env.SessionAccessExpire) * time.Second),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存会话
|
// 保存会话
|
||||||
@@ -255,6 +258,9 @@ func authClientCredential(ctx *fiber.Ctx, auth *AuthCtx, _ *TokenReq, now time.T
|
|||||||
}
|
}
|
||||||
|
|
||||||
func authPassword(ctx *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (*m.Session, error) {
|
func authPassword(ctx *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (*m.Session, error) {
|
||||||
|
ip, _ := orm.ParseInet(ctx.Get(core.HeaderUserIP))
|
||||||
|
ua := ctx.Get(core.HeaderUserUA)
|
||||||
|
|
||||||
var user *m.User
|
var user *m.User
|
||||||
err := q.Q.Transaction(func(tx *q.Query) (err error) {
|
err := q.Q.Transaction(func(tx *q.Query) (err error) {
|
||||||
switch req.LoginType {
|
switch req.LoginType {
|
||||||
@@ -267,7 +273,7 @@ func authPassword(ctx *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (
|
|||||||
user = &m.User{
|
user = &m.User{
|
||||||
Phone: req.Username,
|
Phone: req.Username,
|
||||||
Username: u.P(req.Username),
|
Username: u.P(req.Username),
|
||||||
Status: int32(user2.StatusEnabled),
|
Status: m.UserStatusEnabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case GrantPasswordEmail:
|
case GrantPasswordEmail:
|
||||||
@@ -285,15 +291,15 @@ func authPassword(ctx *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 账户状态
|
// 账户状态
|
||||||
if user2.Status(user.Status) == user2.StatusDisabled {
|
if user.Status == m.UserStatusDisabled {
|
||||||
slog.Debug("账户状态异常", "username", req.Username, "status", user.Status)
|
slog.Debug("账户状态异常", "username", req.Username, "status", user.Status)
|
||||||
return core.NewBizErr("账号无法登录")
|
return core.NewBizErr("账号无法登录")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新用户的登录时间
|
// 更新用户的登录时间
|
||||||
user.LastLogin = u.P(orm.LocalDateTime(time.Now()))
|
user.LastLogin = u.P(time.Now())
|
||||||
user.LastLoginHost = u.X(ctx.IP())
|
user.LastLoginIP = ip
|
||||||
user.LastLoginAgent = u.X(ctx.Get(fiber.HeaderUserAgent))
|
user.LastLoginUA = u.X(ua)
|
||||||
if err := tx.User.Save(user); err != nil {
|
if err := tx.User.Save(user); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -306,17 +312,17 @@ func authPassword(ctx *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (
|
|||||||
|
|
||||||
// 生成会话
|
// 生成会话
|
||||||
session := &m.Session{
|
session := &m.Session{
|
||||||
IP: u.X(ctx.IP()),
|
IP: ip,
|
||||||
UA: u.X(ctx.Get(fiber.HeaderUserAgent)),
|
UA: u.X(ua),
|
||||||
UserID: &user.ID,
|
UserID: &user.ID,
|
||||||
ClientID: &auth.Client.ID,
|
ClientID: &auth.Client.ID,
|
||||||
Scopes_: u.X(req.Scope),
|
Scopes: u.X(req.Scope),
|
||||||
AccessToken: uuid.NewString(),
|
AccessToken: uuid.NewString(),
|
||||||
AccessTokenExpires: orm.LocalDateTime(now.Add(time.Duration(env.SessionAccessExpire) * time.Second)),
|
AccessTokenExpires: now.Add(time.Duration(env.SessionAccessExpire) * time.Second),
|
||||||
}
|
}
|
||||||
if req.Remember {
|
if req.Remember {
|
||||||
session.RefreshToken = u.P(uuid.NewString())
|
session.RefreshToken = u.P(uuid.NewString())
|
||||||
session.RefreshTokenExpires = u.P(orm.LocalDateTime(now.Add(time.Duration(env.SessionRefreshExpire) * time.Second)))
|
session.RefreshTokenExpires = u.P(now.Add(time.Duration(env.SessionRefreshExpire) * time.Second))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = SaveSession(session)
|
err = SaveSession(session)
|
||||||
@@ -340,10 +346,10 @@ func authRefreshToken(_ *fiber.Ctx, _ *AuthCtx, req *TokenReq, now time.Time) (*
|
|||||||
|
|
||||||
// 生成令牌
|
// 生成令牌
|
||||||
session.AccessToken = uuid.NewString()
|
session.AccessToken = uuid.NewString()
|
||||||
session.AccessTokenExpires = orm.LocalDateTime(now.Add(time.Duration(env.SessionAccessExpire) * time.Second))
|
session.AccessTokenExpires = now.Add(time.Duration(env.SessionAccessExpire) * time.Second)
|
||||||
if session.RefreshToken != nil {
|
if session.RefreshToken != nil {
|
||||||
session.RefreshToken = u.P(uuid.NewString())
|
session.RefreshToken = u.P(uuid.NewString())
|
||||||
session.RefreshTokenExpires = u.P(orm.LocalDateTime(now.Add(time.Duration(env.SessionRefreshExpire) * time.Second)))
|
session.RefreshTokenExpires = u.P(now.Add(time.Duration(env.SessionRefreshExpire) * time.Second))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存令牌
|
// 保存令牌
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"platform/web/domains/client"
|
|
||||||
m "platform/web/models"
|
m "platform/web/models"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
@@ -40,8 +39,7 @@ func (a *AuthCtx) PermitSecretClient(scopes ...string) (*AuthCtx, error) {
|
|||||||
if a.Client == nil {
|
if a.Client == nil {
|
||||||
return a, ErrAuthenticateForbidden
|
return a, ErrAuthenticateForbidden
|
||||||
}
|
}
|
||||||
spec := client.Spec(a.Client.Spec)
|
if a.Client.Spec != m.ClientSpecAPI && a.Client.Spec != m.ClientSpecWeb {
|
||||||
if spec != client.SpecApi && spec != client.SpecWeb {
|
|
||||||
return a, ErrAuthenticateForbidden
|
return a, ErrAuthenticateForbidden
|
||||||
}
|
}
|
||||||
if !a.checkScopes(scopes...) {
|
if !a.checkScopes(scopes...) {
|
||||||
@@ -50,16 +48,14 @@ func (a *AuthCtx) PermitSecretClient(scopes ...string) (*AuthCtx, error) {
|
|||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AuthCtx) PermitInternalClient(scopes ...string) (*AuthCtx, error) {
|
func (a *AuthCtx) PermitOfficialClient(scopes ...string) (*AuthCtx, error) {
|
||||||
if a.Client == nil {
|
if a.Client == nil {
|
||||||
return a, ErrAuthenticateForbidden
|
return a, ErrAuthenticateForbidden
|
||||||
}
|
}
|
||||||
spec := client.Spec(a.Client.Spec)
|
if a.Client.Spec != m.ClientSpecAPI && a.Client.Spec != m.ClientSpecWeb {
|
||||||
if spec != client.SpecApi && spec != client.SpecWeb {
|
|
||||||
return a, ErrAuthenticateForbidden
|
return a, ErrAuthenticateForbidden
|
||||||
}
|
}
|
||||||
cType := client.Type(a.Client.Type)
|
if a.Client.Type != m.ClientTypeOfficial {
|
||||||
if cType != client.TypeInternal {
|
|
||||||
return a, ErrAuthenticateForbidden
|
return a, ErrAuthenticateForbidden
|
||||||
}
|
}
|
||||||
if !a.checkScopes(scopes...) {
|
if !a.checkScopes(scopes...) {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
g "platform/web/globals"
|
g "platform/web/globals"
|
||||||
"platform/web/globals/orm"
|
|
||||||
m "platform/web/models"
|
m "platform/web/models"
|
||||||
q "platform/web/queries"
|
q "platform/web/queries"
|
||||||
"time"
|
"time"
|
||||||
@@ -17,7 +16,7 @@ func FindSession(accessToken string, now time.Time) (*m.Session, error) {
|
|||||||
Preload(field.Associations).
|
Preload(field.Associations).
|
||||||
Where(
|
Where(
|
||||||
q.Session.AccessToken.Eq(accessToken),
|
q.Session.AccessToken.Eq(accessToken),
|
||||||
q.Session.AccessTokenExpires.Gt(orm.LocalDateTime(now)),
|
q.Session.AccessTokenExpires.Gt(now),
|
||||||
).First()
|
).First()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +25,7 @@ func FindSessionByRefresh(refreshToken string, now time.Time) (*m.Session, error
|
|||||||
Preload(field.Associations).
|
Preload(field.Associations).
|
||||||
Where(
|
Where(
|
||||||
q.Session.RefreshToken.Eq(refreshToken),
|
q.Session.RefreshToken.Eq(refreshToken),
|
||||||
q.Session.RefreshTokenExpires.Gt(orm.LocalDateTime(now)),
|
q.Session.RefreshTokenExpires.Gt(now),
|
||||||
).First()
|
).First()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,49 +6,6 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// region page
|
|
||||||
|
|
||||||
type PageReq struct {
|
|
||||||
RawPage int `json:"page"`
|
|
||||||
RawSize int `json:"size"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PageReq) GetPage() int {
|
|
||||||
if p.RawPage < 1 {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return p.RawPage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PageReq) GetSize() int {
|
|
||||||
if p.RawSize < 1 {
|
|
||||||
return 10
|
|
||||||
}
|
|
||||||
if p.RawSize > 100 {
|
|
||||||
return 100
|
|
||||||
}
|
|
||||||
return p.RawSize
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PageReq) GetOffset() int {
|
|
||||||
return (p.GetPage() - 1) * p.GetSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PageReq) GetLimit() int {
|
|
||||||
return p.GetSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
type PageResp struct {
|
|
||||||
Total int `json:"total"`
|
|
||||||
Page int `json:"page"`
|
|
||||||
Size int `json:"size"`
|
|
||||||
List any `json:"list"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region error
|
|
||||||
|
|
||||||
type Err struct {
|
type Err struct {
|
||||||
msg string
|
msg string
|
||||||
err error
|
err error
|
||||||
@@ -109,5 +66,3 @@ type ServErr struct{ Err }
|
|||||||
func NewServErr(msg string, err ...error) *ServErr {
|
func NewServErr(msg string, err ...error) *ServErr {
|
||||||
return &ServErr{newErr(msg, err...)}
|
return &ServErr{newErr(msg, err...)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
|
||||||
43
web/core/http.go
Normal file
43
web/core/http.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
const HeaderUserIP = "X-Data-IP"
|
||||||
|
const HeaderUserUA = "X-Data-UA"
|
||||||
|
|
||||||
|
// PageReq 分页请求参数
|
||||||
|
type PageReq struct {
|
||||||
|
RawPage int `json:"page"`
|
||||||
|
RawSize int `json:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PageReq) GetPage() int {
|
||||||
|
if p.RawPage < 1 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return p.RawPage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PageReq) GetSize() int {
|
||||||
|
if p.RawSize < 1 {
|
||||||
|
return 10
|
||||||
|
}
|
||||||
|
if p.RawSize > 100 {
|
||||||
|
return 100
|
||||||
|
}
|
||||||
|
return p.RawSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PageReq) GetOffset() int {
|
||||||
|
return (p.GetPage() - 1) * p.GetSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PageReq) GetLimit() int {
|
||||||
|
return p.GetSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageResp 分页响应参数
|
||||||
|
type PageResp struct {
|
||||||
|
Total int `json:"total"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
Size int `json:"size"`
|
||||||
|
List any `json:"list"`
|
||||||
|
}
|
||||||
29
web/core/model.go
Normal file
29
web/core/model.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/pkg/u"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IModel interface {
|
||||||
|
GetID() int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type Model struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id;primaryKey"`
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
|
||||||
|
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"column:deleted_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Model) GetID() int32 {
|
||||||
|
return m.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetIDs[T IModel](models []T) []int32 {
|
||||||
|
return u.Map(models, func(m T) int32 {
|
||||||
|
return m.GetID()
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package announcement
|
|
||||||
|
|
||||||
type Type int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypeNormal Type = iota + 1 // 普通公告
|
|
||||||
)
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package bill
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/shopspring/decimal"
|
|
||||||
m "platform/web/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewForRecharge(uid int32, billNo string, info string, amount decimal.Decimal, trade *m.Trade) *m.Bill {
|
|
||||||
return &m.Bill{
|
|
||||||
UserID: uid,
|
|
||||||
BillNo: billNo,
|
|
||||||
TradeID: &trade.ID,
|
|
||||||
Type: int32(TypeRecharge),
|
|
||||||
Info: &info,
|
|
||||||
Amount: amount,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewForConsume(uid int32, billNo string, info string, amount decimal.Decimal, resource *m.Resource, trade ...*m.Trade) *m.Bill {
|
|
||||||
var bill = &m.Bill{
|
|
||||||
UserID: uid,
|
|
||||||
BillNo: billNo,
|
|
||||||
ResourceID: &resource.ID,
|
|
||||||
Type: int32(TypeConsume),
|
|
||||||
Info: &info,
|
|
||||||
Amount: amount,
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(trade) > 0 {
|
|
||||||
bill.TradeID = &trade[0].ID
|
|
||||||
}
|
|
||||||
|
|
||||||
return bill
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package bill
|
|
||||||
|
|
||||||
type Type int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypeConsume Type = iota + 1 // 消费
|
|
||||||
TypeRefund // 退款
|
|
||||||
TypeRecharge // 充值
|
|
||||||
)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package channel
|
|
||||||
|
|
||||||
type Protocol int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
ProtocolHttp Protocol = iota + 1
|
|
||||||
ProtocolHttps
|
|
||||||
ProtocolSocks5
|
|
||||||
)
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package client
|
|
||||||
|
|
||||||
type Spec int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
SpecNative Spec = iota + 1 // 原生客户端
|
|
||||||
SpecBrowser // 浏览器客户端
|
|
||||||
SpecWeb // Web 服务
|
|
||||||
SpecApi // Api 服务
|
|
||||||
)
|
|
||||||
|
|
||||||
type Type int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypeNormal Type = iota // 普通客户端
|
|
||||||
TypeInternal // 内部客户端
|
|
||||||
)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package coupon
|
|
||||||
|
|
||||||
type Status int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
StatusUnused = iota // 未使用
|
|
||||||
StatusUsed // 已使用
|
|
||||||
StatusExpired // 已过期
|
|
||||||
)
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package edge
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
type ISP int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
IspUnknown ISP = iota // 未知
|
|
||||||
IspChinaTelecom // 中国电信
|
|
||||||
IspChinaUnicom // 中国联通
|
|
||||||
IspChinaMobile // 中国移动
|
|
||||||
)
|
|
||||||
|
|
||||||
func ISPFromStr(str string) ISP {
|
|
||||||
switch {
|
|
||||||
case strings.Contains(str, "电信"):
|
|
||||||
return IspChinaTelecom
|
|
||||||
case strings.Contains(str, "联通"):
|
|
||||||
return IspChinaUnicom
|
|
||||||
case strings.Contains(str, "移动"):
|
|
||||||
return IspChinaMobile
|
|
||||||
}
|
|
||||||
return IspUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
func (isp ISP) String() string {
|
|
||||||
switch isp {
|
|
||||||
case IspChinaTelecom:
|
|
||||||
return "电信"
|
|
||||||
case IspChinaUnicom:
|
|
||||||
return "联通"
|
|
||||||
case IspChinaMobile:
|
|
||||||
return "移动"
|
|
||||||
default:
|
|
||||||
return "未知"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Type int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypeSelfHosted Type = iota + 1 // 自建节点
|
|
||||||
)
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package proxy
|
|
||||||
|
|
||||||
type Type int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypeThirdParty Type = iota + 1 // 三方代理
|
|
||||||
TypeSelfHosted // 自建代理
|
|
||||||
)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package refund
|
|
||||||
|
|
||||||
type Status int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
StatusHandling Status = iota + 1 // 待处理
|
|
||||||
StatusSuccess // 已退款
|
|
||||||
StatusRefused // 已拒绝
|
|
||||||
)
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package resource
|
|
||||||
|
|
||||||
type Type int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypeShort Type = iota + 1 // 短效动态
|
|
||||||
TypeLong // 长效动态
|
|
||||||
)
|
|
||||||
|
|
||||||
type Mode int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
ModeTime Mode = iota + 1 // 包时
|
|
||||||
ModeCount // 包量
|
|
||||||
)
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package trade
|
|
||||||
|
|
||||||
import (
|
|
||||||
m "platform/web/models"
|
|
||||||
|
|
||||||
"github.com/shopspring/decimal"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Type int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypePurchase Type = iota + 1 // 购买
|
|
||||||
TypeRecharge // 充值
|
|
||||||
)
|
|
||||||
|
|
||||||
type Method int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
MethodAlipay Method = iota + 1 // 支付宝
|
|
||||||
MethodWeChat // 微信
|
|
||||||
MethodSft // 商福通
|
|
||||||
MethodSftAlipay // 商福通渠道指定支付宝
|
|
||||||
MethodSftWeChat // 商福通渠道指定微信
|
|
||||||
)
|
|
||||||
|
|
||||||
type Platform int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
PlatformDesktop Platform = iota + 1 // 桌面网站
|
|
||||||
PlatformMobile // 手机网站
|
|
||||||
)
|
|
||||||
|
|
||||||
type Acquirer int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
AcquirerAlipay Acquirer = iota + 1 // 支付宝
|
|
||||||
AcquirerWeChat // 微信
|
|
||||||
AcquirerUnionPay // 银联
|
|
||||||
)
|
|
||||||
|
|
||||||
type Status int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
StatusPending Status = iota // 待支付
|
|
||||||
StatusSuccess // 已支付
|
|
||||||
StatusCanceled // 已取消
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProductInfo interface {
|
|
||||||
GetType() Type
|
|
||||||
GetSubject() string
|
|
||||||
GetAmount() decimal.Decimal
|
|
||||||
Serialize() (string, error)
|
|
||||||
Deserialize(str string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type CompleteEvent interface {
|
|
||||||
Check(t Type) (ProductInfo, bool)
|
|
||||||
OnTradeComplete(info ProductInfo, trade *m.Trade) error
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package user
|
|
||||||
|
|
||||||
type IdType int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
IdTypeNone IdType = iota // 未认证
|
|
||||||
IdTypePersonal // 个人认证
|
|
||||||
IdTypeEnterprise // 企业认证
|
|
||||||
)
|
|
||||||
|
|
||||||
type Status int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
StatusDisabled Status = iota // 禁用
|
|
||||||
StatusEnabled // 启用
|
|
||||||
)
|
|
||||||
@@ -2,14 +2,20 @@ package events
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/hibiken/asynq"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/hibiken/asynq"
|
||||||
)
|
)
|
||||||
|
|
||||||
const RemoveChannel = "channel:remove"
|
const RemoveChannel = "channel:remove"
|
||||||
|
|
||||||
func NewRemoveChannel(ids []int32) *asynq.Task {
|
type RemoveChannelData struct {
|
||||||
bytes, err := json.Marshal(ids)
|
Batch string `json:"batch"`
|
||||||
|
IDs []int32 `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRemoveChannel(data RemoveChannelData) *asynq.Task {
|
||||||
|
bytes, err := json.Marshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("序列化删除通道任务失败", "error", err)
|
slog.Error("序列化删除通道任务失败", "error", err)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
9
web/events/proxy.go
Normal file
9
web/events/proxy.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package events
|
||||||
|
|
||||||
|
import "github.com/hibiken/asynq"
|
||||||
|
|
||||||
|
const FlushGateway = "gateway:flush"
|
||||||
|
|
||||||
|
func NewFlushGateway() *asynq.Task {
|
||||||
|
return asynq.NewTask(FlushGateway, nil)
|
||||||
|
}
|
||||||
@@ -3,7 +3,8 @@ package events
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
trade2 "platform/web/domains/trade"
|
|
||||||
|
m "platform/web/models"
|
||||||
|
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
)
|
)
|
||||||
@@ -12,7 +13,7 @@ const CancelTrade = "trade:update"
|
|||||||
|
|
||||||
type CancelTradeData struct {
|
type CancelTradeData struct {
|
||||||
TradeNo string `json:"trade_no" validate:"required"`
|
TradeNo string `json:"trade_no" validate:"required"`
|
||||||
Method trade2.Method `json:"method" validate:"required"`
|
Method m.TradeMethod `json:"method" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCancelTrade(data CancelTradeData) *asynq.Task {
|
func NewCancelTrade(data CancelTradeData) *asynq.Task {
|
||||||
|
|||||||
32
web/globals/orm/inet.go
Normal file
32
web/globals/orm/inet.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package orm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Inet struct {
|
||||||
|
netip.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (inet Inet) Value() (driver.Value, error) {
|
||||||
|
return inet.MarshalBinary()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (inet *Inet) Scan(value any) (err error) {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case []byte:
|
||||||
|
return inet.UnmarshalBinary(value)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("不支持的类型: %T", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseInet(ip string) (*Inet, error) {
|
||||||
|
addr, err := netip.ParseAddr(ip)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Inet{addr}, nil
|
||||||
|
}
|
||||||
@@ -20,8 +20,7 @@ var formats = []string{
|
|||||||
"2006-01-02",
|
"2006-01-02",
|
||||||
}
|
}
|
||||||
|
|
||||||
//goland:noinspection GoMixedReceiverTypes
|
func (ldt *LocalDateTime) Scan(value any) (err error) {
|
||||||
func (ldt *LocalDateTime) Scan(value interface{}) (err error) {
|
|
||||||
var t time.Time
|
var t time.Time
|
||||||
if strValue, ok := value.(string); ok {
|
if strValue, ok := value.(string); ok {
|
||||||
var timeValue time.Time
|
var timeValue time.Time
|
||||||
@@ -50,35 +49,26 @@ func (ldt *LocalDateTime) Scan(value interface{}) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//goland:noinspection GoMixedReceiverTypes
|
|
||||||
func (ldt LocalDateTime) Value() (driver.Value, error) {
|
func (ldt LocalDateTime) Value() (driver.Value, error) {
|
||||||
return time.Time(ldt).Local(), nil
|
return time.Time(ldt).Local(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GormDataType gorm common data type
|
|
||||||
//
|
|
||||||
//goland:noinspection GoMixedReceiverTy
|
|
||||||
//goland:noinspection GoMixedReceiverTypes
|
|
||||||
func (ldt LocalDateTime) GormDataType() string {
|
func (ldt LocalDateTime) GormDataType() string {
|
||||||
return "ldt"
|
return "ldt"
|
||||||
}
|
}
|
||||||
|
|
||||||
//goland:noinspection GoMixedReceiverTypes
|
|
||||||
func (ldt LocalDateTime) GobEncode() ([]byte, error) {
|
func (ldt LocalDateTime) GobEncode() ([]byte, error) {
|
||||||
return time.Time(ldt).GobEncode()
|
return time.Time(ldt).GobEncode()
|
||||||
}
|
}
|
||||||
|
|
||||||
//goland:noinspection GoMixedReceiverTypes
|
|
||||||
func (ldt *LocalDateTime) GobDecode(b []byte) error {
|
func (ldt *LocalDateTime) GobDecode(b []byte) error {
|
||||||
return (*time.Time)(ldt).GobDecode(b)
|
return (*time.Time)(ldt).GobDecode(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
//goland:noinspection GoMixedReceiverTypes
|
|
||||||
func (ldt LocalDateTime) MarshalJSON() ([]byte, error) {
|
func (ldt LocalDateTime) MarshalJSON() ([]byte, error) {
|
||||||
return time.Time(ldt).MarshalJSON()
|
return time.Time(ldt).MarshalJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
//goland:noinspection GoMixedReceiverTypes
|
|
||||||
func (ldt *LocalDateTime) UnmarshalJSON(b []byte) error {
|
func (ldt *LocalDateTime) UnmarshalJSON(b []byte) error {
|
||||||
return (*time.Time)(ldt).UnmarshalJSON(b)
|
return (*time.Time)(ldt).UnmarshalJSON(b)
|
||||||
}
|
}
|
||||||
|
|||||||
24
web/globals/orm/slice.go
Normal file
24
web/globals/orm/slice.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package orm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Slice[T any] struct {
|
||||||
|
Arr []T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Slice[T]) Value() (driver.Value, error) {
|
||||||
|
return json.Marshal(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Slice[T]) Scan(value any) error {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case []byte:
|
||||||
|
return json.Unmarshal(value, s)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("不支持的类型: %T", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ package handlers
|
|||||||
import (
|
import (
|
||||||
"platform/web/auth"
|
"platform/web/auth"
|
||||||
"platform/web/core"
|
"platform/web/core"
|
||||||
"platform/web/globals/orm"
|
|
||||||
q "platform/web/queries"
|
q "platform/web/queries"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -39,13 +38,13 @@ func ListBill(c *fiber.Ctx) error {
|
|||||||
Where(q.Bill.UserID.Eq(authCtx.User.ID))
|
Where(q.Bill.UserID.Eq(authCtx.User.ID))
|
||||||
|
|
||||||
if req.Type != nil {
|
if req.Type != nil {
|
||||||
do.Where(q.Bill.Type.Eq(int32(*req.Type)))
|
do.Where(q.Bill.Type.Eq(int(*req.Type)))
|
||||||
}
|
}
|
||||||
if req.CreateAfter != nil {
|
if req.CreateAfter != nil {
|
||||||
do.Where(q.Bill.CreatedAt.Gte(orm.LocalDateTime(*req.CreateAfter)))
|
do.Where(q.Bill.CreatedAt.Gte(*req.CreateAfter))
|
||||||
}
|
}
|
||||||
if req.CreateBefore != nil {
|
if req.CreateBefore != nil {
|
||||||
do.Where(q.Bill.CreatedAt.Lte(orm.LocalDateTime(*req.CreateBefore)))
|
do.Where(q.Bill.CreatedAt.Lte(*req.CreateBefore))
|
||||||
}
|
}
|
||||||
if req.BillNo != nil && *req.BillNo != "" {
|
if req.BillNo != nil && *req.BillNo != "" {
|
||||||
do.Where(q.Bill.BillNo.Eq(*req.BillNo))
|
do.Where(q.Bill.BillNo.Eq(*req.BillNo))
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"net/netip"
|
||||||
|
"platform/pkg/u"
|
||||||
"platform/web/auth"
|
"platform/web/auth"
|
||||||
"platform/web/core"
|
"platform/web/core"
|
||||||
channel2 "platform/web/domains/channel"
|
m "platform/web/models"
|
||||||
"platform/web/globals/orm"
|
|
||||||
q "platform/web/queries"
|
q "platform/web/queries"
|
||||||
s "platform/web/services"
|
s "platform/web/services"
|
||||||
"time"
|
"time"
|
||||||
@@ -40,18 +40,18 @@ func ListChannels(c *fiber.Ctx) error {
|
|||||||
Where(q.Channel.UserID.Eq(authContext.User.ID))
|
Where(q.Channel.UserID.Eq(authContext.User.ID))
|
||||||
switch req.AuthType {
|
switch req.AuthType {
|
||||||
case s.ChannelAuthTypeIp:
|
case s.ChannelAuthTypeIp:
|
||||||
cond.Where(q.Channel.AuthIP.Is(true))
|
cond.Where(q.Channel.Whitelists.IsNotNull())
|
||||||
case s.ChannelAuthTypePass:
|
case s.ChannelAuthTypePass:
|
||||||
cond.Where(q.Channel.AuthPass.Is(true))
|
cond.Where(q.Channel.Username.IsNotNull(), q.Channel.Password.IsNotNull())
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.ExpireAfter != nil {
|
if req.ExpireAfter != nil {
|
||||||
cond.Where(q.Channel.Expiration.Gte(orm.LocalDateTime(*req.ExpireAfter)))
|
cond.Where(q.Channel.ExpiredAt.Gte(*req.ExpireAfter))
|
||||||
}
|
}
|
||||||
if req.ExpireBefore != nil {
|
if req.ExpireBefore != nil {
|
||||||
cond.Where(q.Channel.Expiration.Lte(orm.LocalDateTime(*req.ExpireBefore)))
|
cond.Where(q.Channel.ExpiredAt.Lte(*req.ExpireBefore))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询数据
|
// 查询数据
|
||||||
@@ -92,17 +92,17 @@ func ListChannels(c *fiber.Ctx) error {
|
|||||||
type CreateChannelReq struct {
|
type CreateChannelReq struct {
|
||||||
ResourceId int32 `json:"resource_id" validate:"required"`
|
ResourceId int32 `json:"resource_id" validate:"required"`
|
||||||
AuthType s.ChannelAuthType `json:"auth_type" validate:"required"`
|
AuthType s.ChannelAuthType `json:"auth_type" validate:"required"`
|
||||||
Protocol channel2.Protocol `json:"protocol" validate:"required"`
|
Protocol int `json:"protocol" validate:"required"`
|
||||||
Count int `json:"count" validate:"required"`
|
Count int `json:"count" validate:"required"`
|
||||||
Prov string `json:"prov"`
|
Prov *string `json:"prov"`
|
||||||
City string `json:"city"`
|
City *string `json:"city"`
|
||||||
Isp string `json:"isp"`
|
Isp *int `json:"isp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateChannelRespItem struct {
|
type CreateChannelRespItem struct {
|
||||||
Proto channel2.Protocol `json:"-"`
|
Proto int `json:"-"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
Port int32 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
Username *string `json:"username,omitempty"`
|
Username *string `json:"username,omitempty"`
|
||||||
Password *string `json:"password,omitempty"`
|
Password *string `json:"password,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -115,48 +115,32 @@ func CreateChannel(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查用户其他权限
|
|
||||||
user := authCtx.User
|
user := authCtx.User
|
||||||
if user.IDToken == nil || *user.IDToken == "" {
|
if user.IDToken == nil || *user.IDToken == "" {
|
||||||
return fiber.NewError(fiber.StatusForbidden, "账号未实名")
|
return fiber.NewError(fiber.StatusForbidden, "账号未实名")
|
||||||
}
|
}
|
||||||
|
|
||||||
count, err := q.Whitelist.Where(
|
// 解析参数
|
||||||
q.Whitelist.UserID.Eq(user.ID),
|
|
||||||
q.Whitelist.Host.Eq(c.IP()),
|
|
||||||
).Count()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if count == 0 {
|
|
||||||
return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("非白名单IP %s", c.IP()))
|
|
||||||
}
|
|
||||||
|
|
||||||
req := new(CreateChannelReq)
|
req := new(CreateChannelReq)
|
||||||
if err := c.BodyParser(req); err != nil {
|
if err := c.BodyParser(req); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var isp string
|
ip, err := netip.ParseAddr(c.Get(core.HeaderUserIP))
|
||||||
switch req.Isp {
|
if err != nil {
|
||||||
case "1":
|
return core.NewBizErr("解析请求头客户端 IP 地址失败", err)
|
||||||
isp = "电信"
|
|
||||||
case "2":
|
|
||||||
isp = "联通"
|
|
||||||
case "3":
|
|
||||||
isp = "移动"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建通道
|
// 创建通道
|
||||||
result, err := s.Channel.CreateChannel(
|
result, err := s.Channel.CreateChannels(
|
||||||
c,
|
ip,
|
||||||
user.ID,
|
user.ID,
|
||||||
req.ResourceId,
|
req.ResourceId,
|
||||||
req.Protocol,
|
req.AuthType == s.ChannelAuthTypeIp,
|
||||||
req.AuthType,
|
req.AuthType == s.ChannelAuthTypePass,
|
||||||
req.Count,
|
req.Count,
|
||||||
s.EdgeFilter{
|
s.EdgeFilter{
|
||||||
Isp: isp,
|
Isp: u.ElseTo(req.Isp, m.ToEdgeISP),
|
||||||
Prov: req.Prov,
|
Prov: req.Prov,
|
||||||
City: req.City,
|
City: req.City,
|
||||||
},
|
},
|
||||||
@@ -170,8 +154,8 @@ func CreateChannel(c *fiber.Ctx) error {
|
|||||||
for i, channel := range result {
|
for i, channel := range result {
|
||||||
resp[i] = &CreateChannelRespItem{
|
resp[i] = &CreateChannelRespItem{
|
||||||
Proto: req.Protocol,
|
Proto: req.Protocol,
|
||||||
Host: channel.ProxyHost,
|
Host: channel.Proxy.IP.String(),
|
||||||
Port: channel.ProxyPort,
|
Port: channel.Port,
|
||||||
}
|
}
|
||||||
if req.AuthType == s.ChannelAuthTypePass {
|
if req.AuthType == s.ChannelAuthTypePass {
|
||||||
resp[i].Username = channel.Username
|
resp[i].Username = channel.Username
|
||||||
@@ -188,12 +172,13 @@ type CreateChannelResultType string
|
|||||||
// region RemoveChannels
|
// region RemoveChannels
|
||||||
|
|
||||||
type RemoveChannelsReq struct {
|
type RemoveChannelsReq struct {
|
||||||
ByIds []int32 `json:"by_ids" validate:"required"`
|
Batch string `json:"batch" validate:"required"`
|
||||||
|
Ids []int32 `json:"ids" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveChannels(c *fiber.Ctx) error {
|
func RemoveChannels(c *fiber.Ctx) error {
|
||||||
// 检查权限
|
// 检查权限
|
||||||
authCtx, err := auth.GetAuthCtx(c).PermitUser()
|
_, err := auth.GetAuthCtx(c).PermitOfficialClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -205,7 +190,7 @@ func RemoveChannels(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 删除通道
|
// 删除通道
|
||||||
err = s.Channel.RemoveChannels(req.ByIds, authCtx.User.ID)
|
err = s.Channel.RemoveChannels(req.Batch, req.Ids)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,8 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
"platform/pkg/u"
|
|
||||||
"platform/web/auth"
|
|
||||||
edge2 "platform/web/domains/edge"
|
|
||||||
proxy2 "platform/web/domains/proxy"
|
|
||||||
g "platform/web/globals"
|
|
||||||
m "platform/web/models"
|
|
||||||
q "platform/web/queries"
|
|
||||||
s "platform/web/services"
|
s "platform/web/services"
|
||||||
|
|
||||||
"gorm.io/gen/field"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,80 +17,82 @@ type RegisterEdgeResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AssignEdge(c *fiber.Ctx) (err error) {
|
func AssignEdge(c *fiber.Ctx) (err error) {
|
||||||
|
return c.JSON(map[string]any{
|
||||||
// 验证请求参数
|
"error": "接口暂不可用",
|
||||||
var req = new(RegisterEdgeReq)
|
|
||||||
err = g.Validator.Validate(c, req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 全局锁,防止并发注册
|
|
||||||
var mutex = g.Redsync.NewMutex("edge:discovery")
|
|
||||||
if err := mutex.Lock(); err != nil {
|
|
||||||
return errors.New("服务繁忙,请稍后重试")
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if ok, err := mutex.Unlock(); err != nil {
|
|
||||||
slog.Error("解锁失败", slog.Bool("ok", ok), slog.Any("err", err))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 检查节点
|
|
||||||
var fwd *m.Proxy
|
|
||||||
var edge *m.Edge
|
|
||||||
edge, err = q.Edge.
|
|
||||||
Where(q.Edge.Name.Eq(req.Name)).
|
|
||||||
Take()
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
// 挑选合适的转发服务
|
|
||||||
fwd, err = q.Proxy.
|
|
||||||
LeftJoin(q.Edge, q.Edge.ProxyID.EqCol(q.Proxy.ID), q.Edge.Status.Eq(1)).
|
|
||||||
Select(q.Proxy.ALL, q.Edge.ALL.Count().As("count")).
|
|
||||||
Where(q.Proxy.Type.Eq(int32(proxy2.TypeSelfHosted))).
|
|
||||||
Group(q.Proxy.ID).
|
|
||||||
Order(field.NewField("", "count").Desc()).
|
|
||||||
First()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// 保存节点信息
|
|
||||||
edge = &m.Edge{
|
|
||||||
Name: req.Name,
|
|
||||||
Version: int32(req.Version),
|
|
||||||
Type: int32(edge2.TypeSelfHosted),
|
|
||||||
ProxyID: &fwd.ID,
|
|
||||||
}
|
|
||||||
err = q.Edge.Create(edge)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if err == nil {
|
|
||||||
// 获取已配置的转发服务
|
|
||||||
fwd, err = q.Proxy.
|
|
||||||
Where(q.Proxy.ID.Eq(*edge.ProxyID)).
|
|
||||||
Take()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// 节点已存在,更新版本号
|
|
||||||
if edge.Version < int32(req.Version) {
|
|
||||||
_, err = q.Edge.
|
|
||||||
Where(q.Edge.ID.Eq(edge.ID)).
|
|
||||||
UpdateSimple(q.Edge.Version.Value(int32(req.Version)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回服务地址
|
|
||||||
return c.JSON(RegisterEdgeResp{
|
|
||||||
Id: edge.ID,
|
|
||||||
Host: fwd.Host,
|
|
||||||
})
|
})
|
||||||
|
// // 验证请求参数
|
||||||
|
// var req = new(RegisterEdgeReq)
|
||||||
|
// err = g.Validator.Validate(c, req)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 全局锁,防止并发注册
|
||||||
|
// var mutex = g.Redsync.NewMutex("edge:discovery")
|
||||||
|
// if err := mutex.Lock(); err != nil {
|
||||||
|
// return errors.New("服务繁忙,请稍后重试")
|
||||||
|
// }
|
||||||
|
// defer func() {
|
||||||
|
// if ok, err := mutex.Unlock(); err != nil {
|
||||||
|
// slog.Error("解锁失败", slog.Bool("ok", ok), slog.Any("err", err))
|
||||||
|
// }
|
||||||
|
// }()
|
||||||
|
|
||||||
|
// // 检查节点
|
||||||
|
// var fwd *m.Proxy
|
||||||
|
// var edge *m.Edge
|
||||||
|
// edge, err = q.Edge.
|
||||||
|
// Where(q.Edge.Mac.Eq(req.Name)).
|
||||||
|
// Take()
|
||||||
|
// if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
// // 挑选合适的转发服务
|
||||||
|
// fwd, err = q.Proxy.
|
||||||
|
// LeftJoin(q.Edge, q.Edge.ProxyID.EqCol(q.Proxy.ID), q.Edge.Status.Eq(1)).
|
||||||
|
// Select(q.Proxy.ALL, q.Edge.ALL.Count().As("count")).
|
||||||
|
// Where(q.Proxy.Type.Eq(int32(proxy2.TypeSelfHosted))).
|
||||||
|
// Group(q.Proxy.ID).
|
||||||
|
// Order(field.NewField("", "count").Desc()).
|
||||||
|
// First()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// // 保存节点信息
|
||||||
|
// edge = &m.Edge{
|
||||||
|
// Name: req.Name,
|
||||||
|
// Version: int32(req.Version),
|
||||||
|
// Type: int32(edge2.TypeSelfHosted),
|
||||||
|
// ProxyID: &fwd.ID,
|
||||||
|
// }
|
||||||
|
// err = q.Edge.Create(edge)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// } else if err == nil {
|
||||||
|
// // 获取已配置的转发服务
|
||||||
|
// fwd, err = q.Proxy.
|
||||||
|
// Where(q.Proxy.ID.Eq(*edge.ProxyID)).
|
||||||
|
// Take()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// // 节点已存在,更新版本号
|
||||||
|
// if edge.Version < int32(req.Version) {
|
||||||
|
// _, err = q.Edge.
|
||||||
|
// Where(q.Edge.ID.Eq(edge.ID)).
|
||||||
|
// UpdateSimple(q.Edge.Version.Value(int32(req.Version)))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 返回服务地址
|
||||||
|
// return c.JSON(RegisterEdgeResp{
|
||||||
|
// Id: edge.ID,
|
||||||
|
// Host: fwd.Host,
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
type AllEdgesAvailableReq struct {
|
type AllEdgesAvailableReq struct {
|
||||||
@@ -120,36 +110,40 @@ type AllEdgesAvailableRespItem struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AllEdgesAvailable(c *fiber.Ctx) (err error) {
|
func AllEdgesAvailable(c *fiber.Ctx) (err error) {
|
||||||
// 检查权限
|
return c.JSON(map[string]any{
|
||||||
_, err = auth.GetAuthCtx(c).PermitSecretClient()
|
"error": "接口暂不可用",
|
||||||
if err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证请求参数
|
// // 检查权限
|
||||||
var req = new(AllEdgesAvailableReq)
|
// _, err = auth.GetAuthCtx(c).PermitSecretClient()
|
||||||
err = g.Validator.Validate(c, req)
|
// if err != nil {
|
||||||
if err != nil {
|
// return err
|
||||||
return err
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
// 获取可用的转发服务
|
// // 验证请求参数
|
||||||
infos, err := s.Edge.AllEdges(req.Count, req.EdgeFilter)
|
// var req = new(AllEdgesAvailableReq)
|
||||||
if err != nil {
|
// err = g.Validator.Validate(c, req)
|
||||||
return err
|
// if err != nil {
|
||||||
}
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
// 返回结果
|
// // 获取可用的转发服务
|
||||||
var edges = make([]AllEdgesAvailableRespItem, len(infos))
|
// infos, err := s.Edge.AllEdges(req.Count, req.EdgeFilter)
|
||||||
for i, info := range infos {
|
// if err != nil {
|
||||||
edges[i] = AllEdgesAvailableRespItem{
|
// return err
|
||||||
Ip: info.Host,
|
// }
|
||||||
Port: u.Z(info.ProxyPort),
|
|
||||||
Isp: edge2.ISP(info.Isp).String(),
|
// // 返回结果
|
||||||
Prov: info.Prov,
|
// var edges = make([]AllEdgesAvailableRespItem, len(infos))
|
||||||
City: info.City,
|
// for i, info := range infos {
|
||||||
Status: info.Status,
|
// edges[i] = AllEdgesAvailableRespItem{
|
||||||
}
|
// Ip: info.Host,
|
||||||
}
|
// Port: u.Z(info.ProxyPort),
|
||||||
return c.JSON(edges)
|
// Isp: edge2.ISP(info.Isp).String(),
|
||||||
|
// Prov: info.Prov,
|
||||||
|
// City: info.City,
|
||||||
|
// Status: info.Status,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return c.JSON(edges)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import (
|
|||||||
// region Identify
|
// region Identify
|
||||||
|
|
||||||
type IdentifyReq struct {
|
type IdentifyReq struct {
|
||||||
Type int32 `json:"type" validate:"required,oneof=1 2"`
|
Type int `json:"type" validate:"required,oneof=1 2"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
IdenNo string `json:"iden_no" validate:"required"`
|
IdenNo string `json:"iden_no" validate:"required"`
|
||||||
}
|
}
|
||||||
@@ -173,7 +173,7 @@ func IdentifyCallback(c *fiber.Ctx) error {
|
|||||||
q.User.Name,
|
q.User.Name,
|
||||||
).
|
).
|
||||||
Updates(m.User{
|
Updates(m.User{
|
||||||
IDType: info.Type,
|
IDType: m.UserIDType(info.Type),
|
||||||
IDNo: &info.IdNo,
|
IDNo: &info.IdNo,
|
||||||
IDToken: &info.Token,
|
IDToken: &info.Token,
|
||||||
Name: &info.Name,
|
Name: &info.Name,
|
||||||
@@ -202,7 +202,7 @@ func idenKey(id string) string {
|
|||||||
|
|
||||||
type idenInfo struct {
|
type idenInfo struct {
|
||||||
Uid int32 `json:"uid"`
|
Uid int32 `json:"uid"`
|
||||||
Type int32 `json:"type"`
|
Type int `json:"type"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
IdNo string `json:"id_no"`
|
IdNo string `json:"id_no"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
|||||||
@@ -1,26 +1,9 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"encoding/base32"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"platform/pkg/u"
|
|
||||||
auth2 "platform/web/auth"
|
|
||||||
"platform/web/core"
|
|
||||||
edge2 "platform/web/domains/edge"
|
|
||||||
proxy2 "platform/web/domains/proxy"
|
|
||||||
g "platform/web/globals"
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
m "platform/web/models"
|
|
||||||
q "platform/web/queries"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
"gorm.io/gen/field"
|
|
||||||
"gorm.io/gorm/clause"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// region 报告上线
|
// region 报告上线
|
||||||
@@ -38,103 +21,106 @@ type ProxyReportOnlineResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ProxyReportOnline(c *fiber.Ctx) (err error) {
|
func ProxyReportOnline(c *fiber.Ctx) (err error) {
|
||||||
|
return c.JSON(map[string]any{
|
||||||
// 检查接口权限
|
"error": "接口暂不可用",
|
||||||
_, err = auth2.GetAuthCtx(c).PermitSecretClient()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证请求参数
|
|
||||||
var req = new(ProxyReportOnlineReq)
|
|
||||||
err = g.Validator.Validate(c, req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建代理
|
|
||||||
var ip = c.Context().RemoteIP()
|
|
||||||
|
|
||||||
var secretBytes = make([]byte, 16)
|
|
||||||
if _, err := rand.Read(secretBytes); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var secret = base32.StdEncoding.
|
|
||||||
WithPadding(base32.NoPadding).
|
|
||||||
EncodeToString(secretBytes)
|
|
||||||
slog.Debug("生成随机密钥", "ip", ip, "secret", secret)
|
|
||||||
|
|
||||||
var proxy = &m.Proxy{
|
|
||||||
Name: req.Name,
|
|
||||||
Version: int32(req.Version),
|
|
||||||
Type: int32(proxy2.TypeSelfHosted),
|
|
||||||
Host: ip.String(),
|
|
||||||
Secret: &secret,
|
|
||||||
Status: 1,
|
|
||||||
}
|
|
||||||
err = q.Proxy.
|
|
||||||
Clauses(clause.OnConflict{
|
|
||||||
UpdateAll: true,
|
|
||||||
Columns: []clause.Column{
|
|
||||||
{Name: q.Proxy.Name.ColumnName().String()},
|
|
||||||
},
|
|
||||||
}).
|
|
||||||
Create(proxy)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取边缘节点信息
|
|
||||||
data, err := q.Edge.Where(
|
|
||||||
q.Edge.ProxyID.Eq(proxy.ID),
|
|
||||||
).Find()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
edges := make([]*ProxyEdge, len(data))
|
|
||||||
for i, edge := range data {
|
|
||||||
edges[i] = &ProxyEdge{
|
|
||||||
Id: edge.ID,
|
|
||||||
Port: edge.ProxyPort,
|
|
||||||
Prov: &edge.Prov,
|
|
||||||
City: &edge.City,
|
|
||||||
Isp: u.P(edge2.ISP(edge.Isp).String()),
|
|
||||||
Status: &edge.Status,
|
|
||||||
Loss: edge.Loss,
|
|
||||||
Rtt: edge.Rtt,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取许可配置
|
|
||||||
channels, err := q.Channel.Where(
|
|
||||||
q.Channel.ProxyID.Eq(proxy.ID),
|
|
||||||
q.Channel.Expiration.Gt(orm.LocalDateTime(time.Now())),
|
|
||||||
).Find()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var permits = make([]*ProxyPermit, len(channels))
|
|
||||||
for i, channel := range channels {
|
|
||||||
if channel.EdgeID == nil {
|
|
||||||
return core.NewBizErr(fmt.Sprintf("权限解析异常,通道缺少边缘节点ID %d", channel.ID))
|
|
||||||
}
|
|
||||||
permits[i] = &ProxyPermit{
|
|
||||||
Id: *channel.EdgeID,
|
|
||||||
Expire: time.Time(channel.Expiration),
|
|
||||||
Whitelists: u.P(strings.Split(u.Z(channel.Whitelists), ",")),
|
|
||||||
Username: channel.Username,
|
|
||||||
Password: channel.Password,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debug("注册转发服务", "ip", ip, "id", proxy.ID)
|
|
||||||
return c.JSON(&ProxyReportOnlineResp{
|
|
||||||
Id: proxy.ID,
|
|
||||||
Secret: secret,
|
|
||||||
Edges: edges,
|
|
||||||
Permits: permits,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// // 检查接口权限
|
||||||
|
// _, err = auth2.GetAuthCtx(c).PermitSecretClient()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 验证请求参数
|
||||||
|
// var req = new(ProxyReportOnlineReq)
|
||||||
|
// err = g.Validator.Validate(c, req)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 创建代理
|
||||||
|
// var ip = c.Context().RemoteIP()
|
||||||
|
|
||||||
|
// var secretBytes = make([]byte, 16)
|
||||||
|
// if _, err := rand.Read(secretBytes); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// var secret = base32.StdEncoding.
|
||||||
|
// WithPadding(base32.NoPadding).
|
||||||
|
// EncodeToString(secretBytes)
|
||||||
|
// slog.Debug("生成随机密钥", "ip", ip, "secret", secret)
|
||||||
|
|
||||||
|
// var proxy = &m.Proxy{
|
||||||
|
// Mac: req.Name,
|
||||||
|
// Version: int32(req.Version),
|
||||||
|
// Type: m.ProxyTypeSelfHosted,
|
||||||
|
// IP: ip,
|
||||||
|
// Secret: &secret,
|
||||||
|
// Status: 1,
|
||||||
|
// }
|
||||||
|
// err = q.Proxy.
|
||||||
|
// Clauses(clause.OnConflict{
|
||||||
|
// UpdateAll: true,
|
||||||
|
// Columns: []clause.Column{
|
||||||
|
// {Name: q.Proxy.Mac.ColumnName().String()},
|
||||||
|
// },
|
||||||
|
// }).
|
||||||
|
// Create(proxy)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 获取边缘节点信息
|
||||||
|
// data, err := q.Edge.Where(
|
||||||
|
// q.Edge.ProxyID.Eq(proxy.ID),
|
||||||
|
// ).Find()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// edges := make([]*ProxyEdge, len(data))
|
||||||
|
// for i, edge := range data {
|
||||||
|
// edges[i] = &ProxyEdge{
|
||||||
|
// Id: edge.ID,
|
||||||
|
// Port: edge.ProxyPort,
|
||||||
|
// Prov: &edge.Prov,
|
||||||
|
// City: &edge.City,
|
||||||
|
// Isp: u.P(edge2.ISP(edge.Isp).String()),
|
||||||
|
// Status: &edge.Status,
|
||||||
|
// Loss: edge.Loss,
|
||||||
|
// Rtt: edge.Rtt,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 获取许可配置
|
||||||
|
// channels, err := q.Channel.Where(
|
||||||
|
// q.Channel.ProxyID.Eq(proxy.ID),
|
||||||
|
// q.Channel.Expiration.Gt(orm.LocalDateTime(time.Now())),
|
||||||
|
// ).Find()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// var permits = make([]*ProxyPermit, len(channels))
|
||||||
|
// for i, channel := range channels {
|
||||||
|
// if channel.EdgeID == nil {
|
||||||
|
// return core.NewBizErr(fmt.Sprintf("权限解析异常,通道缺少边缘节点ID %d", channel.ID))
|
||||||
|
// }
|
||||||
|
// permits[i] = &ProxyPermit{
|
||||||
|
// Id: *channel.EdgeID,
|
||||||
|
// Expire: time.Time(channel.Expiration),
|
||||||
|
// Whitelists: u.P(strings.Split(u.Z(channel.Whitelists), ",")),
|
||||||
|
// Username: channel.Username,
|
||||||
|
// Password: channel.Password,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// slog.Debug("注册转发服务", "ip", ip, "id", proxy.ID)
|
||||||
|
// return c.JSON(&ProxyReportOnlineResp{
|
||||||
|
// Id: proxy.ID,
|
||||||
|
// Secret: secret,
|
||||||
|
// Edges: edges,
|
||||||
|
// Permits: permits,
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@@ -146,36 +132,40 @@ type ProxyReportOfflineReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ProxyReportOffline(c *fiber.Ctx) (err error) {
|
func ProxyReportOffline(c *fiber.Ctx) (err error) {
|
||||||
// 检查接口权限
|
return c.JSON(map[string]any{
|
||||||
_, err = auth2.GetAuthCtx(c).PermitSecretClient()
|
"error": "接口暂不可用",
|
||||||
if err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证请求参数
|
// // 检查接口权限
|
||||||
var req = new(ProxyReportOfflineReq)
|
// _, err = auth2.GetAuthCtx(c).PermitSecretClient()
|
||||||
err = g.Validator.Validate(c, req)
|
// if err != nil {
|
||||||
if err != nil {
|
// return err
|
||||||
return err
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
// 下线转发服务
|
// // 验证请求参数
|
||||||
_, err = q.Proxy.
|
// var req = new(ProxyReportOfflineReq)
|
||||||
Where(q.Proxy.ID.Eq(req.Id)).
|
// err = g.Validator.Validate(c, req)
|
||||||
UpdateSimple(q.Proxy.Status.Value(0))
|
// if err != nil {
|
||||||
if err != nil {
|
// return err
|
||||||
return err
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
// 下线所有相关的边缘节点
|
// // 下线转发服务
|
||||||
_, err = q.Edge.
|
// _, err = q.Proxy.
|
||||||
Where(q.Edge.ProxyID.Eq(req.Id)).
|
// Where(q.Proxy.ID.Eq(req.Id)).
|
||||||
UpdateSimple(q.Edge.Status.Value(0))
|
// UpdateSimple(q.Proxy.Status.Value(0))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
|
||||||
return nil
|
// // 下线所有相关的边缘节点
|
||||||
|
// _, err = q.Edge.
|
||||||
|
// Where(q.Edge.ProxyID.Eq(req.Id)).
|
||||||
|
// UpdateSimple(q.Edge.Status.Value(0))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@@ -188,157 +178,161 @@ type ProxyReportUpdateReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ProxyReportUpdate(c *fiber.Ctx) (err error) {
|
func ProxyReportUpdate(c *fiber.Ctx) (err error) {
|
||||||
// 检查接口权限
|
return c.JSON(map[string]any{
|
||||||
_, err = auth2.GetAuthCtx(c).PermitSecretClient()
|
"error": "接口暂不可用",
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证请求参数
|
|
||||||
var req = new(ProxyReportUpdateReq)
|
|
||||||
err = g.Validator.Validate(c, req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新节点信息
|
|
||||||
var idsActive = make([]int32, 0, len(req.Edges))
|
|
||||||
var idsInactive = make([]int32, 0, len(req.Edges))
|
|
||||||
var idsIspUnknown = make([]int32, 0, len(req.Edges))
|
|
||||||
var idsIspTelecom = make([]int32, 0, len(req.Edges))
|
|
||||||
var idsIspUnicom = make([]int32, 0, len(req.Edges))
|
|
||||||
var idsIspMobile = make([]int32, 0, len(req.Edges))
|
|
||||||
var otherEdges = make([]*ProxyEdge, 0, len(req.Edges))
|
|
||||||
for _, edge := range req.Edges {
|
|
||||||
|
|
||||||
// 检查更新ISP
|
|
||||||
if edge.Isp != nil {
|
|
||||||
switch edge2.ISPFromStr(*edge.Isp) {
|
|
||||||
case edge2.IspUnknown:
|
|
||||||
idsIspUnknown = append(idsIspUnknown, edge.Id)
|
|
||||||
case edge2.IspChinaTelecom:
|
|
||||||
idsIspTelecom = append(idsIspTelecom, edge.Id)
|
|
||||||
case edge2.IspChinaUnicom:
|
|
||||||
idsIspUnicom = append(idsIspUnicom, edge.Id)
|
|
||||||
case edge2.IspChinaMobile:
|
|
||||||
idsIspMobile = append(idsIspMobile, edge.Id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查更新状态
|
|
||||||
if edge.Status != nil {
|
|
||||||
if *edge.Status == 1 {
|
|
||||||
idsActive = append(idsActive, edge.Id)
|
|
||||||
} else {
|
|
||||||
idsInactive = append(idsInactive, edge.Id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 无法分类更新
|
|
||||||
if edge.Host != nil || edge.Port != nil || edge.Prov != nil || edge.City != nil {
|
|
||||||
otherEdges = append(otherEdges, edge)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debug("更新边缘节点信息",
|
|
||||||
"active", len(idsActive),
|
|
||||||
"inactive", len(idsInactive),
|
|
||||||
"isp_unknown", len(idsIspUnknown),
|
|
||||||
"isp_telecom", len(idsIspTelecom),
|
|
||||||
"isp_unicom", len(idsIspUnicom),
|
|
||||||
"isp_mobile", len(idsIspMobile),
|
|
||||||
"other_edges", len(otherEdges),
|
|
||||||
)
|
|
||||||
|
|
||||||
err = q.Q.Transaction(func(q *q.Query) error {
|
|
||||||
// 更新边缘节点状态
|
|
||||||
if len(idsActive) > 0 {
|
|
||||||
_, err = q.Edge.Debug().
|
|
||||||
Where(q.Edge.ID.In(idsActive...)).
|
|
||||||
UpdateSimple(q.Edge.Status.Value(1))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(idsInactive) > 0 {
|
|
||||||
_, err = q.Edge.Debug().
|
|
||||||
Where(q.Edge.ID.In(idsInactive...)).
|
|
||||||
UpdateSimple(q.Edge.Status.Value(0))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新边缘节点ISP
|
|
||||||
if len(idsIspUnknown) > 0 {
|
|
||||||
_, err = q.Edge.Debug().
|
|
||||||
Where(q.Edge.ID.In(idsIspUnknown...)).
|
|
||||||
UpdateSimple(q.Edge.Isp.Value(int32(edge2.IspUnknown)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(idsIspTelecom) > 0 {
|
|
||||||
_, err = q.Edge.Debug().
|
|
||||||
Where(q.Edge.ID.In(idsIspTelecom...)).
|
|
||||||
UpdateSimple(q.Edge.Isp.Value(int32(edge2.IspChinaTelecom)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(idsIspUnicom) > 0 {
|
|
||||||
_, err = q.Edge.Debug().
|
|
||||||
Where(q.Edge.ID.In(idsIspUnicom...)).
|
|
||||||
UpdateSimple(q.Edge.Isp.Value(int32(edge2.IspChinaUnicom)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(idsIspMobile) > 0 {
|
|
||||||
_, err = q.Edge.Debug().
|
|
||||||
Where(q.Edge.ID.In(idsIspMobile...)).
|
|
||||||
UpdateSimple(q.Edge.Isp.Value(int32(edge2.IspChinaMobile)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新其他边缘节点信息
|
|
||||||
for _, edge := range otherEdges {
|
|
||||||
do := q.Edge.Debug().Where(q.Edge.ID.Eq(edge.Id))
|
|
||||||
|
|
||||||
var assigns = make([]field.AssignExpr, 0, 5)
|
|
||||||
if edge.Host != nil {
|
|
||||||
assigns = append(assigns, q.Edge.Host.Value(*edge.Host))
|
|
||||||
}
|
|
||||||
if edge.Port != nil {
|
|
||||||
assigns = append(assigns, q.Edge.ProxyPort.Value(*edge.Port))
|
|
||||||
}
|
|
||||||
if edge.Prov != nil {
|
|
||||||
assigns = append(assigns, q.Edge.Prov.Value(*edge.Prov))
|
|
||||||
}
|
|
||||||
if edge.City != nil {
|
|
||||||
assigns = append(assigns, q.Edge.City.Value(*edge.City))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新边缘节点
|
|
||||||
_, err := do.UpdateSimple(assigns...)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("更新边缘节点 %d 失败: %w", edge.Id, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
// // 检查接口权限
|
||||||
|
// _, err = auth2.GetAuthCtx(c).PermitSecretClient()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 验证请求参数
|
||||||
|
// var req = new(ProxyReportUpdateReq)
|
||||||
|
// err = g.Validator.Validate(c, req)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 更新节点信息
|
||||||
|
// var idsActive = make([]int32, 0, len(req.Edges))
|
||||||
|
// var idsInactive = make([]int32, 0, len(req.Edges))
|
||||||
|
// var idsIspUnknown = make([]int32, 0, len(req.Edges))
|
||||||
|
// var idsIspTelecom = make([]int32, 0, len(req.Edges))
|
||||||
|
// var idsIspUnicom = make([]int32, 0, len(req.Edges))
|
||||||
|
// var idsIspMobile = make([]int32, 0, len(req.Edges))
|
||||||
|
// var otherEdges = make([]*ProxyEdge, 0, len(req.Edges))
|
||||||
|
// for _, edge := range req.Edges {
|
||||||
|
|
||||||
|
// // 检查更新ISP
|
||||||
|
// if edge.Isp != nil {
|
||||||
|
// switch edge2.ISPFromStr(*edge.Isp) {
|
||||||
|
// case edge2.IspUnknown:
|
||||||
|
// idsIspUnknown = append(idsIspUnknown, edge.Id)
|
||||||
|
// case edge2.IspChinaTelecom:
|
||||||
|
// idsIspTelecom = append(idsIspTelecom, edge.Id)
|
||||||
|
// case edge2.IspChinaUnicom:
|
||||||
|
// idsIspUnicom = append(idsIspUnicom, edge.Id)
|
||||||
|
// case edge2.IspChinaMobile:
|
||||||
|
// idsIspMobile = append(idsIspMobile, edge.Id)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 检查更新状态
|
||||||
|
// if edge.Status != nil {
|
||||||
|
// if *edge.Status == 1 {
|
||||||
|
// idsActive = append(idsActive, edge.Id)
|
||||||
|
// } else {
|
||||||
|
// idsInactive = append(idsInactive, edge.Id)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 无法分类更新
|
||||||
|
// if edge.Host != nil || edge.Port != nil || edge.Prov != nil || edge.City != nil {
|
||||||
|
// otherEdges = append(otherEdges, edge)
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// slog.Debug("更新边缘节点信息",
|
||||||
|
// "active", len(idsActive),
|
||||||
|
// "inactive", len(idsInactive),
|
||||||
|
// "isp_unknown", len(idsIspUnknown),
|
||||||
|
// "isp_telecom", len(idsIspTelecom),
|
||||||
|
// "isp_unicom", len(idsIspUnicom),
|
||||||
|
// "isp_mobile", len(idsIspMobile),
|
||||||
|
// "other_edges", len(otherEdges),
|
||||||
|
// )
|
||||||
|
|
||||||
|
// err = q.Q.Transaction(func(q *q.Query) error {
|
||||||
|
// // 更新边缘节点状态
|
||||||
|
// if len(idsActive) > 0 {
|
||||||
|
// _, err = q.Edge.Debug().
|
||||||
|
// Where(q.Edge.ID.In(idsActive...)).
|
||||||
|
// UpdateSimple(q.Edge.Status.Value(1))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if len(idsInactive) > 0 {
|
||||||
|
// _, err = q.Edge.Debug().
|
||||||
|
// Where(q.Edge.ID.In(idsInactive...)).
|
||||||
|
// UpdateSimple(q.Edge.Status.Value(0))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 更新边缘节点ISP
|
||||||
|
// if len(idsIspUnknown) > 0 {
|
||||||
|
// _, err = q.Edge.Debug().
|
||||||
|
// Where(q.Edge.ID.In(idsIspUnknown...)).
|
||||||
|
// UpdateSimple(q.Edge.Isp.Value(int32(edge2.IspUnknown)))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if len(idsIspTelecom) > 0 {
|
||||||
|
// _, err = q.Edge.Debug().
|
||||||
|
// Where(q.Edge.ID.In(idsIspTelecom...)).
|
||||||
|
// UpdateSimple(q.Edge.Isp.Value(int32(edge2.IspChinaTelecom)))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if len(idsIspUnicom) > 0 {
|
||||||
|
// _, err = q.Edge.Debug().
|
||||||
|
// Where(q.Edge.ID.In(idsIspUnicom...)).
|
||||||
|
// UpdateSimple(q.Edge.Isp.Value(int32(edge2.IspChinaUnicom)))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if len(idsIspMobile) > 0 {
|
||||||
|
// _, err = q.Edge.Debug().
|
||||||
|
// Where(q.Edge.ID.In(idsIspMobile...)).
|
||||||
|
// UpdateSimple(q.Edge.Isp.Value(int32(edge2.IspChinaMobile)))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 更新其他边缘节点信息
|
||||||
|
// for _, edge := range otherEdges {
|
||||||
|
// do := q.Edge.Debug().Where(q.Edge.ID.Eq(edge.Id))
|
||||||
|
|
||||||
|
// var assigns = make([]field.AssignExpr, 0, 5)
|
||||||
|
// if edge.Host != nil {
|
||||||
|
// assigns = append(assigns, q.Edge.Host.Value(*edge.Host))
|
||||||
|
// }
|
||||||
|
// if edge.Port != nil {
|
||||||
|
// assigns = append(assigns, q.Edge.ProxyPort.Value(*edge.Port))
|
||||||
|
// }
|
||||||
|
// if edge.Prov != nil {
|
||||||
|
// assigns = append(assigns, q.Edge.Prov.Value(*edge.Prov))
|
||||||
|
// }
|
||||||
|
// if edge.City != nil {
|
||||||
|
// assigns = append(assigns, q.Edge.City.Value(*edge.City))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 更新边缘节点
|
||||||
|
// _, err := do.UpdateSimple(assigns...)
|
||||||
|
// if err != nil {
|
||||||
|
// return fmt.Errorf("更新边缘节点 %d 失败: %w", edge.Id, err)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// })
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ import (
|
|||||||
"platform/pkg/u"
|
"platform/pkg/u"
|
||||||
"platform/web/auth"
|
"platform/web/auth"
|
||||||
"platform/web/core"
|
"platform/web/core"
|
||||||
resource2 "platform/web/domains/resource"
|
|
||||||
g "platform/web/globals"
|
g "platform/web/globals"
|
||||||
"platform/web/globals/orm"
|
m "platform/web/models"
|
||||||
q "platform/web/queries"
|
q "platform/web/queries"
|
||||||
s "platform/web/services"
|
s "platform/web/services"
|
||||||
"time"
|
"time"
|
||||||
@@ -43,7 +42,7 @@ func ListResourceShort(c *fiber.Ctx) error {
|
|||||||
// 查询套餐列表
|
// 查询套餐列表
|
||||||
do := q.Resource.Where(
|
do := q.Resource.Where(
|
||||||
q.Resource.UserID.Eq(authCtx.User.ID),
|
q.Resource.UserID.Eq(authCtx.User.ID),
|
||||||
q.Resource.Type.Eq(int32(resource2.TypeShort)),
|
q.Resource.Type.Eq(int(m.ResourceTypeShort)),
|
||||||
)
|
)
|
||||||
if req.ResourceNo != nil && *req.ResourceNo != "" {
|
if req.ResourceNo != nil && *req.ResourceNo != "" {
|
||||||
do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo))
|
do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo))
|
||||||
@@ -52,19 +51,19 @@ func ListResourceShort(c *fiber.Ctx) error {
|
|||||||
do.Where(q.Resource.Active.Is(*req.Active))
|
do.Where(q.Resource.Active.Is(*req.Active))
|
||||||
}
|
}
|
||||||
if req.Type != nil {
|
if req.Type != nil {
|
||||||
do.Where(q.ResourceShort.As(q.Resource.Short.Name()).Type.Eq(int32(*req.Type)))
|
do.Where(q.ResourceShort.As(q.Resource.Short.Name()).Type.Eq(*req.Type))
|
||||||
}
|
}
|
||||||
if req.CreateAfter != nil {
|
if req.CreateAfter != nil {
|
||||||
do.Where(q.Resource.CreatedAt.Gte(orm.LocalDateTime(*req.CreateAfter)))
|
do.Where(q.Resource.CreatedAt.Gte(*req.CreateAfter))
|
||||||
}
|
}
|
||||||
if req.CreateBefore != nil {
|
if req.CreateBefore != nil {
|
||||||
do.Where(q.Resource.CreatedAt.Lte(orm.LocalDateTime(*req.CreateBefore)))
|
do.Where(q.Resource.CreatedAt.Lte(*req.CreateBefore))
|
||||||
}
|
}
|
||||||
if req.ExpireAfter != nil {
|
if req.ExpireAfter != nil {
|
||||||
do.Where(q.ResourceShort.As(q.Resource.Short.Name()).Expire.Gte(orm.LocalDateTime(*req.ExpireAfter)))
|
do.Where(q.ResourceShort.As(q.Resource.Short.Name()).Expire.Gte(*req.ExpireAfter))
|
||||||
}
|
}
|
||||||
if req.ExpireBefore != nil {
|
if req.ExpireBefore != nil {
|
||||||
do.Where(q.ResourceShort.As(q.Resource.Short.Name()).Expire.Lte(orm.LocalDateTime(*req.ExpireBefore)))
|
do.Where(q.ResourceShort.As(q.Resource.Short.Name()).Expire.Lte(*req.ExpireBefore))
|
||||||
}
|
}
|
||||||
|
|
||||||
resource, err := q.Resource.Debug().Where(do).
|
resource, err := q.Resource.Debug().Where(do).
|
||||||
@@ -124,7 +123,7 @@ func ListResourceLong(c *fiber.Ctx) error {
|
|||||||
// 查询套餐列表
|
// 查询套餐列表
|
||||||
do := q.Resource.Where(
|
do := q.Resource.Where(
|
||||||
q.Resource.UserID.Eq(authCtx.User.ID),
|
q.Resource.UserID.Eq(authCtx.User.ID),
|
||||||
q.Resource.Type.Eq(int32(resource2.TypeLong)),
|
q.Resource.Type.Eq(int(m.ResourceTypeLong)),
|
||||||
)
|
)
|
||||||
if req.ResourceNo != nil && *req.ResourceNo != "" {
|
if req.ResourceNo != nil && *req.ResourceNo != "" {
|
||||||
do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo))
|
do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo))
|
||||||
@@ -133,19 +132,19 @@ func ListResourceLong(c *fiber.Ctx) error {
|
|||||||
do.Where(q.Resource.Active.Is(*req.Active))
|
do.Where(q.Resource.Active.Is(*req.Active))
|
||||||
}
|
}
|
||||||
if req.Type != nil {
|
if req.Type != nil {
|
||||||
do.Where(q.ResourceLong.As(q.Resource.Long.Name()).Type.Eq(int32(*req.Type)))
|
do.Where(q.ResourceLong.As(q.Resource.Long.Name()).Type.Eq(int(*req.Type)))
|
||||||
}
|
}
|
||||||
if req.CreateAfter != nil {
|
if req.CreateAfter != nil {
|
||||||
do.Where(q.Resource.CreatedAt.Gte(orm.LocalDateTime(*req.CreateAfter)))
|
do.Where(q.Resource.CreatedAt.Gte(*req.CreateAfter))
|
||||||
}
|
}
|
||||||
if req.CreateBefore != nil {
|
if req.CreateBefore != nil {
|
||||||
do.Where(q.Resource.CreatedAt.Lte(orm.LocalDateTime(*req.CreateBefore)))
|
do.Where(q.Resource.CreatedAt.Lte(*req.CreateBefore))
|
||||||
}
|
}
|
||||||
if req.ExpireAfter != nil {
|
if req.ExpireAfter != nil {
|
||||||
do.Where(q.ResourceLong.As(q.Resource.Long.Name()).Expire.Gte(orm.LocalDateTime(*req.ExpireAfter)))
|
do.Where(q.ResourceLong.As(q.Resource.Long.Name()).Expire.Gte(*req.ExpireAfter))
|
||||||
}
|
}
|
||||||
if req.ExpireBefore != nil {
|
if req.ExpireBefore != nil {
|
||||||
do.Where(q.ResourceLong.As(q.Resource.Long.Name()).Expire.Lte(orm.LocalDateTime(*req.ExpireBefore)))
|
do.Where(q.ResourceLong.As(q.Resource.Long.Name()).Expire.Lte(*req.ExpireBefore))
|
||||||
}
|
}
|
||||||
|
|
||||||
resource, err := q.Resource.Debug().Where(do).
|
resource, err := q.Resource.Debug().Where(do).
|
||||||
@@ -202,27 +201,27 @@ func AllActiveResource(c *fiber.Ctx) error {
|
|||||||
q.Resource.UserID.Eq(authCtx.User.ID),
|
q.Resource.UserID.Eq(authCtx.User.ID),
|
||||||
q.Resource.Active.Is(true),
|
q.Resource.Active.Is(true),
|
||||||
q.Resource.Where(
|
q.Resource.Where(
|
||||||
q.Resource.Type.Eq(int32(resource2.TypeShort)),
|
q.Resource.Type.Eq(int(m.ResourceTypeShort)),
|
||||||
q.ResourceShort.As(q.Resource.Short.Name()).Where(
|
q.ResourceShort.As(q.Resource.Short.Name()).Where(
|
||||||
short.Type.Eq(int32(resource2.ModeTime)),
|
short.Type.Eq(int(m.ResourceModeTime)),
|
||||||
short.Expire.Gte(orm.LocalDateTime(now)),
|
short.Expire.Gte(now),
|
||||||
q.ResourceShort.As(q.Resource.Short.Name()).
|
q.ResourceShort.As(q.Resource.Short.Name()).
|
||||||
Where(short.DailyLast.Lt(orm.LocalDateTime(u.Today()))).
|
Where(short.DailyLast.Lt(u.Today())).
|
||||||
Or(short.DailyLimit.GtCol(short.DailyUsed)),
|
Or(short.DailyLimit.GtCol(short.DailyUsed)),
|
||||||
).Or(
|
).Or(
|
||||||
short.Type.Eq(int32(resource2.ModeCount)),
|
short.Type.Eq(int(m.ResourceModeQuota)),
|
||||||
short.Quota.GtCol(short.Used),
|
short.Quota.GtCol(short.Used),
|
||||||
),
|
),
|
||||||
).Or(
|
).Or(
|
||||||
q.Resource.Type.Eq(int32(resource2.TypeLong)),
|
q.Resource.Type.Eq(int(m.ResourceTypeLong)),
|
||||||
q.ResourceLong.As(q.Resource.Long.Name()).Where(
|
q.ResourceLong.As(q.Resource.Long.Name()).Where(
|
||||||
long.Type.Eq(int32(resource2.ModeTime)),
|
long.Type.Eq(int(m.ResourceModeTime)),
|
||||||
long.Expire.Gte(orm.LocalDateTime(now)),
|
long.Expire.Gte(now),
|
||||||
q.ResourceLong.As(q.Resource.Long.Name()).
|
q.ResourceLong.As(q.Resource.Long.Name()).
|
||||||
Where(long.DailyLast.Lt(orm.LocalDateTime(u.Today()))).
|
Where(long.DailyLast.Lt(u.Today())).
|
||||||
Or(long.DailyLimit.GtCol(long.DailyUsed)),
|
Or(long.DailyLimit.GtCol(long.DailyUsed)),
|
||||||
).Or(
|
).Or(
|
||||||
long.Type.Eq(int32(resource2.ModeCount)),
|
long.Type.Eq(int(m.ResourceModeQuota)),
|
||||||
long.Quota.GtCol(long.Used),
|
long.Quota.GtCol(long.Used),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -282,23 +281,23 @@ func StatisticResourceFree(c *fiber.Ctx) error {
|
|||||||
switch {
|
switch {
|
||||||
|
|
||||||
// 短效包量
|
// 短效包量
|
||||||
case resource2.Type(resource.Type) == resource2.TypeShort && resource2.Mode(resource.Short.Type) == resource2.ModeCount:
|
case resource.Type == m.ResourceTypeShort && resource.Short.Type == m.ResourceModeQuota:
|
||||||
if u.Z(resource.Short.Quota) > resource.Short.Used {
|
if u.Z(resource.Short.Quota) > resource.Short.Used {
|
||||||
shortCount++
|
shortCount++
|
||||||
shortQuotaSum += int(u.Z(resource.Short.Quota) - resource.Short.Used)
|
shortQuotaSum += int(u.Z(resource.Short.Quota) - resource.Short.Used)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 长效包量
|
// 长效包量
|
||||||
case resource2.Type(resource.Type) == resource2.TypeLong && resource2.Mode(resource.Long.Type) == resource2.ModeCount:
|
case resource.Type == m.ResourceTypeLong && resource.Long.Type == m.ResourceModeQuota:
|
||||||
if u.Z(resource.Long.Quota) > resource.Long.Used {
|
if u.Z(resource.Long.Quota) > resource.Long.Used {
|
||||||
longCount++
|
longCount++
|
||||||
longQuotaSum += int(u.Z(resource.Long.Quota) - resource.Long.Used)
|
longQuotaSum += int(u.Z(resource.Long.Quota) - resource.Long.Used)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 短效包时
|
// 短效包时
|
||||||
case resource2.Type(resource.Type) == resource2.TypeShort && resource2.Mode(resource.Short.Type) == resource2.ModeTime:
|
case resource.Type == m.ResourceTypeShort && resource.Short.Type == m.ResourceModeTime:
|
||||||
if time.Time(*resource.Short.Expire).After(time.Now()) {
|
if time.Time(*resource.Short.Expire).After(time.Now()) {
|
||||||
if resource.Short.DailyLast == nil || u.SameDate(time.Time(*resource.Short.DailyLast)) == false {
|
if resource.Short.DailyLast == nil || u.IsToday(time.Time(*resource.Short.DailyLast)) == false {
|
||||||
shortCount++
|
shortCount++
|
||||||
shortDailyFreeSum += int(resource.Short.DailyLimit)
|
shortDailyFreeSum += int(resource.Short.DailyLimit)
|
||||||
} else if resource.Short.DailyLimit > resource.Short.DailyUsed {
|
} else if resource.Short.DailyLimit > resource.Short.DailyUsed {
|
||||||
@@ -308,9 +307,9 @@ func StatisticResourceFree(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 长效包时
|
// 长效包时
|
||||||
case resource2.Type(resource.Type) == resource2.TypeLong && resource2.Mode(resource.Long.Type) == resource2.ModeTime:
|
case resource.Type == m.ResourceTypeLong && resource.Long.Type == m.ResourceModeTime:
|
||||||
if time.Time(*resource.Long.Expire).After(time.Now()) {
|
if time.Time(*resource.Long.Expire).After(time.Now()) {
|
||||||
if resource.Long.DailyLast == nil || u.SameDate(time.Time(*resource.Long.DailyLast)) == false {
|
if resource.Long.DailyLast == nil || u.IsToday(time.Time(*resource.Long.DailyLast)) == false {
|
||||||
longCount++
|
longCount++
|
||||||
longDailyFreeSum += int(resource.Long.DailyLimit)
|
longDailyFreeSum += int(resource.Long.DailyLimit)
|
||||||
} else if resource.Long.DailyLimit > resource.Long.DailyUsed {
|
} else if resource.Long.DailyLimit > resource.Long.DailyUsed {
|
||||||
@@ -376,10 +375,10 @@ func StatisticResourceUsage(c *fiber.Ctx) error {
|
|||||||
do.Where(q.LogsUserUsage.ResourceID.Eq(resourceID))
|
do.Where(q.LogsUserUsage.ResourceID.Eq(resourceID))
|
||||||
}
|
}
|
||||||
if req.TimeAfter != nil {
|
if req.TimeAfter != nil {
|
||||||
do.Where(q.LogsUserUsage.Time.Gte(orm.LocalDateTime(*req.TimeAfter)))
|
do.Where(q.LogsUserUsage.Time.Gte(*req.TimeAfter))
|
||||||
}
|
}
|
||||||
if req.TimeBefore != nil {
|
if req.TimeBefore != nil {
|
||||||
do.Where(q.LogsUserUsage.Time.Lte(orm.LocalDateTime(*req.TimeBefore)))
|
do.Where(q.LogsUserUsage.Time.Lte(*req.TimeBefore))
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = new(StatisticResourceUsageResp)
|
var data = new(StatisticResourceUsageResp)
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"platform/web/auth"
|
"platform/web/auth"
|
||||||
"platform/web/core"
|
"platform/web/core"
|
||||||
trade2 "platform/web/domains/trade"
|
|
||||||
g "platform/web/globals"
|
g "platform/web/globals"
|
||||||
|
m "platform/web/models"
|
||||||
s "platform/web/services"
|
s "platform/web/services"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
type TradeCreateReq struct {
|
type TradeCreateReq struct {
|
||||||
s.CreateTradeData
|
s.CreateTradeData
|
||||||
Type trade2.Type `json:"type" validate:"required"`
|
Type m.TradeType `json:"type" validate:"required"`
|
||||||
Resource *s.CreateResourceData `json:"resource,omitempty"`
|
Resource *s.CreateResourceData `json:"resource,omitempty"`
|
||||||
Recharge *s.RechargeProductInfo `json:"recharge,omitempty"`
|
Recharge *s.RechargeProductInfo `json:"recharge,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -38,12 +38,12 @@ func TradeCreate(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case trade2.TypePurchase:
|
case m.TradeTypePurchase:
|
||||||
if req.Resource == nil {
|
if req.Resource == nil {
|
||||||
return core.NewBizErr("购买信息不能为空")
|
return core.NewBizErr("购买信息不能为空")
|
||||||
}
|
}
|
||||||
req.Product = req.Resource
|
req.Product = req.Resource
|
||||||
case trade2.TypeRecharge:
|
case m.TradeTypeRecharge:
|
||||||
if req.Recharge == nil {
|
if req.Recharge == nil {
|
||||||
return core.NewBizErr("充值信息不能为空")
|
return core.NewBizErr("充值信息不能为空")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ type VerifierReq struct {
|
|||||||
|
|
||||||
func SmsCode(c *fiber.Ctx) error {
|
func SmsCode(c *fiber.Ctx) error {
|
||||||
|
|
||||||
_, err := auth.GetAuthCtx(c).PermitInternalClient()
|
_, err := auth.GetAuthCtx(c).PermitOfficialClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"platform/pkg/env"
|
"platform/pkg/env"
|
||||||
|
"platform/pkg/u"
|
||||||
"platform/web/auth"
|
"platform/web/auth"
|
||||||
"platform/web/core"
|
"platform/web/core"
|
||||||
g "platform/web/globals"
|
g "platform/web/globals"
|
||||||
|
"platform/web/globals/orm"
|
||||||
m "platform/web/models"
|
m "platform/web/models"
|
||||||
q "platform/web/queries"
|
q "platform/web/queries"
|
||||||
"time"
|
"time"
|
||||||
@@ -89,7 +90,7 @@ func CreateWhitelist(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = secureAddr(req.Host)
|
ip, err := secureAddr(req.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -97,7 +98,7 @@ func CreateWhitelist(c *fiber.Ctx) error {
|
|||||||
// 创建白名单
|
// 创建白名单
|
||||||
err = q.Whitelist.Create(&m.Whitelist{
|
err = q.Whitelist.Create(&m.Whitelist{
|
||||||
UserID: authCtx.User.ID,
|
UserID: authCtx.User.ID,
|
||||||
Host: req.Host,
|
IP: u.Z(ip),
|
||||||
Remark: &req.Remark,
|
Remark: &req.Remark,
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
@@ -125,17 +126,21 @@ func UpdateWhitelist(c *fiber.Ctx) error {
|
|||||||
return fiber.NewError(fiber.StatusBadRequest, "id is required")
|
return fiber.NewError(fiber.StatusBadRequest, "id is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ip, err := secureAddr(req.Host)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// 更新白名单
|
// 更新白名单
|
||||||
_, err = q.Whitelist.
|
_, err = q.Whitelist.
|
||||||
Where(
|
Where(
|
||||||
q.Whitelist.ID.Eq(req.ID),
|
q.Whitelist.ID.Eq(req.ID),
|
||||||
q.Whitelist.UserID.Eq(authCtx.User.ID),
|
q.Whitelist.UserID.Eq(authCtx.User.ID),
|
||||||
).
|
).
|
||||||
Updates(&m.Whitelist{
|
UpdateSimple(
|
||||||
ID: req.ID,
|
q.Whitelist.IP.Value(ip),
|
||||||
Host: req.Host,
|
q.Whitelist.Remark.Value(req.Remark),
|
||||||
Remark: &req.Remark,
|
)
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -186,13 +191,13 @@ func RemoveWhitelist(c *fiber.Ctx) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func secureAddr(str string) error {
|
func secureAddr(str string) (*orm.Inet, error) {
|
||||||
var addr = net.ParseIP(str)
|
ip, err := orm.ParseInet(str)
|
||||||
if addr == nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "IP 解析失败")
|
return nil, err
|
||||||
}
|
}
|
||||||
if env.RunMode == env.RunModeDev || addr.IsGlobalUnicast() {
|
if !ip.IsGlobalUnicast() && env.RunMode != env.RunModeDev {
|
||||||
return nil
|
return nil, fiber.NewError(fiber.StatusBadRequest, "IP 地址不可用")
|
||||||
}
|
}
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "IP 地址不可用")
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameAdmin = "admin"
|
|
||||||
|
|
||||||
// Admin mapped from table <admin>
|
|
||||||
type Admin struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:管理员ID" json:"id"` // 管理员ID
|
|
||||||
Username string `gorm:"column:username;type:character varying(255);not null;comment:用户名" json:"username"` // 用户名
|
|
||||||
Password string `gorm:"column:password;type:character varying(255);not null;comment:密码" json:"password"` // 密码
|
|
||||||
Name *string `gorm:"column:name;type:character varying(255);comment:真实姓名" json:"name"` // 真实姓名
|
|
||||||
Avatar *string `gorm:"column:avatar;type:character varying(255);comment:头像URL" json:"avatar"` // 头像URL
|
|
||||||
Phone *string `gorm:"column:phone;type:character varying(255);comment:手机号码" json:"phone"` // 手机号码
|
|
||||||
Email *string `gorm:"column:email;type:character varying(255);comment:邮箱" json:"email"` // 邮箱
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;default:1;comment:状态:0-禁用,1-正常" json:"status"` // 状态:0-禁用,1-正常
|
|
||||||
LastLogin *orm.LocalDateTime `gorm:"column:last_login;type:timestamp without time zone;comment:最后登录时间" json:"last_login"` // 最后登录时间
|
|
||||||
LastLoginHost *string `gorm:"column:last_login_host;type:character varying(45);comment:最后登录地址" json:"last_login_host"` // 最后登录地址
|
|
||||||
LastLoginAgent *string `gorm:"column:last_login_agent;type:character varying(255);comment:最后登录代理" json:"last_login_agent"` // 最后登录代理
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Admin's table name
|
|
||||||
func (*Admin) TableName() string {
|
|
||||||
return TableNameAdmin
|
|
||||||
}
|
|
||||||
31
web/models/admin.go
Normal file
31
web/models/admin.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"platform/web/core"
|
||||||
|
"platform/web/globals/orm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Admin 管理员表
|
||||||
|
type Admin struct {
|
||||||
|
core.Model
|
||||||
|
Username string `json:"username" gorm:"column:username"` // 用户名
|
||||||
|
Password string `json:"password" gorm:"column:password"` // 密码
|
||||||
|
Name *string `json:"name" gorm:"column:name"` // 真实姓名
|
||||||
|
Avatar *string `json:"avatar" gorm:"column:avatar"` // 头像URL
|
||||||
|
Phone *string `json:"phone" gorm:"column:phone"` // 手机号码
|
||||||
|
Email *string `json:"email" gorm:"column:email"` // 邮箱
|
||||||
|
Status AdminStatus `json:"status" gorm:"column:status"` // 状态:0-禁用,1-正常
|
||||||
|
LastLogin *time.Time `json:"last_login" gorm:"column:last_login"` // 最后登录时间
|
||||||
|
LastLoginIP *orm.Inet `json:"last_login_ip" gorm:"column:last_login_ip"` // 最后登录地址
|
||||||
|
LastLoginUA *string `json:"last_login_ua" gorm:"column:last_login_ua"` // 最后登录代理
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdminStatus 管理员状态枚举
|
||||||
|
type AdminStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AdminStatusDisabled AdminStatus = 0 // 禁用
|
||||||
|
AdminStatusEnabled AdminStatus = 1 // 正常
|
||||||
|
)
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameAdminRole = "admin_role"
|
|
||||||
|
|
||||||
// AdminRole mapped from table <admin_role>
|
|
||||||
type AdminRole struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:管理员角色ID" json:"id"` // 管理员角色ID
|
|
||||||
Name string `gorm:"column:name;type:character varying(255);not null;comment:角色名称" json:"name"` // 角色名称
|
|
||||||
Description *string `gorm:"column:description;type:character varying(255);comment:角色描述" json:"description"` // 角色描述
|
|
||||||
Active *bool `gorm:"column:active;type:boolean;default:true;comment:是否激活" json:"active"` // 是否激活
|
|
||||||
Sort *int32 `gorm:"column:sort;type:integer;comment:排序" json:"sort"` // 排序
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName AdminRole's table name
|
|
||||||
func (*AdminRole) TableName() string {
|
|
||||||
return TableNameAdminRole
|
|
||||||
}
|
|
||||||
14
web/models/admin_role.go
Normal file
14
web/models/admin_role.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AdminRole 管理员角色表
|
||||||
|
type AdminRole struct {
|
||||||
|
core.Model
|
||||||
|
Name string `json:"name" gorm:"column:name"` // 角色名称
|
||||||
|
Description *string `json:"description" gorm:"column:description"` // 角色描述
|
||||||
|
Active bool `json:"active" gorm:"column:active"` // 是否激活
|
||||||
|
Sort int32 `json:"sort" gorm:"column:sort"` // 排序
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameAdminRoleLink = "admin_role_link"
|
|
||||||
|
|
||||||
// AdminRoleLink mapped from table <admin_role_link>
|
|
||||||
type AdminRoleLink struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:关联ID" json:"id"` // 关联ID
|
|
||||||
AdminID int32 `gorm:"column:admin_id;type:integer;not null;comment:管理员ID" json:"admin_id"` // 管理员ID
|
|
||||||
RoleID int32 `gorm:"column:role_id;type:integer;not null;comment:角色ID" json:"role_id"` // 角色ID
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName AdminRoleLink's table name
|
|
||||||
func (*AdminRoleLink) TableName() string {
|
|
||||||
return TableNameAdminRoleLink
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameAdminRolePermissionLink = "admin_role_permission_link"
|
|
||||||
|
|
||||||
// AdminRolePermissionLink mapped from table <admin_role_permission_link>
|
|
||||||
type AdminRolePermissionLink struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:关联ID" json:"id"` // 关联ID
|
|
||||||
RoleID int32 `gorm:"column:role_id;type:integer;not null;comment:角色ID" json:"role_id"` // 角色ID
|
|
||||||
PermissionID int32 `gorm:"column:permission_id;type:integer;not null;comment:权限ID" json:"permission_id"` // 权限ID
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName AdminRolePermissionLink's table name
|
|
||||||
func (*AdminRolePermissionLink) TableName() string {
|
|
||||||
return TableNameAdminRolePermissionLink
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameAnnouncement = "announcement"
|
|
||||||
|
|
||||||
// Announcement mapped from table <announcement>
|
|
||||||
type Announcement struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:公告ID" json:"id"` // 公告ID
|
|
||||||
Title string `gorm:"column:title;type:character varying(255);not null;comment:公告标题" json:"title"` // 公告标题
|
|
||||||
Content *string `gorm:"column:content;type:text;comment:公告内容" json:"content"` // 公告内容
|
|
||||||
Type int32 `gorm:"column:type;type:integer;not null;default:1;comment:公告类型:1-普通公告" json:"type"` // 公告类型:1-普通公告
|
|
||||||
Pin bool `gorm:"column:pin;type:boolean;not null;comment:是否置顶" json:"pin"` // 是否置顶
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;default:1;comment:公告状态:0-禁用,1-正常" json:"status"` // 公告状态:0-禁用,1-正常
|
|
||||||
Sort int32 `gorm:"column:sort;type:integer;not null;comment:公告排序" json:"sort"` // 公告排序
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Announcement's table name
|
|
||||||
func (*Announcement) TableName() string {
|
|
||||||
return TableNameAnnouncement
|
|
||||||
}
|
|
||||||
31
web/models/announcement.go
Normal file
31
web/models/announcement.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Announcement 公告表
|
||||||
|
type Announcement struct {
|
||||||
|
core.Model
|
||||||
|
Title string `json:"title" gorm:"column:title"` // 公告标题
|
||||||
|
Content *string `json:"content" gorm:"column:content"` // 公告内容
|
||||||
|
Type AnnouncementType `json:"type" gorm:"column:type"` // 公告类型:1-普通公告
|
||||||
|
Pin bool `json:"pin" gorm:"column:pin"` // 是否置顶
|
||||||
|
Status AnnouncementStatus `json:"status" gorm:"column:status"` // 公告状态:0-禁用,1-正常
|
||||||
|
Sort int32 `json:"sort" gorm:"column:sort"` // 公告排序
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnnouncementType 公告类型枚举
|
||||||
|
type AnnouncementType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AnnouncementTypeNormal AnnouncementType = 1 // 普通公告
|
||||||
|
)
|
||||||
|
|
||||||
|
// AnnouncementStatus 公告状态枚举
|
||||||
|
type AnnouncementStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AnnouncementStatusDisabled AnnouncementStatus = 0 // 禁用
|
||||||
|
AnnouncementStatusEnabled AnnouncementStatus = 1 // 正常
|
||||||
|
)
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"github.com/shopspring/decimal"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameBill = "bill"
|
|
||||||
|
|
||||||
// Bill mapped from table <bill>
|
|
||||||
type Bill struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:账单ID" json:"id"` // 账单ID
|
|
||||||
UserID int32 `gorm:"column:user_id;type:integer;not null;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
TradeID *int32 `gorm:"column:trade_id;type:integer;comment:订单ID" json:"trade_id"` // 订单ID
|
|
||||||
ResourceID *int32 `gorm:"column:resource_id;type:integer;comment:套餐ID" json:"resource_id"` // 套餐ID
|
|
||||||
RefundID *int32 `gorm:"column:refund_id;type:integer;comment:退款ID" json:"refund_id"` // 退款ID
|
|
||||||
BillNo string `gorm:"column:bill_no;type:character varying(255);not null;comment:易读账单号" json:"bill_no"` // 易读账单号
|
|
||||||
Info *string `gorm:"column:info;type:character varying(255);comment:产品可读信息" json:"info"` // 产品可读信息
|
|
||||||
Type int32 `gorm:"column:type;type:integer;not null;comment:账单类型:1-消费,2-退款,3-充值" json:"type"` // 账单类型:1-消费,2-退款,3-充值
|
|
||||||
Amount decimal.Decimal `gorm:"column:amount;type:numeric(12,2);not null;comment:账单金额" json:"amount"` // 账单金额
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
Trade *Trade `gorm:"foreignKey:TradeID" json:"trade"`
|
|
||||||
Refund *Refund `gorm:"foreignKey:RefundID" json:"refund"`
|
|
||||||
Resource *Resource `gorm:"foreignKey:ResourceID" json:"resource"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Bill's table name
|
|
||||||
func (*Bill) TableName() string {
|
|
||||||
return TableNameBill
|
|
||||||
}
|
|
||||||
34
web/models/bill.go
Normal file
34
web/models/bill.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bill 账单表
|
||||||
|
type Bill struct {
|
||||||
|
core.Model
|
||||||
|
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
TradeID *int32 `json:"trade_id" gorm:"column:trade_id"` // 订单ID
|
||||||
|
ResourceID *int32 `json:"resource_id" gorm:"column:resource_id"` // 套餐ID
|
||||||
|
RefundID *int32 `json:"refund_id" gorm:"column:refund_id"` // 退款ID
|
||||||
|
BillNo string `json:"bill_no" gorm:"column:bill_no"` // 易读账单号
|
||||||
|
Info *string `json:"info" gorm:"column:info"` // 产品可读信息
|
||||||
|
Type BillType `json:"type" gorm:"column:type"` // 账单类型:1-消费,2-退款,3-充值
|
||||||
|
Amount decimal.Decimal `json:"amount" gorm:"column:amount"` // 账单金额
|
||||||
|
|
||||||
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
||||||
|
Trade *Trade `json:"trade" gorm:"foreignKey:TradeID"`
|
||||||
|
Resource *Resource `json:"resource" gorm:"foreignKey:ResourceID"`
|
||||||
|
Refund *Refund `json:"refund" gorm:"foreignKey:RefundID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BillType 账单类型枚举
|
||||||
|
type BillType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
BillTypeConsume BillType = 1 // 消费
|
||||||
|
BillTypeRefund BillType = 2 // 退款
|
||||||
|
BillTypeRecharge BillType = 3 // 充值
|
||||||
|
)
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameChannel = "channel"
|
|
||||||
|
|
||||||
// Channel mapped from table <channel>
|
|
||||||
type Channel struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:通道ID" json:"id"` // 通道ID
|
|
||||||
UserID int32 `gorm:"column:user_id;type:integer;not null;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
ProxyID int32 `gorm:"column:proxy_id;type:integer;not null;comment:代理ID" json:"proxy_id"` // 代理ID
|
|
||||||
EdgeID *int32 `gorm:"column:edge_id;type:integer;comment:节点ID" json:"edge_id"` // 节点ID
|
|
||||||
ResourceID int32 `gorm:"column:resource_id;type:integer;not null;comment:套餐ID" json:"resource_id"` // 套餐ID
|
|
||||||
ProxyHost string `gorm:"column:proxy_host;type:character varying(255);not null;comment:代理地址" json:"proxy_host"` // 代理地址
|
|
||||||
ProxyPort int32 `gorm:"column:proxy_port;type:integer;not null;comment:转发端口" json:"proxy_port"` // 转发端口
|
|
||||||
EdgeHost *string `gorm:"column:edge_host;type:character varying(255);comment:节点地址" json:"edge_host"` // 节点地址
|
|
||||||
Protocol *int32 `gorm:"column:protocol;type:integer;comment:协议类型:1-http,2-https,3-socks5" json:"protocol"` // 协议类型:1-http,2-https,3-socks5
|
|
||||||
AuthIP bool `gorm:"column:auth_ip;type:boolean;not null;comment:IP认证" json:"auth_ip"` // IP认证
|
|
||||||
Whitelists *string `gorm:"column:whitelists;type:text;comment:IP白名单,逗号分隔" json:"whitelists"` // IP白名单,逗号分隔
|
|
||||||
AuthPass bool `gorm:"column:auth_pass;type:boolean;not null;comment:密码认证" json:"auth_pass"` // 密码认证
|
|
||||||
Username *string `gorm:"column:username;type:character varying(255);comment:用户名" json:"username"` // 用户名
|
|
||||||
Password *string `gorm:"column:password;type:character varying(255);comment:密码" json:"password"` // 密码
|
|
||||||
Expiration orm.LocalDateTime `gorm:"column:expiration;type:timestamp without time zone;not null;comment:过期时间" json:"expiration"` // 过期时间
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Channel's table name
|
|
||||||
func (*Channel) TableName() string {
|
|
||||||
return TableNameChannel
|
|
||||||
}
|
|
||||||
31
web/models/channel.go
Normal file
31
web/models/channel.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
"platform/web/globals/orm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Channel 通道表
|
||||||
|
type Channel struct {
|
||||||
|
core.Model
|
||||||
|
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
ResourceID int32 `json:"resource_id" gorm:"column:resource_id"` // 套餐ID
|
||||||
|
ProxyID int32 `json:"proxy_id" gorm:"column:proxy_id"` // 代理ID
|
||||||
|
BatchNo string `json:"batch_no" gorm:"column:batch_no"` // 批次编号
|
||||||
|
Port uint16 `json:"port" gorm:"column:port"` // 代理端口
|
||||||
|
EdgeID *int32 `json:"edge_id" gorm:"column:edge_id"` // 节点ID(手动配置)
|
||||||
|
FilterISP *EdgeISP `json:"filter_isp" gorm:"column:filter_isp"` // 运营商过滤(自动配置):参考 edge.isp
|
||||||
|
FilterProv *string `json:"filter_prov" gorm:"column:filter_prov"` // 省份过滤(自动配置)
|
||||||
|
FilterCity *string `json:"filter_city" gorm:"column:filter_city"` // 城市过滤(自动配置)
|
||||||
|
IP *orm.Inet `json:"ip" gorm:"column:ip"` // 节点地址
|
||||||
|
Whitelists *orm.Slice[string] `json:"whitelists" gorm:"column:whitelists"` // IP白名单,逗号分隔
|
||||||
|
Username *string `json:"username" gorm:"column:username"` // 用户名
|
||||||
|
Password *string `json:"password" gorm:"column:password"` // 密码
|
||||||
|
ExpiredAt time.Time `json:"expired_at" gorm:"column:expired_at"` // 过期时间
|
||||||
|
|
||||||
|
User User `json:"user" gorm:"foreignKey:UserID"`
|
||||||
|
Resource Resource `json:"resource" gorm:"foreignKey:ResourceID"`
|
||||||
|
Proxy Proxy `json:"proxy" gorm:"foreignKey:ProxyID"`
|
||||||
|
Edge *Edge `json:"edge" gorm:"foreignKey:EdgeID"`
|
||||||
|
}
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameClient = "client"
|
|
||||||
|
|
||||||
// Client mapped from table <client>
|
|
||||||
type Client struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:客户端ID" json:"id"` // 客户端ID
|
|
||||||
ClientID string `gorm:"column:client_id;type:character varying(255);not null;comment:OAuth2客户端标识符" json:"client_id"` // OAuth2客户端标识符
|
|
||||||
ClientSecret string `gorm:"column:client_secret;type:character varying(255);not null;comment:OAuth2客户端密钥" json:"client_secret"` // OAuth2客户端密钥
|
|
||||||
RedirectURI *string `gorm:"column:redirect_uri;type:character varying(255);comment:OAuth2 重定向URI" json:"redirect_uri"` // OAuth2 重定向URI
|
|
||||||
Spec int32 `gorm:"column:spec;type:integer;not null;comment:安全规范:1-native,2-browser,3-web,4-api" json:"spec"` // 安全规范:1-native,2-browser,3-web,4-api
|
|
||||||
Name string `gorm:"column:name;type:character varying(255);not null;comment:名称" json:"name"` // 名称
|
|
||||||
Icon *string `gorm:"column:icon;type:character varying(255);comment:图标URL" json:"icon"` // 图标URL
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;default:1;comment:状态:0-禁用,1-正常" json:"status"` // 状态:0-禁用,1-正常
|
|
||||||
Type int32 `gorm:"column:type;type:integer;not null;comment:类型:0-普通,1-官方" json:"type"` // 类型:0-普通,1-官方
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Client's table name
|
|
||||||
func (*Client) TableName() string {
|
|
||||||
return TableNameClient
|
|
||||||
}
|
|
||||||
44
web/models/client.go
Normal file
44
web/models/client.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client 客户端表
|
||||||
|
type Client struct {
|
||||||
|
core.Model
|
||||||
|
ClientID string `json:"client_id" gorm:"column:client_id"` // OAuth2客户端标识符
|
||||||
|
ClientSecret string `json:"client_secret" gorm:"column:client_secret"` // OAuth2客户端密钥
|
||||||
|
RedirectURI *string `json:"redirect_uri" gorm:"column:redirect_uri"` // OAuth2 重定向URI
|
||||||
|
Spec ClientSpec `json:"spec" gorm:"column:spec"` // 安全规范:1-native,2-browser,3-web,4-api
|
||||||
|
Name string `json:"name" gorm:"column:name"` // 名称
|
||||||
|
Icon *string `json:"icon" gorm:"column:icon"` // 图标URL
|
||||||
|
Status ClientStatus `json:"status" gorm:"column:status"` // 状态:0-禁用,1-正常
|
||||||
|
Type ClientType `json:"type" gorm:"column:type"` // 类型:0-普通,1-官方
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientSpec 客户端安全规范枚举
|
||||||
|
type ClientSpec int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClientSpecNative ClientSpec = 1 // native
|
||||||
|
ClientSpecBrowser ClientSpec = 2 // browser
|
||||||
|
ClientSpecWeb ClientSpec = 3 // web
|
||||||
|
ClientSpecAPI ClientSpec = 4 // api
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientStatus 客户端状态枚举
|
||||||
|
type ClientStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClientStatusDisabled ClientStatus = 0 // 禁用
|
||||||
|
ClientStatusEnabled ClientStatus = 1 // 正常
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientType 客户端类型枚举
|
||||||
|
type ClientType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClientTypeNormal ClientType = 0 // 普通
|
||||||
|
ClientTypeOfficial ClientType = 1 // 官方
|
||||||
|
)
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameClientPermissionLink = "client_permission_link"
|
|
||||||
|
|
||||||
// ClientPermissionLink mapped from table <client_permission_link>
|
|
||||||
type ClientPermissionLink struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:关联ID" json:"id"` // 关联ID
|
|
||||||
ClientID int32 `gorm:"column:client_id;type:integer;not null;comment:客户端ID" json:"client_id"` // 客户端ID
|
|
||||||
PermissionID int32 `gorm:"column:permission_id;type:integer;not null;comment:权限ID" json:"permission_id"` // 权限ID
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName ClientPermissionLink's table name
|
|
||||||
func (*ClientPermissionLink) TableName() string {
|
|
||||||
return TableNameClientPermissionLink
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"github.com/shopspring/decimal"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameCoupon = "coupon"
|
|
||||||
|
|
||||||
// Coupon mapped from table <coupon>
|
|
||||||
type Coupon struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:优惠券ID" json:"id"` // 优惠券ID
|
|
||||||
UserID *int32 `gorm:"column:user_id;type:integer;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
Code string `gorm:"column:code;type:character varying(255);not null;comment:优惠券代码" json:"code"` // 优惠券代码
|
|
||||||
Remark *string `gorm:"column:remark;type:character varying(255);comment:优惠券备注" json:"remark"` // 优惠券备注
|
|
||||||
Amount decimal.Decimal `gorm:"column:amount;type:numeric(12,2);not null;comment:优惠券金额" json:"amount"` // 优惠券金额
|
|
||||||
MinAmount decimal.Decimal `gorm:"column:min_amount;type:numeric(12,2);not null;comment:最低消费金额" json:"min_amount"` // 最低消费金额
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;comment:优惠券状态:0-未使用,1-已使用,2-已过期" json:"status"` // 优惠券状态:0-未使用,1-已使用,2-已过期
|
|
||||||
ExpireAt *orm.LocalDateTime `gorm:"column:expire_at;type:timestamp without time zone;comment:过期时间" json:"expire_at"` // 过期时间
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Coupon's table name
|
|
||||||
func (*Coupon) TableName() string {
|
|
||||||
return TableNameCoupon
|
|
||||||
}
|
|
||||||
29
web/models/coupon.go
Normal file
29
web/models/coupon.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Coupon 优惠券表
|
||||||
|
type Coupon struct {
|
||||||
|
core.Model
|
||||||
|
UserID *int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
Code string `json:"code" gorm:"column:code"` // 优惠券代码
|
||||||
|
Remark *string `json:"remark" gorm:"column:remark"` // 优惠券备注
|
||||||
|
Amount decimal.Decimal `json:"amount" gorm:"column:amount"` // 优惠券金额
|
||||||
|
MinAmount decimal.Decimal `json:"min_amount" gorm:"column:min_amount"` // 最低消费金额
|
||||||
|
Status CouponStatus `json:"status" gorm:"column:status"` // 优惠券状态:0-未使用,1-已使用,2-已过期
|
||||||
|
ExpireAt *time.Time `json:"expire_at" gorm:"column:expire_at"` // 过期时间
|
||||||
|
}
|
||||||
|
|
||||||
|
// CouponStatus 优惠券状态枚举
|
||||||
|
type CouponStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
CouponStatusUnused CouponStatus = 0 // 未使用
|
||||||
|
CouponStatusUsed CouponStatus = 1 // 已使用
|
||||||
|
CouponStatusExpired CouponStatus = 2 // 已过期
|
||||||
|
)
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameEdge = "edge"
|
|
||||||
|
|
||||||
// Edge mapped from table <edge>
|
|
||||||
type Edge struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:节点ID" json:"id"` // 节点ID
|
|
||||||
ProxyID *int32 `gorm:"column:proxy_id;type:integer;comment:代理ID" json:"proxy_id"` // 代理ID
|
|
||||||
Type int32 `gorm:"column:type;type:integer;not null;comment:节点类型:1-自建" json:"type"` // 节点类型:1-自建
|
|
||||||
Version int32 `gorm:"column:version;type:integer;not null;comment:节点版本" json:"version"` // 节点版本
|
|
||||||
Name string `gorm:"column:name;type:character varying(255);not null;comment:节点名称" json:"name"` // 节点名称
|
|
||||||
Host string `gorm:"column:host;type:character varying(255);not null;comment:节点地址" json:"host"` // 节点地址
|
|
||||||
Isp int32 `gorm:"column:isp;type:integer;not null;comment:运营商:0-未知,1-电信,2-联通,3-移动" json:"isp"` // 运营商:0-未知,1-电信,2-联通,3-移动
|
|
||||||
Prov string `gorm:"column:prov;type:character varying(255);not null;comment:省份" json:"prov"` // 省份
|
|
||||||
City string `gorm:"column:city;type:character varying(255);not null;comment:城市" json:"city"` // 城市
|
|
||||||
ProxyPort *int32 `gorm:"column:proxy_port;type:integer;comment:代理端口" json:"proxy_port"` // 代理端口
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;comment:节点状态:0-离线,1-正常" json:"status"` // 节点状态:0-离线,1-正常
|
|
||||||
Rtt *int32 `gorm:"column:rtt;type:integer;comment:最近平均延迟" json:"rtt"` // 最近平均延迟
|
|
||||||
Loss *int32 `gorm:"column:loss;type:integer;comment:最近丢包率" json:"loss"` // 最近丢包率
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Edge's table name
|
|
||||||
func (*Edge) TableName() string {
|
|
||||||
return TableNameEdge
|
|
||||||
}
|
|
||||||
65
web/models/edge.go
Normal file
65
web/models/edge.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
"platform/web/globals/orm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Edge 节点表
|
||||||
|
type Edge struct {
|
||||||
|
core.Model
|
||||||
|
Type EdgeType `json:"type" gorm:"column:type"` // 节点类型:1-自建
|
||||||
|
Version int32 `json:"version" gorm:"column:version"` // 节点版本
|
||||||
|
Mac string `json:"mac" gorm:"column:mac"` // 节点 mac 地址
|
||||||
|
IP orm.Inet `json:"ip" gorm:"column:ip;not null"` // 节点地址
|
||||||
|
ISP EdgeISP `json:"isp" gorm:"column:isp"` // 运营商:0-未知,1-电信,2-联通,3-移动
|
||||||
|
Prov string `json:"prov" gorm:"column:prov"` // 省份
|
||||||
|
City string `json:"city" gorm:"column:city"` // 城市
|
||||||
|
Status EdgeStatus `json:"status" gorm:"column:status"` // 节点状态:0-离线,1-正常
|
||||||
|
RTT int32 `json:"rtt" gorm:"column:rtt"` // 最近平均延迟
|
||||||
|
Loss int32 `json:"loss" gorm:"column:loss"` // 最近丢包率
|
||||||
|
}
|
||||||
|
|
||||||
|
// EdgeType 节点类型枚举
|
||||||
|
type EdgeType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
EdgeTypeSelfBuilt EdgeType = 1 // 自建
|
||||||
|
)
|
||||||
|
|
||||||
|
// EdgeStatus 节点状态枚举
|
||||||
|
type EdgeStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
EdgeStatusOffline EdgeStatus = 0 // 离线
|
||||||
|
EdgeStatusNormal EdgeStatus = 1 // 正常
|
||||||
|
)
|
||||||
|
|
||||||
|
// EdgeISP 运营商枚举
|
||||||
|
type EdgeISP int
|
||||||
|
|
||||||
|
const (
|
||||||
|
EdgeISPTelecom EdgeISP = 1 // 电信
|
||||||
|
EdgeISPUnicom EdgeISP = 2 // 联通
|
||||||
|
EdgeISPMobile EdgeISP = 3 // 移动
|
||||||
|
)
|
||||||
|
|
||||||
|
func (isp *EdgeISP) String() string {
|
||||||
|
if isp == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch *isp {
|
||||||
|
case EdgeISPTelecom:
|
||||||
|
return "电信"
|
||||||
|
case EdgeISPUnicom:
|
||||||
|
return "联通"
|
||||||
|
case EdgeISPMobile:
|
||||||
|
return "移动"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToEdgeISP(i int) EdgeISP {
|
||||||
|
return EdgeISP(i)
|
||||||
|
}
|
||||||
8
web/models/link_admin_role.go
Normal file
8
web/models/link_admin_role.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// LinkAdminRole 管理员角色关联表
|
||||||
|
type LinkAdminRole struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id"` // 关联ID
|
||||||
|
AdminID int32 `json:"admin_id" gorm:"column:admin_id"` // 管理员ID
|
||||||
|
RoleID int32 `json:"role_id" gorm:"column:role_id"` // 角色ID
|
||||||
|
}
|
||||||
8
web/models/link_admin_role_permission.go
Normal file
8
web/models/link_admin_role_permission.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// LinkAdminRolePermission 管理员角色权限关联表
|
||||||
|
type LinkAdminRolePermission struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id"` // 关联ID
|
||||||
|
RoleID int32 `json:"role_id" gorm:"column:role_id"` // 角色ID
|
||||||
|
PermissionID int32 `json:"permission_id" gorm:"column:permission_id"` // 权限ID
|
||||||
|
}
|
||||||
8
web/models/link_client_permission.go
Normal file
8
web/models/link_client_permission.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// LinkClientPermission 客户端权限关联表
|
||||||
|
type LinkClientPermission struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id"` // 关联ID
|
||||||
|
ClientID int32 `json:"client_id" gorm:"column:client_id"` // 客户端ID
|
||||||
|
PermissionID int32 `json:"permission_id" gorm:"column:permission_id"` // 权限ID
|
||||||
|
}
|
||||||
8
web/models/link_user_role.go
Normal file
8
web/models/link_user_role.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// LinkUserRole 用户角色关联表
|
||||||
|
type LinkUserRole struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id"` // 关联ID
|
||||||
|
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
RoleID int32 `json:"role_id" gorm:"column:role_id"` // 角色ID
|
||||||
|
}
|
||||||
8
web/models/link_user_role_permission.go
Normal file
8
web/models/link_user_role_permission.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// LinkUserRolePermission 用户角色权限关联表
|
||||||
|
type LinkUserRolePermission struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id"` // 关联ID
|
||||||
|
RoleID int32 `json:"role_id" gorm:"column:role_id"` // 角色ID
|
||||||
|
PermissionID int32 `json:"permission_id" gorm:"column:permission_id"` // 权限ID
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import "platform/web/globals/orm"
|
|
||||||
|
|
||||||
const TableNameLogsLogin = "logs_login"
|
|
||||||
|
|
||||||
// LogsLogin mapped from table <logs_login>
|
|
||||||
type LogsLogin struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:登录日志ID" json:"id"` // 登录日志ID
|
|
||||||
IP string `gorm:"column:ip;type:character varying(45);not null;comment:IP地址" json:"ip"` // IP地址
|
|
||||||
UA string `gorm:"column:ua;type:character varying(255);not null;comment:用户代理" json:"ua"` // 用户代理
|
|
||||||
GrantType string `gorm:"column:grant_type;type:character varying(255);not null;comment:授权类型:authorization_code-授权码模式,client_credentials-客户端凭证模式,refresh_token-刷新令牌模式,password-密码模式" json:"grant_type"` // 授权类型:authorization_code-授权码模式,client_credentials-客户端凭证模式,refresh_token-刷新令牌模式,password-密码模式
|
|
||||||
PasswordGrantType string `gorm:"column:password_grant_type;type:character varying(255);not null;comment:密码模式子授权类型:password-账号密码,phone_code-手机验证码,email_code-邮箱验证码" json:"password_grant_type"` // 密码模式子授权类型:password-账号密码,phone_code-手机验证码,email_code-邮箱验证码
|
|
||||||
Success bool `gorm:"column:success;type:boolean;not null;comment:登录是否成功" json:"success"` // 登录是否成功
|
|
||||||
UserID *int32 `gorm:"column:user_id;type:integer;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
Time orm.LocalDateTime `gorm:"column:time;type:timestamp without time zone;not null;comment:登录时间" json:"time"` // 登录时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName LogsLogin's table name
|
|
||||||
func (*LogsLogin) TableName() string {
|
|
||||||
return TableNameLogsLogin
|
|
||||||
}
|
|
||||||
39
web/models/logs_login.go
Normal file
39
web/models/logs_login.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/globals/orm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LogsLogin 登录日志表
|
||||||
|
type LogsLogin struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id"` // 登录日志ID
|
||||||
|
IP orm.Inet `json:"ip" gorm:"column:ip;not null"` // IP地址
|
||||||
|
UA string `json:"ua" gorm:"column:ua"` // 用户代理
|
||||||
|
GrantType GrantType `json:"grant_type" gorm:"column:grant_type"` // 授权类型
|
||||||
|
PasswordType PasswordType `json:"password_type" gorm:"column:password_type"` // 密码模式子授权类型
|
||||||
|
Success bool `json:"success" gorm:"column:success"` // 登录是否成功
|
||||||
|
UserID *int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
Time time.Time `json:"time" gorm:"column:time"` // 登录时间
|
||||||
|
|
||||||
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GrantType 授权类型枚举
|
||||||
|
type GrantType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
GrantTypeAuthorizationCode GrantType = "authorization_code" // 授权码模式
|
||||||
|
GrantTypeClientCredentials GrantType = "client_credentials" // 客户端凭证模式
|
||||||
|
GrantTypeRefreshToken GrantType = "refresh_token" // 刷新令牌模式
|
||||||
|
GrantTypePassword GrantType = "password" // 密码模式
|
||||||
|
)
|
||||||
|
|
||||||
|
// PasswordType 密码模式子授权类型枚举
|
||||||
|
type PasswordType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PasswordTypePassword PasswordType = "password" // 账号密码
|
||||||
|
PasswordTypePhoneCode PasswordType = "phone_code" // 手机验证码
|
||||||
|
PasswordTypeEmailCode PasswordType = "email_code" // 邮箱验证码
|
||||||
|
)
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import "platform/web/globals/orm"
|
|
||||||
|
|
||||||
const TableNameLogsRequest = "logs_request"
|
|
||||||
|
|
||||||
// LogsRequest mapped from table <logs_request>
|
|
||||||
type LogsRequest struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:访问日志ID" json:"id"` // 访问日志ID
|
|
||||||
IP string `gorm:"column:ip;type:character varying(45);not null;comment:IP地址" json:"ip"` // IP地址
|
|
||||||
UA string `gorm:"column:ua;type:character varying(255);not null;comment:用户代理" json:"ua"` // 用户代理
|
|
||||||
UserID *int32 `gorm:"column:user_id;type:integer;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
ClientID *int32 `gorm:"column:client_id;type:integer;comment:客户端ID" json:"client_id"` // 客户端ID
|
|
||||||
Method string `gorm:"column:method;type:character varying(10);not null;comment:请求方法" json:"method"` // 请求方法
|
|
||||||
Path string `gorm:"column:path;type:character varying(255);not null;comment:请求路径" json:"path"` // 请求路径
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;comment:响应状态码" json:"status"` // 响应状态码
|
|
||||||
Error *string `gorm:"column:error;type:text;comment:错误信息" json:"error"` // 错误信息
|
|
||||||
Time orm.LocalDateTime `gorm:"column:time;type:timestamp without time zone;not null;comment:请求时间" json:"time"` // 请求时间
|
|
||||||
Latency string `gorm:"column:latency;type:character varying(255);not null;comment:请求延迟" json:"latency"` // 请求延迟
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName LogsRequest's table name
|
|
||||||
func (*LogsRequest) TableName() string {
|
|
||||||
return TableNameLogsRequest
|
|
||||||
}
|
|
||||||
24
web/models/logs_request.go
Normal file
24
web/models/logs_request.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/globals/orm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LogsRequest 访问日志表
|
||||||
|
type LogsRequest struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id"` // 访问日志ID
|
||||||
|
IP orm.Inet `json:"ip" gorm:"column:ip;not null"` // IP地址
|
||||||
|
UA string `json:"ua" gorm:"column:ua"` // 用户代理
|
||||||
|
UserID *int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
ClientID *int32 `json:"client_id" gorm:"column:client_id"` // 客户端ID
|
||||||
|
Method string `json:"method" gorm:"column:method"` // 请求方法
|
||||||
|
Path string `json:"path" gorm:"column:path"` // 请求路径
|
||||||
|
Status int16 `json:"status" gorm:"column:status"` // 响应状态码
|
||||||
|
Error *string `json:"error" gorm:"column:error"` // 错误信息
|
||||||
|
Time time.Time `json:"time" gorm:"column:time"` // 请求时间
|
||||||
|
Latency string `json:"latency" gorm:"column:latency"` // 请求延迟
|
||||||
|
|
||||||
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
||||||
|
Client *Client `json:"client" gorm:"foreignKey:ClientID"`
|
||||||
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import "platform/web/globals/orm"
|
|
||||||
|
|
||||||
const TableNameLogsUserBandwidth = "logs_user_bandwidth"
|
|
||||||
|
|
||||||
// LogsUserBandwidth mapped from table <logs_user_bandwidth>
|
|
||||||
type LogsUserBandwidth struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:日志ID" json:"id"` // 日志ID
|
|
||||||
UserID int32 `gorm:"column:user_id;type:integer;not null;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
Bandwidth int32 `gorm:"column:bandwidth;type:integer;not null;comment:带宽使用量(KB)" json:"bandwidth"` // 带宽使用量(KB)
|
|
||||||
Time orm.LocalDateTime `gorm:"column:time;type:timestamp without time zone;not null;comment:记录时间" json:"time"` // 记录时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName LogsUserBandwidth's table name
|
|
||||||
func (*LogsUserBandwidth) TableName() string {
|
|
||||||
return TableNameLogsUserBandwidth
|
|
||||||
}
|
|
||||||
13
web/models/logs_user_bandwidth.go
Normal file
13
web/models/logs_user_bandwidth.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LogsUserBandwidth 用户带宽日志表
|
||||||
|
type LogsUserBandwidth struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id;not null"` // 日志ID
|
||||||
|
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
Bandwidth int32 `json:"bandwidth" gorm:"column:bandwidth"` // 带宽使用量(KB)
|
||||||
|
Time time.Time `json:"time" gorm:"column:time"` // 记录时间
|
||||||
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import "platform/web/globals/orm"
|
|
||||||
|
|
||||||
const TableNameLogsUserUsage = "logs_user_usage"
|
|
||||||
|
|
||||||
// LogsUserUsage mapped from table <logs_user_usage>
|
|
||||||
type LogsUserUsage struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:日志ID" json:"id"` // 日志ID
|
|
||||||
UserID int32 `gorm:"column:user_id;type:integer;not null;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
ResourceID int32 `gorm:"column:resource_id;type:integer;not null;comment:套餐ID" json:"resource_id"` // 套餐ID
|
|
||||||
Count_ int32 `gorm:"column:count;type:integer;not null;comment:数量" json:"count"` // 数量
|
|
||||||
Prov *string `gorm:"column:prov;type:character varying(255);comment:省份" json:"prov"` // 省份
|
|
||||||
City *string `gorm:"column:city;type:character varying(255);comment:城市" json:"city"` // 城市
|
|
||||||
Isp *string `gorm:"column:isp;type:character varying(255);comment:运营商" json:"isp"` // 运营商
|
|
||||||
IP string `gorm:"column:ip;type:character varying(45);not null;comment:IP地址" json:"ip"` // IP地址
|
|
||||||
Time orm.LocalDateTime `gorm:"column:time;type:timestamp without time zone;not null;comment:提取时间" json:"time"` // 提取时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName LogsUserUsage's table name
|
|
||||||
func (*LogsUserUsage) TableName() string {
|
|
||||||
return TableNameLogsUserUsage
|
|
||||||
}
|
|
||||||
19
web/models/logs_user_usage.go
Normal file
19
web/models/logs_user_usage.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/globals/orm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LogsUserUsage 用户使用日志表
|
||||||
|
type LogsUserUsage struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id"` // 日志ID
|
||||||
|
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
ResourceID int32 `json:"resource_id" gorm:"column:resource_id"` // 套餐ID
|
||||||
|
Count int32 `json:"count" gorm:"column:count"` // 数量
|
||||||
|
Prov *string `json:"prov" gorm:"column:prov"` // 省份
|
||||||
|
City *string `json:"city" gorm:"column:city"` // 城市
|
||||||
|
ISP *string `json:"isp" gorm:"column:isp"` // 运营商
|
||||||
|
IP orm.Inet `json:"ip" gorm:"column:ip"` // IP地址
|
||||||
|
Time time.Time `json:"time" gorm:"column:time"` // 提取时间
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNamePermission = "permission"
|
|
||||||
|
|
||||||
// Permission mapped from table <permission>
|
|
||||||
type Permission struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:权限ID" json:"id"` // 权限ID
|
|
||||||
ParentID *int32 `gorm:"column:parent_id;type:integer;comment:父权限ID" json:"parent_id"` // 父权限ID
|
|
||||||
Name string `gorm:"column:name;type:character varying(255);not null;comment:权限名称" json:"name"` // 权限名称
|
|
||||||
Description *string `gorm:"column:description;type:character varying(255);comment:权限描述" json:"description"` // 权限描述
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Permission's table name
|
|
||||||
func (*Permission) TableName() string {
|
|
||||||
return TableNamePermission
|
|
||||||
}
|
|
||||||
14
web/models/permission.go
Normal file
14
web/models/permission.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "platform/web/core"
|
||||||
|
|
||||||
|
// Permission 权限表
|
||||||
|
type Permission struct {
|
||||||
|
core.Model
|
||||||
|
ParentID *int32 `json:"parent_id" gorm:"column:parent_id"` // 父权限ID
|
||||||
|
Name string `json:"name" gorm:"column:name"` // 权限名称
|
||||||
|
Description *string `json:"description" gorm:"column:description"` // 权限描述
|
||||||
|
|
||||||
|
Parent *Permission `json:"parent" gorm:"foreignKey:ParentID"`
|
||||||
|
Children []*Permission `json:"children" gorm:"foreignKey:ParentID"`
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameProduct = "product"
|
|
||||||
|
|
||||||
// Product mapped from table <product>
|
|
||||||
type Product struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:产品ID" json:"id"` // 产品ID
|
|
||||||
Code string `gorm:"column:code;type:character varying(255);not null;comment:产品代码" json:"code"` // 产品代码
|
|
||||||
Name string `gorm:"column:name;type:character varying(255);not null;comment:产品名称" json:"name"` // 产品名称
|
|
||||||
Description *string `gorm:"column:description;type:character varying(255);comment:产品描述" json:"description"` // 产品描述
|
|
||||||
Sort int32 `gorm:"column:sort;type:integer;not null;comment:排序" json:"sort"` // 排序
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;default:1;comment:产品状态:0-禁用,1-正常" json:"status"` // 产品状态:0-禁用,1-正常
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Product's table name
|
|
||||||
func (*Product) TableName() string {
|
|
||||||
return TableNameProduct
|
|
||||||
}
|
|
||||||
23
web/models/product.go
Normal file
23
web/models/product.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Product 产品表
|
||||||
|
type Product struct {
|
||||||
|
core.Model
|
||||||
|
Code string `json:"code" gorm:"column:code"` // 产品代码
|
||||||
|
Name string `json:"name" gorm:"column:name"` // 产品名称
|
||||||
|
Description *string `json:"description" gorm:"column:description"` // 产品描述
|
||||||
|
Sort int32 `json:"sort" gorm:"column:sort"` // 排序
|
||||||
|
Status ProductStatus `json:"status" gorm:"column:status"` // 产品状态:0-禁用,1-正常
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductStatus 产品状态枚举
|
||||||
|
type ProductStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProductStatusDisabled ProductStatus = 0 // 禁用
|
||||||
|
ProductStatusEnabled ProductStatus = 1 // 正常
|
||||||
|
)
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameProxy = "proxy"
|
|
||||||
|
|
||||||
// Proxy mapped from table <proxy>
|
|
||||||
type Proxy struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:代理服务ID" json:"id"` // 代理服务ID
|
|
||||||
Version int32 `gorm:"column:version;type:integer;not null;comment:代理服务版本" json:"version"` // 代理服务版本
|
|
||||||
Name string `gorm:"column:name;type:character varying(255);not null;comment:代理服务名称" json:"name"` // 代理服务名称
|
|
||||||
Host string `gorm:"column:host;type:character varying(255);not null;comment:代理服务地址" json:"host"` // 代理服务地址
|
|
||||||
Secret *string `gorm:"column:secret;type:character varying(255);comment:代理服务密钥" json:"secret"` // 代理服务密钥
|
|
||||||
Type int32 `gorm:"column:type;type:integer;not null;comment:代理服务类型:1-三方,2-自有" json:"type"` // 代理服务类型:1-三方,2-自有
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;comment:代理服务状态:0-离线,1-在线" json:"status"` // 代理服务状态:0-离线,1-在线
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
Edges []Edge `gorm:"foreignKey:ProxyID;references:ID" json:"edges"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Proxy's table name
|
|
||||||
func (*Proxy) TableName() string {
|
|
||||||
return TableNameProxy
|
|
||||||
}
|
|
||||||
38
web/models/proxy.go
Normal file
38
web/models/proxy.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
"platform/web/globals/orm"
|
||||||
|
|
||||||
|
"gorm.io/datatypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Proxy 代理服务表
|
||||||
|
type Proxy struct {
|
||||||
|
core.Model
|
||||||
|
Version int32 `json:"version" gorm:"column:version"` // 代理服务版本
|
||||||
|
Mac string `json:"mac" gorm:"column:mac"` // 代理服务名称
|
||||||
|
IP orm.Inet `json:"ip" gorm:"column:ip;not null"` // 代理服务地址
|
||||||
|
Secret *string `json:"secret" gorm:"column:secret"` // 代理服务密钥
|
||||||
|
Type ProxyType `json:"type" gorm:"column:type"` // 代理服务类型:1-自有,2-白银
|
||||||
|
Status ProxyStatus `json:"status" gorm:"column:status"` // 代理服务状态:0-离线,1-在线
|
||||||
|
Meta *datatypes.JSONType[any] `json:"meta" gorm:"column:meta"` // 代理服务元信息
|
||||||
|
|
||||||
|
Channels []Channel `json:"channels" gorm:"foreignkey:ProxyID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProxyType 代理服务类型枚举
|
||||||
|
type ProxyType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProxyTypeSelfHosted ProxyType = 1 // 自有
|
||||||
|
ProxyTypeBaiYin ProxyType = 2 // 白银
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProxyStatus 代理服务状态枚举
|
||||||
|
type ProxyStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProxyStatusOffline ProxyStatus = 0 // 离线
|
||||||
|
ProxyStatusOnline ProxyStatus = 1 // 在线
|
||||||
|
)
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"github.com/shopspring/decimal"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameRefund = "refund"
|
|
||||||
|
|
||||||
// Refund mapped from table <refund>
|
|
||||||
type Refund struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:退款ID" json:"id"` // 退款ID
|
|
||||||
TradeID int32 `gorm:"column:trade_id;type:integer;not null;comment:订单ID" json:"trade_id"` // 订单ID
|
|
||||||
ProductID *int32 `gorm:"column:product_id;type:integer;comment:产品ID" json:"product_id"` // 产品ID
|
|
||||||
Amount decimal.Decimal `gorm:"column:amount;type:numeric(12,2);not null;comment:退款金额" json:"amount"` // 退款金额
|
|
||||||
Reason *string `gorm:"column:reason;type:character varying(255);comment:退款原因" json:"reason"` // 退款原因
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;comment:退款状态:0-待处理,1-已退款,2-已拒绝" json:"status"` // 退款状态:0-待处理,1-已退款,2-已拒绝
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Refund's table name
|
|
||||||
func (*Refund) TableName() string {
|
|
||||||
return TableNameRefund
|
|
||||||
}
|
|
||||||
26
web/models/refund.go
Normal file
26
web/models/refund.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Refund 退款记录表
|
||||||
|
type Refund struct {
|
||||||
|
core.Model
|
||||||
|
TradeID int32 `json:"trade_id" gorm:"column:trade_id"` // 订单ID
|
||||||
|
ProductID *int32 `json:"product_id" gorm:"column:product_id"` // 产品ID
|
||||||
|
Amount decimal.Decimal `json:"amount" gorm:"column:amount"` // 退款金额
|
||||||
|
Reason *string `json:"reason" gorm:"column:reason"` // 退款原因
|
||||||
|
Status RefundStatus `json:"status" gorm:"column:status"` // 退款状态:0-待处理,1-已退款,2-已拒绝
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefundStatus 退款状态枚举
|
||||||
|
type RefundStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
RefundStatusPending RefundStatus = 0 // 待处理
|
||||||
|
RefundStatusRefunded RefundStatus = 1 // 已退款
|
||||||
|
RefundStatusRejected RefundStatus = 2 // 已拒绝
|
||||||
|
)
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameResource = "resource"
|
|
||||||
|
|
||||||
// Resource mapped from table <resource>
|
|
||||||
type Resource struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:套餐ID" json:"id"` // 套餐ID
|
|
||||||
UserID int32 `gorm:"column:user_id;type:integer;not null;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
ResourceNo *string `gorm:"column:resource_no;type:character varying(255);comment:套餐编号" json:"resource_no"` // 套餐编号
|
|
||||||
Active bool `gorm:"column:active;type:boolean;not null;default:true;comment:套餐状态" json:"active"` // 套餐状态
|
|
||||||
Type int32 `gorm:"column:type;type:integer;not null;comment:套餐类型:1-短效动态,2-长效动态" json:"type"` // 套餐类型:1-短效动态,2-长效动态
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
Short *ResourceShort `gorm:"foreignKey:ResourceID;references:ID" json:"short"`
|
|
||||||
Long *ResourceLong `gorm:"foreignKey:ResourceID;references:ID" json:"long"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Resource's table name
|
|
||||||
func (*Resource) TableName() string {
|
|
||||||
return TableNameResource
|
|
||||||
}
|
|
||||||
34
web/models/resource.go
Normal file
34
web/models/resource.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource 套餐表
|
||||||
|
type Resource struct {
|
||||||
|
core.Model
|
||||||
|
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
ResourceNo *string `json:"resource_no" gorm:"column:resource_no"` // 套餐编号
|
||||||
|
Active bool `json:"active" gorm:"column:active"` // 套餐状态
|
||||||
|
Type ResourceType `json:"type" gorm:"column:type"` // 套餐类型:1-短效动态,2-长效动态
|
||||||
|
|
||||||
|
User User `json:"user" gorm:"foreignKey:UserID"`
|
||||||
|
Short *ResourceShort `json:"short" gorm:"foreignKey:ResourceID"`
|
||||||
|
Long *ResourceLong `json:"long" gorm:"foreignKey:ResourceID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceType 套餐类型枚举
|
||||||
|
type ResourceType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ResourceTypeShort ResourceType = 1 // 短效动态
|
||||||
|
ResourceTypeLong ResourceType = 2 // 长效动态
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResourceLongType 套餐计费模式枚举
|
||||||
|
type ResourceMode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ResourceModeTime ResourceMode = 1 // 包时
|
||||||
|
ResourceModeQuota ResourceMode = 2 // 包量
|
||||||
|
)
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import "platform/web/globals/orm"
|
|
||||||
|
|
||||||
const TableNameResourceLong = "resource_long"
|
|
||||||
|
|
||||||
// ResourceLong mapped from table <resource_long>
|
|
||||||
type ResourceLong struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:ID" json:"id"` // ID
|
|
||||||
ResourceID int32 `gorm:"column:resource_id;type:integer;not null;comment:套餐ID" json:"resource_id"` // 套餐ID
|
|
||||||
Type int32 `gorm:"column:type;type:integer;not null;comment:套餐类型:1-包时,2-包量" json:"type"` // 套餐类型:1-包时,2-包量
|
|
||||||
Live int32 `gorm:"column:live;type:integer;not null;comment:可用时长(天)" json:"live"` // 可用时长(天)
|
|
||||||
Expire *orm.LocalDateTime `gorm:"column:expire;type:timestamp without time zone;comment:过期时间" json:"expire"` // 过期时间
|
|
||||||
Quota *int32 `gorm:"column:quota;type:integer;comment:配额数量" json:"quota"` // 配额数量
|
|
||||||
Used int32 `gorm:"column:used;type:integer;not null;comment:已用数量" json:"used"` // 已用数量
|
|
||||||
DailyLimit int32 `gorm:"column:daily_limit;type:integer;not null;comment:每日限制" json:"daily_limit"` // 每日限制
|
|
||||||
DailyUsed int32 `gorm:"column:daily_used;type:integer;not null;comment:今日已用数量" json:"daily_used"` // 今日已用数量
|
|
||||||
DailyLast *orm.LocalDateTime `gorm:"column:daily_last;type:timestamp without time zone;comment:今日最后使用时间" json:"daily_last"` // 今日最后使用时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName ResourceLong's table name
|
|
||||||
func (*ResourceLong) TableName() string {
|
|
||||||
return TableNameResourceLong
|
|
||||||
}
|
|
||||||
19
web/models/resource_long.go
Normal file
19
web/models/resource_long.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResourceLong 长效动态套餐表
|
||||||
|
type ResourceLong struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id"` // ID
|
||||||
|
ResourceID int32 `json:"resource_id" gorm:"column:resource_id"` // 套餐ID
|
||||||
|
Type ResourceMode `json:"type" gorm:"column:type"` // 套餐类型:1-包时,2-包量
|
||||||
|
Live int32 `json:"live" gorm:"column:live"` // 可用时长(天)
|
||||||
|
Expire *time.Time `json:"expire" gorm:"column:expire"` // 过期时间
|
||||||
|
Quota *int32 `json:"quota" gorm:"column:quota"` // 配额数量
|
||||||
|
Used int32 `json:"used" gorm:"column:used"` // 已用数量
|
||||||
|
DailyLimit int32 `json:"daily_limit" gorm:"column:daily_limit"` // 每日限制
|
||||||
|
DailyUsed int32 `json:"daily_used" gorm:"column:daily_used"` // 今日已用数量
|
||||||
|
DailyLast *time.Time `json:"daily_last" gorm:"column:daily_last"` // 今日最后使用时间
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import "platform/web/globals/orm"
|
|
||||||
|
|
||||||
const TableNameResourceShort = "resource_short"
|
|
||||||
|
|
||||||
// ResourceShort mapped from table <resource_short>
|
|
||||||
type ResourceShort struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:ID" json:"id"` // ID
|
|
||||||
ResourceID int32 `gorm:"column:resource_id;type:integer;not null;comment:套餐ID" json:"resource_id"` // 套餐ID
|
|
||||||
Type int32 `gorm:"column:type;type:integer;not null;comment:套餐类型:1-包时,2-包量" json:"type"` // 套餐类型:1-包时,2-包量
|
|
||||||
Live int32 `gorm:"column:live;type:integer;not null;comment:可用时长(秒)" json:"live"` // 可用时长(秒)
|
|
||||||
Expire *orm.LocalDateTime `gorm:"column:expire;type:timestamp without time zone;comment:过期时间" json:"expire"` // 过期时间
|
|
||||||
Quota *int32 `gorm:"column:quota;type:integer;comment:配额数量" json:"quota"` // 配额数量
|
|
||||||
Used int32 `gorm:"column:used;type:integer;not null;comment:已用数量" json:"used"` // 已用数量
|
|
||||||
DailyLimit int32 `gorm:"column:daily_limit;type:integer;not null;comment:每日限制" json:"daily_limit"` // 每日限制
|
|
||||||
DailyUsed int32 `gorm:"column:daily_used;type:integer;not null;comment:今日已用数量" json:"daily_used"` // 今日已用数量
|
|
||||||
DailyLast *orm.LocalDateTime `gorm:"column:daily_last;type:timestamp without time zone;comment:今日最后使用时间" json:"daily_last"` // 今日最后使用时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName ResourceShort's table name
|
|
||||||
func (*ResourceShort) TableName() string {
|
|
||||||
return TableNameResourceShort
|
|
||||||
}
|
|
||||||
19
web/models/resource_short.go
Normal file
19
web/models/resource_short.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResourceShort 短效动态套餐表
|
||||||
|
type ResourceShort struct {
|
||||||
|
ID int32 `json:"id" gorm:"column:id"` // ID
|
||||||
|
ResourceID int32 `json:"resource_id" gorm:"column:resource_id"` // 套餐ID
|
||||||
|
Type ResourceMode `json:"type" gorm:"column:type"` // 套餐类型:1-包时,2-包量
|
||||||
|
Live int32 `json:"live" gorm:"column:live"` // 可用时长(秒)
|
||||||
|
Expire *time.Time `json:"expire" gorm:"column:expire"` // 过期时间
|
||||||
|
Quota *int32 `json:"quota" gorm:"column:quota"` // 配额数量
|
||||||
|
Used int32 `json:"used" gorm:"column:used"` // 已用数量
|
||||||
|
DailyLimit int32 `json:"daily_limit" gorm:"column:daily_limit"` // 每日限制
|
||||||
|
DailyUsed int32 `json:"daily_used" gorm:"column:daily_used"` // 今日已用数量
|
||||||
|
DailyLast *time.Time `json:"daily_last" gorm:"column:daily_last"` // 今日最后使用时间
|
||||||
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameSession = "session"
|
|
||||||
|
|
||||||
// Session mapped from table <session>
|
|
||||||
type Session struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:会话ID" json:"id"` // 会话ID
|
|
||||||
UserID *int32 `gorm:"column:user_id;type:integer;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
AdminID *int32 `gorm:"column:admin_id;type:integer;comment:管理员ID" json:"admin_id"` // 管理员ID
|
|
||||||
ClientID *int32 `gorm:"column:client_id;type:integer;comment:客户端ID" json:"client_id"` // 客户端ID
|
|
||||||
IP *string `gorm:"column:ip;type:character varying(45);comment:IP地址" json:"ip"` // IP地址
|
|
||||||
UA *string `gorm:"column:ua;type:character varying(255);comment:用户代理" json:"ua"` // 用户代理
|
|
||||||
AccessToken string `gorm:"column:access_token;type:character varying(255);not null;comment:访问令牌" json:"access_token"` // 访问令牌
|
|
||||||
AccessTokenExpires orm.LocalDateTime `gorm:"column:access_token_expires;type:timestamp without time zone;not null;comment:访问令牌过期时间" json:"access_token_expires"` // 访问令牌过期时间
|
|
||||||
RefreshToken *string `gorm:"column:refresh_token;type:character varying(255);comment:刷新令牌" json:"refresh_token"` // 刷新令牌
|
|
||||||
RefreshTokenExpires *orm.LocalDateTime `gorm:"column:refresh_token_expires;type:timestamp without time zone;comment:刷新令牌过期时间" json:"refresh_token_expires"` // 刷新令牌过期时间
|
|
||||||
Scopes_ *string `gorm:"column:scopes;type:character varying(255);comment:权限范围" json:"scopes"` // 权限范围
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
User *User `gorm:"foreignKey:UserID" json:"user"`
|
|
||||||
Admin *Admin `gorm:"foreignKey:UserID" json:"admin"`
|
|
||||||
Client *Client `gorm:"belongsTo:ID;foreignKey:ClientID" json:"client"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Session's table name
|
|
||||||
func (*Session) TableName() string {
|
|
||||||
return TableNameSession
|
|
||||||
}
|
|
||||||
26
web/models/session.go
Normal file
26
web/models/session.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
"platform/web/globals/orm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Session 会话表
|
||||||
|
type Session struct {
|
||||||
|
core.Model
|
||||||
|
UserID *int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
AdminID *int32 `json:"admin_id" gorm:"column:admin_id"` // 管理员ID
|
||||||
|
ClientID *int32 `json:"client_id" gorm:"column:client_id"` // 客户端ID
|
||||||
|
IP *orm.Inet `json:"ip" gorm:"column:ip"` // IP地址
|
||||||
|
UA *string `json:"ua" gorm:"column:ua"` // 用户代理
|
||||||
|
AccessToken string `json:"access_token" gorm:"column:access_token"` // 访问令牌
|
||||||
|
AccessTokenExpires time.Time `json:"access_token_expires" gorm:"column:access_token_expires"` // 访问令牌过期时间
|
||||||
|
RefreshToken *string `json:"refresh_token" gorm:"column:refresh_token"` // 刷新令牌
|
||||||
|
RefreshTokenExpires *time.Time `json:"refresh_token_expires" gorm:"column:refresh_token_expires"` // 刷新令牌过期时间
|
||||||
|
Scopes *string `json:"scopes" gorm:"column:scopes"` // 权限范围
|
||||||
|
|
||||||
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
||||||
|
Admin *Admin `json:"admin" gorm:"foreignKey:AdminID"`
|
||||||
|
Client *Client `json:"client" gorm:"foreignKey:ClientID;belongsTo:ID"`
|
||||||
|
}
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"github.com/shopspring/decimal"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameTrade = "trade"
|
|
||||||
|
|
||||||
// Trade mapped from table <trade>
|
|
||||||
type Trade struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:订单ID" json:"id"` // 订单ID
|
|
||||||
UserID int32 `gorm:"column:user_id;type:integer;not null;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
InnerNo string `gorm:"column:inner_no;type:character varying(255);not null;comment:内部订单号" json:"inner_no"` // 内部订单号
|
|
||||||
OuterNo *string `gorm:"column:outer_no;type:character varying(255);comment:外部订单号" json:"outer_no"` // 外部订单号
|
|
||||||
Type int32 `gorm:"column:type;type:integer;not null;comment:订单类型:1-购买产品,2-充值余额" json:"type"` // 订单类型:1-购买产品,2-充值余额
|
|
||||||
Subject string `gorm:"column:subject;type:character varying(255);not null;comment:订单主题" json:"subject"` // 订单主题
|
|
||||||
Remark *string `gorm:"column:remark;type:character varying(255);comment:订单备注" json:"remark"` // 订单备注
|
|
||||||
Amount decimal.Decimal `gorm:"column:amount;type:numeric(12,2);not null;comment:订单总金额" json:"amount"` // 订单总金额
|
|
||||||
Payment decimal.Decimal `gorm:"column:payment;type:numeric(12,2);not null;comment:实际支付金额" json:"payment"` // 实际支付金额
|
|
||||||
Method int32 `gorm:"column:method;type:integer;not null;comment:支付方式:1-支付宝,2-微信,3-商福通,4-商福通渠道支付宝,5-商福通渠道微信" json:"method"` // 支付方式:1-支付宝,2-微信,3-商福通,4-商福通渠道支付宝,5-商福通渠道微信
|
|
||||||
Platform int32 `gorm:"column:platform;type:integer;not null;comment:支付平台:1-电脑网站,2-手机网站" json:"platform"` // 支付平台:1-电脑网站,2-手机网站
|
|
||||||
Acquirer *int32 `gorm:"column:acquirer;type:integer;comment:收单机构:1-支付宝,2-微信,3-银联" json:"acquirer"` // 收单机构:1-支付宝,2-微信,3-银联
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;comment:订单状态:0-待支付,1-已支付,2-已取消" json:"status"` // 订单状态:0-待支付,1-已支付,2-已取消
|
|
||||||
Refunded bool `gorm:"column:refunded;type:boolean;not null" json:"refunded"`
|
|
||||||
PaymentURL *string `gorm:"column:payment_url;type:text;comment:支付链接" json:"payment_url"` // 支付链接
|
|
||||||
CompletedAt *orm.LocalDateTime `gorm:"column:completed_at;type:timestamp without time zone;comment:支付时间" json:"completed_at"` // 支付时间
|
|
||||||
CanceledAt *orm.LocalDateTime `gorm:"column:canceled_at;type:timestamp without time zone;comment:取消时间" json:"canceled_at"` // 取消时间
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Trade's table name
|
|
||||||
func (*Trade) TableName() string {
|
|
||||||
return TableNameTrade
|
|
||||||
}
|
|
||||||
74
web/models/trade.go
Normal file
74
web/models/trade.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Trade 订单表
|
||||||
|
type Trade struct {
|
||||||
|
core.Model
|
||||||
|
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
InnerNo string `json:"inner_no" gorm:"column:inner_no"` // 内部订单号
|
||||||
|
OuterNo *string `json:"outer_no" gorm:"column:outer_no"` // 外部订单号
|
||||||
|
Type TradeType `json:"type" gorm:"column:type"` // 订单类型:1-购买产品,2-充值余额
|
||||||
|
Subject string `json:"subject" gorm:"column:subject"` // 订单主题
|
||||||
|
Remark *string `json:"remark" gorm:"column:remark"` // 订单备注
|
||||||
|
Amount decimal.Decimal `json:"amount" gorm:"column:amount"` // 订单总金额
|
||||||
|
Payment decimal.Decimal `json:"payment" gorm:"column:payment"` // 实际支付金额
|
||||||
|
Method TradeMethod `json:"method" gorm:"column:method"` // 支付方式:1-支付宝,2-微信,3-商福通,4-商福通渠道支付宝,5-商福通渠道微信
|
||||||
|
Platform TradePlatform `json:"platform" gorm:"column:platform"` // 支付平台:1-电脑网站,2-手机网站
|
||||||
|
Acquirer *TradeAcquirer `json:"acquirer" gorm:"column:acquirer"` // 收单机构:1-支付宝,2-微信,3-银联
|
||||||
|
Status TradeStatus `json:"status" gorm:"column:status"` // 订单状态:0-待支付,1-已支付,2-已取消
|
||||||
|
Refunded bool `json:"refunded" gorm:"column:refunded"` // 是否已退款
|
||||||
|
PaymentURL *string `json:"payment_url" gorm:"column:payment_url"` // 支付链接
|
||||||
|
CompletedAt *time.Time `json:"completed_at" gorm:"column:completed_at"` // 支付时间
|
||||||
|
CanceledAt *time.Time `json:"canceled_at" gorm:"column:canceled_at"` // 取消时间
|
||||||
|
}
|
||||||
|
|
||||||
|
// TradeType 订单类型枚举
|
||||||
|
type TradeType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TradeTypePurchase TradeType = 1 // 购买产品
|
||||||
|
TradeTypeRecharge TradeType = 2 // 充值余额
|
||||||
|
)
|
||||||
|
|
||||||
|
// TradeMethod 支付方式枚举
|
||||||
|
type TradeMethod int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TradeMethodAlipay TradeMethod = 1 // 支付宝
|
||||||
|
TradeMethodWechat TradeMethod = 2 // 微信
|
||||||
|
TradeMethodSft TradeMethod = 3 // 商福通
|
||||||
|
TradeMethodSftAlipay TradeMethod = 4 // 商福通渠道支付宝
|
||||||
|
TradeMethodSftWechat TradeMethod = 5 // 商福通渠道微信
|
||||||
|
)
|
||||||
|
|
||||||
|
// TradePlatform 支付平台枚举
|
||||||
|
type TradePlatform int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TradePlatformPC TradePlatform = 1 // 电脑网站
|
||||||
|
TradePlatformMobile TradePlatform = 2 // 手机网站
|
||||||
|
)
|
||||||
|
|
||||||
|
// TradeAcquirer 收单机构枚举
|
||||||
|
type TradeAcquirer int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TradeAcquirerAlipay TradeAcquirer = 1 // 支付宝
|
||||||
|
TradeAcquirerWechat TradeAcquirer = 2 // 微信
|
||||||
|
TradeAcquirerUnionPay TradeAcquirer = 3 // 银联
|
||||||
|
)
|
||||||
|
|
||||||
|
// TradeStatus 订单状态枚举
|
||||||
|
type TradeStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TradeStatusPending TradeStatus = 0 // 待支付
|
||||||
|
TradeStatusSuccess TradeStatus = 1 // 已支付
|
||||||
|
TradeStatusCanceled TradeStatus = 2 // 已取消
|
||||||
|
)
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"github.com/shopspring/decimal"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameUser = "user"
|
|
||||||
|
|
||||||
// User mapped from table <user>
|
|
||||||
type User struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:用户ID" json:"id"` // 用户ID
|
|
||||||
AdminID *int32 `gorm:"column:admin_id;type:integer;comment:管理员ID" json:"admin_id"` // 管理员ID
|
|
||||||
Phone string `gorm:"column:phone;type:character varying(255);not null;comment:手机号码" json:"phone"` // 手机号码
|
|
||||||
Username *string `gorm:"column:username;type:character varying(255);comment:用户名" json:"username"` // 用户名
|
|
||||||
Email *string `gorm:"column:email;type:character varying(255)" json:"email"`
|
|
||||||
Password *string `gorm:"column:password;type:character varying(255);comment:用户密码" json:"password"` // 用户密码
|
|
||||||
Name *string `gorm:"column:name;type:character varying(255);comment:真实姓名" json:"name"` // 真实姓名
|
|
||||||
Avatar *string `gorm:"column:avatar;type:character varying(255);comment:头像URL" json:"avatar"` // 头像URL
|
|
||||||
Status int32 `gorm:"column:status;type:integer;not null;default:1;comment:用户状态:0-禁用,1-正常" json:"status"` // 用户状态:0-禁用,1-正常
|
|
||||||
Balance decimal.Decimal `gorm:"column:balance;type:numeric(12,2);not null;comment:账户余额" json:"balance"` // 账户余额
|
|
||||||
IDType int32 `gorm:"column:id_type;type:integer;not null;comment:认证类型:0-未认证,1-个人认证,2-企业认证" json:"id_type"` // 认证类型:0-未认证,1-个人认证,2-企业认证
|
|
||||||
IDNo *string `gorm:"column:id_no;type:character varying(255);comment:身份证号或营业执照号" json:"id_no"` // 身份证号或营业执照号
|
|
||||||
IDToken *string `gorm:"column:id_token;type:character varying(255);comment:身份验证标识" json:"id_token"` // 身份验证标识
|
|
||||||
ContactQQ *string `gorm:"column:contact_qq;type:character varying(255);comment:QQ联系方式" json:"contact_qq"` // QQ联系方式
|
|
||||||
ContactWechat *string `gorm:"column:contact_wechat;type:character varying(255);comment:微信联系方式" json:"contact_wechat"` // 微信联系方式
|
|
||||||
LastLogin *orm.LocalDateTime `gorm:"column:last_login;type:timestamp without time zone;comment:最后登录时间" json:"last_login"` // 最后登录时间
|
|
||||||
LastLoginHost *string `gorm:"column:last_login_host;type:character varying(45);comment:最后登录地址" json:"last_login_host"` // 最后登录地址
|
|
||||||
LastLoginAgent *string `gorm:"column:last_login_agent;type:character varying(255);comment:最后登录代理" json:"last_login_agent"` // 最后登录代理
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName User's table name
|
|
||||||
func (*User) TableName() string {
|
|
||||||
return TableNameUser
|
|
||||||
}
|
|
||||||
50
web/models/user.go
Normal file
50
web/models/user.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
"platform/web/globals/orm"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// User 用户表
|
||||||
|
type User struct {
|
||||||
|
core.Model
|
||||||
|
AdminID *int32 `json:"admin_id" gorm:"column:admin_id"` // 管理员ID
|
||||||
|
Phone string `json:"phone" gorm:"column:phone"` // 手机号码
|
||||||
|
Username *string `json:"username" gorm:"column:username"` // 用户名
|
||||||
|
Email *string `json:"email" gorm:"column:email"` // 邮箱
|
||||||
|
Password *string `json:"password" gorm:"column:password"` // 用户密码
|
||||||
|
Name *string `json:"name" gorm:"column:name"` // 真实姓名
|
||||||
|
Avatar *string `json:"avatar" gorm:"column:avatar"` // 头像URL
|
||||||
|
Status UserStatus `json:"status" gorm:"column:status"` // 用户状态:0-禁用,1-正常
|
||||||
|
Balance decimal.Decimal `json:"balance" gorm:"column:balance"` // 账户余额
|
||||||
|
IDType UserIDType `json:"id_type" gorm:"column:id_type"` // 认证类型:0-未认证,1-个人认证,2-企业认证
|
||||||
|
IDNo *string `json:"id_no" gorm:"column:id_no"` // 身份证号或营业执照号
|
||||||
|
IDToken *string `json:"id_token" gorm:"column:id_token"` // 身份验证标识
|
||||||
|
ContactQQ *string `json:"contact_qq" gorm:"column:contact_qq"` // QQ联系方式
|
||||||
|
ContactWechat *string `json:"contact_wechat" gorm:"column:contact_wechat"` // 微信联系方式
|
||||||
|
LastLogin *time.Time `json:"last_login" gorm:"column:last_login"` // 最后登录时间
|
||||||
|
LastLoginIP *orm.Inet `json:"last_login_ip" gorm:"column:last_login_ip"` // 最后登录地址
|
||||||
|
LastLoginUA *string `json:"last_login_ua" gorm:"column:last_login_ua"` // 最后登录代理
|
||||||
|
|
||||||
|
Admin Admin `json:"admin" gorm:"foreignKey:AdminID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserStatus 用户状态枚举
|
||||||
|
type UserStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserStatusDisabled UserStatus = 0 // 禁用
|
||||||
|
UserStatusEnabled UserStatus = 1 // 正常
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserIDType 用户认证类型枚举
|
||||||
|
type UserIDType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserIDTypeUnverified UserIDType = 0 // 未认证
|
||||||
|
UserIDTypePersonal UserIDType = 1 // 个人认证
|
||||||
|
UserIDTypeEnterprise UserIDType = 2 // 企业认证
|
||||||
|
)
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameUserRole = "user_role"
|
|
||||||
|
|
||||||
// UserRole mapped from table <user_role>
|
|
||||||
type UserRole struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:角色ID" json:"id"` // 角色ID
|
|
||||||
Name string `gorm:"column:name;type:character varying(255);not null;comment:角色名称" json:"name"` // 角色名称
|
|
||||||
Description *string `gorm:"column:description;type:character varying(255);comment:角色描述" json:"description"` // 角色描述
|
|
||||||
Active *bool `gorm:"column:active;type:boolean;default:true;comment:是否激活" json:"active"` // 是否激活
|
|
||||||
Sort *int32 `gorm:"column:sort;type:integer;comment:排序" json:"sort"` // 排序
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName UserRole's table name
|
|
||||||
func (*UserRole) TableName() string {
|
|
||||||
return TableNameUserRole
|
|
||||||
}
|
|
||||||
14
web/models/user_role.go
Normal file
14
web/models/user_role.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserRole 用户角色表
|
||||||
|
type UserRole struct {
|
||||||
|
core.Model
|
||||||
|
Name string `json:"name" gorm:"column:name"` // 角色名称
|
||||||
|
Description *string `json:"description" gorm:"column:description"` // 角色描述
|
||||||
|
Active bool `json:"active" gorm:"column:active"` // 是否激活
|
||||||
|
Sort int32 `json:"sort" gorm:"column:sort"` // 排序
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameUserRoleLink = "user_role_link"
|
|
||||||
|
|
||||||
// UserRoleLink mapped from table <user_role_link>
|
|
||||||
type UserRoleLink struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:关联ID" json:"id"` // 关联ID
|
|
||||||
UserID int32 `gorm:"column:user_id;type:integer;not null;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
RoleID int32 `gorm:"column:role_id;type:integer;not null;comment:角色ID" json:"role_id"` // 角色ID
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName UserRoleLink's table name
|
|
||||||
func (*UserRoleLink) TableName() string {
|
|
||||||
return TableNameUserRoleLink
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameUserRolePermissionLink = "user_role_permission_link"
|
|
||||||
|
|
||||||
// UserRolePermissionLink mapped from table <user_role_permission_link>
|
|
||||||
type UserRolePermissionLink struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:关联ID" json:"id"` // 关联ID
|
|
||||||
RoleID int32 `gorm:"column:role_id;type:integer;not null;comment:角色ID" json:"role_id"` // 角色ID
|
|
||||||
PermissionID int32 `gorm:"column:permission_id;type:integer;not null;comment:权限ID" json:"permission_id"` // 权限ID
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName UserRolePermissionLink's table name
|
|
||||||
func (*UserRolePermissionLink) TableName() string {
|
|
||||||
return TableNameUserRolePermissionLink
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
// 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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"platform/web/globals/orm"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TableNameWhitelist = "whitelist"
|
|
||||||
|
|
||||||
// Whitelist mapped from table <whitelist>
|
|
||||||
type Whitelist struct {
|
|
||||||
ID int32 `gorm:"column:id;type:integer;primaryKey;autoIncrement:true;comment:白名单ID" json:"id"` // 白名单ID
|
|
||||||
UserID int32 `gorm:"column:user_id;type:integer;not null;comment:用户ID" json:"user_id"` // 用户ID
|
|
||||||
Host string `gorm:"column:host;type:character varying(45);not null;comment:IP地址" json:"host"` // IP地址
|
|
||||||
Remark *string `gorm:"column:remark;type:character varying(255);comment:备注" json:"remark"` // 备注
|
|
||||||
CreatedAt *orm.LocalDateTime `gorm:"column:created_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt *orm.LocalDateTime `gorm:"column:updated_at;type:timestamp without time zone;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp without time zone;comment:删除时间" json:"deleted_at"` // 删除时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName Whitelist's table name
|
|
||||||
func (*Whitelist) TableName() string {
|
|
||||||
return TableNameWhitelist
|
|
||||||
}
|
|
||||||
14
web/models/whitelist.go
Normal file
14
web/models/whitelist.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"platform/web/core"
|
||||||
|
"platform/web/globals/orm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Whitelist 白名单表
|
||||||
|
type Whitelist struct {
|
||||||
|
core.Model
|
||||||
|
UserID int32 `json:"user_id" gorm:"column:user_id"` // 用户ID
|
||||||
|
IP orm.Inet `json:"ip" gorm:"column:ip;not null"` // IP地址
|
||||||
|
Remark *string `json:"remark" gorm:"column:remark"` // 备注
|
||||||
|
}
|
||||||
@@ -28,19 +28,19 @@ func newAdmin(db *gorm.DB, opts ...gen.DOOption) admin {
|
|||||||
tableName := _admin.adminDo.TableName()
|
tableName := _admin.adminDo.TableName()
|
||||||
_admin.ALL = field.NewAsterisk(tableName)
|
_admin.ALL = field.NewAsterisk(tableName)
|
||||||
_admin.ID = field.NewInt32(tableName, "id")
|
_admin.ID = field.NewInt32(tableName, "id")
|
||||||
|
_admin.CreatedAt = field.NewTime(tableName, "created_at")
|
||||||
|
_admin.UpdatedAt = field.NewTime(tableName, "updated_at")
|
||||||
|
_admin.DeletedAt = field.NewField(tableName, "deleted_at")
|
||||||
_admin.Username = field.NewString(tableName, "username")
|
_admin.Username = field.NewString(tableName, "username")
|
||||||
_admin.Password = field.NewString(tableName, "password")
|
_admin.Password = field.NewString(tableName, "password")
|
||||||
_admin.Name = field.NewString(tableName, "name")
|
_admin.Name = field.NewString(tableName, "name")
|
||||||
_admin.Avatar = field.NewString(tableName, "avatar")
|
_admin.Avatar = field.NewString(tableName, "avatar")
|
||||||
_admin.Phone = field.NewString(tableName, "phone")
|
_admin.Phone = field.NewString(tableName, "phone")
|
||||||
_admin.Email = field.NewString(tableName, "email")
|
_admin.Email = field.NewString(tableName, "email")
|
||||||
_admin.Status = field.NewInt32(tableName, "status")
|
_admin.Status = field.NewInt(tableName, "status")
|
||||||
_admin.LastLogin = field.NewField(tableName, "last_login")
|
_admin.LastLogin = field.NewTime(tableName, "last_login")
|
||||||
_admin.LastLoginHost = field.NewString(tableName, "last_login_host")
|
_admin.LastLoginIP = field.NewField(tableName, "last_login_ip")
|
||||||
_admin.LastLoginAgent = field.NewString(tableName, "last_login_agent")
|
_admin.LastLoginUA = field.NewString(tableName, "last_login_ua")
|
||||||
_admin.CreatedAt = field.NewField(tableName, "created_at")
|
|
||||||
_admin.UpdatedAt = field.NewField(tableName, "updated_at")
|
|
||||||
_admin.DeletedAt = field.NewField(tableName, "deleted_at")
|
|
||||||
|
|
||||||
_admin.fillFieldMap()
|
_admin.fillFieldMap()
|
||||||
|
|
||||||
@@ -51,20 +51,20 @@ type admin struct {
|
|||||||
adminDo
|
adminDo
|
||||||
|
|
||||||
ALL field.Asterisk
|
ALL field.Asterisk
|
||||||
ID field.Int32 // 管理员ID
|
ID field.Int32
|
||||||
Username field.String // 用户名
|
CreatedAt field.Time
|
||||||
Password field.String // 密码
|
UpdatedAt field.Time
|
||||||
Name field.String // 真实姓名
|
DeletedAt field.Field
|
||||||
Avatar field.String // 头像URL
|
Username field.String
|
||||||
Phone field.String // 手机号码
|
Password field.String
|
||||||
Email field.String // 邮箱
|
Name field.String
|
||||||
Status field.Int32 // 状态:0-禁用,1-正常
|
Avatar field.String
|
||||||
LastLogin field.Field // 最后登录时间
|
Phone field.String
|
||||||
LastLoginHost field.String // 最后登录地址
|
Email field.String
|
||||||
LastLoginAgent field.String // 最后登录代理
|
Status field.Int
|
||||||
CreatedAt field.Field // 创建时间
|
LastLogin field.Time
|
||||||
UpdatedAt field.Field // 更新时间
|
LastLoginIP field.Field
|
||||||
DeletedAt field.Field // 删除时间
|
LastLoginUA field.String
|
||||||
|
|
||||||
fieldMap map[string]field.Expr
|
fieldMap map[string]field.Expr
|
||||||
}
|
}
|
||||||
@@ -82,19 +82,19 @@ func (a admin) As(alias string) *admin {
|
|||||||
func (a *admin) updateTableName(table string) *admin {
|
func (a *admin) updateTableName(table string) *admin {
|
||||||
a.ALL = field.NewAsterisk(table)
|
a.ALL = field.NewAsterisk(table)
|
||||||
a.ID = field.NewInt32(table, "id")
|
a.ID = field.NewInt32(table, "id")
|
||||||
|
a.CreatedAt = field.NewTime(table, "created_at")
|
||||||
|
a.UpdatedAt = field.NewTime(table, "updated_at")
|
||||||
|
a.DeletedAt = field.NewField(table, "deleted_at")
|
||||||
a.Username = field.NewString(table, "username")
|
a.Username = field.NewString(table, "username")
|
||||||
a.Password = field.NewString(table, "password")
|
a.Password = field.NewString(table, "password")
|
||||||
a.Name = field.NewString(table, "name")
|
a.Name = field.NewString(table, "name")
|
||||||
a.Avatar = field.NewString(table, "avatar")
|
a.Avatar = field.NewString(table, "avatar")
|
||||||
a.Phone = field.NewString(table, "phone")
|
a.Phone = field.NewString(table, "phone")
|
||||||
a.Email = field.NewString(table, "email")
|
a.Email = field.NewString(table, "email")
|
||||||
a.Status = field.NewInt32(table, "status")
|
a.Status = field.NewInt(table, "status")
|
||||||
a.LastLogin = field.NewField(table, "last_login")
|
a.LastLogin = field.NewTime(table, "last_login")
|
||||||
a.LastLoginHost = field.NewString(table, "last_login_host")
|
a.LastLoginIP = field.NewField(table, "last_login_ip")
|
||||||
a.LastLoginAgent = field.NewString(table, "last_login_agent")
|
a.LastLoginUA = field.NewString(table, "last_login_ua")
|
||||||
a.CreatedAt = field.NewField(table, "created_at")
|
|
||||||
a.UpdatedAt = field.NewField(table, "updated_at")
|
|
||||||
a.DeletedAt = field.NewField(table, "deleted_at")
|
|
||||||
|
|
||||||
a.fillFieldMap()
|
a.fillFieldMap()
|
||||||
|
|
||||||
@@ -113,6 +113,9 @@ func (a *admin) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
|
|||||||
func (a *admin) fillFieldMap() {
|
func (a *admin) fillFieldMap() {
|
||||||
a.fieldMap = make(map[string]field.Expr, 14)
|
a.fieldMap = make(map[string]field.Expr, 14)
|
||||||
a.fieldMap["id"] = a.ID
|
a.fieldMap["id"] = a.ID
|
||||||
|
a.fieldMap["created_at"] = a.CreatedAt
|
||||||
|
a.fieldMap["updated_at"] = a.UpdatedAt
|
||||||
|
a.fieldMap["deleted_at"] = a.DeletedAt
|
||||||
a.fieldMap["username"] = a.Username
|
a.fieldMap["username"] = a.Username
|
||||||
a.fieldMap["password"] = a.Password
|
a.fieldMap["password"] = a.Password
|
||||||
a.fieldMap["name"] = a.Name
|
a.fieldMap["name"] = a.Name
|
||||||
@@ -121,11 +124,8 @@ func (a *admin) fillFieldMap() {
|
|||||||
a.fieldMap["email"] = a.Email
|
a.fieldMap["email"] = a.Email
|
||||||
a.fieldMap["status"] = a.Status
|
a.fieldMap["status"] = a.Status
|
||||||
a.fieldMap["last_login"] = a.LastLogin
|
a.fieldMap["last_login"] = a.LastLogin
|
||||||
a.fieldMap["last_login_host"] = a.LastLoginHost
|
a.fieldMap["last_login_ip"] = a.LastLoginIP
|
||||||
a.fieldMap["last_login_agent"] = a.LastLoginAgent
|
a.fieldMap["last_login_ua"] = a.LastLoginUA
|
||||||
a.fieldMap["created_at"] = a.CreatedAt
|
|
||||||
a.fieldMap["updated_at"] = a.UpdatedAt
|
|
||||||
a.fieldMap["deleted_at"] = a.DeletedAt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a admin) clone(db *gorm.DB) admin {
|
func (a admin) clone(db *gorm.DB) admin {
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ func newAdminRole(db *gorm.DB, opts ...gen.DOOption) adminRole {
|
|||||||
tableName := _adminRole.adminRoleDo.TableName()
|
tableName := _adminRole.adminRoleDo.TableName()
|
||||||
_adminRole.ALL = field.NewAsterisk(tableName)
|
_adminRole.ALL = field.NewAsterisk(tableName)
|
||||||
_adminRole.ID = field.NewInt32(tableName, "id")
|
_adminRole.ID = field.NewInt32(tableName, "id")
|
||||||
|
_adminRole.CreatedAt = field.NewTime(tableName, "created_at")
|
||||||
|
_adminRole.UpdatedAt = field.NewTime(tableName, "updated_at")
|
||||||
|
_adminRole.DeletedAt = field.NewField(tableName, "deleted_at")
|
||||||
_adminRole.Name = field.NewString(tableName, "name")
|
_adminRole.Name = field.NewString(tableName, "name")
|
||||||
_adminRole.Description = field.NewString(tableName, "description")
|
_adminRole.Description = field.NewString(tableName, "description")
|
||||||
_adminRole.Active = field.NewBool(tableName, "active")
|
_adminRole.Active = field.NewBool(tableName, "active")
|
||||||
_adminRole.Sort = field.NewInt32(tableName, "sort")
|
_adminRole.Sort = field.NewInt32(tableName, "sort")
|
||||||
_adminRole.CreatedAt = field.NewField(tableName, "created_at")
|
|
||||||
_adminRole.UpdatedAt = field.NewField(tableName, "updated_at")
|
|
||||||
_adminRole.DeletedAt = field.NewField(tableName, "deleted_at")
|
|
||||||
|
|
||||||
_adminRole.fillFieldMap()
|
_adminRole.fillFieldMap()
|
||||||
|
|
||||||
@@ -45,14 +45,14 @@ type adminRole struct {
|
|||||||
adminRoleDo
|
adminRoleDo
|
||||||
|
|
||||||
ALL field.Asterisk
|
ALL field.Asterisk
|
||||||
ID field.Int32 // 管理员角色ID
|
ID field.Int32
|
||||||
Name field.String // 角色名称
|
CreatedAt field.Time
|
||||||
Description field.String // 角色描述
|
UpdatedAt field.Time
|
||||||
Active field.Bool // 是否激活
|
DeletedAt field.Field
|
||||||
Sort field.Int32 // 排序
|
Name field.String
|
||||||
CreatedAt field.Field // 创建时间
|
Description field.String
|
||||||
UpdatedAt field.Field // 更新时间
|
Active field.Bool
|
||||||
DeletedAt field.Field // 删除时间
|
Sort field.Int32
|
||||||
|
|
||||||
fieldMap map[string]field.Expr
|
fieldMap map[string]field.Expr
|
||||||
}
|
}
|
||||||
@@ -70,13 +70,13 @@ func (a adminRole) As(alias string) *adminRole {
|
|||||||
func (a *adminRole) updateTableName(table string) *adminRole {
|
func (a *adminRole) updateTableName(table string) *adminRole {
|
||||||
a.ALL = field.NewAsterisk(table)
|
a.ALL = field.NewAsterisk(table)
|
||||||
a.ID = field.NewInt32(table, "id")
|
a.ID = field.NewInt32(table, "id")
|
||||||
|
a.CreatedAt = field.NewTime(table, "created_at")
|
||||||
|
a.UpdatedAt = field.NewTime(table, "updated_at")
|
||||||
|
a.DeletedAt = field.NewField(table, "deleted_at")
|
||||||
a.Name = field.NewString(table, "name")
|
a.Name = field.NewString(table, "name")
|
||||||
a.Description = field.NewString(table, "description")
|
a.Description = field.NewString(table, "description")
|
||||||
a.Active = field.NewBool(table, "active")
|
a.Active = field.NewBool(table, "active")
|
||||||
a.Sort = field.NewInt32(table, "sort")
|
a.Sort = field.NewInt32(table, "sort")
|
||||||
a.CreatedAt = field.NewField(table, "created_at")
|
|
||||||
a.UpdatedAt = field.NewField(table, "updated_at")
|
|
||||||
a.DeletedAt = field.NewField(table, "deleted_at")
|
|
||||||
|
|
||||||
a.fillFieldMap()
|
a.fillFieldMap()
|
||||||
|
|
||||||
@@ -95,13 +95,13 @@ func (a *adminRole) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
|
|||||||
func (a *adminRole) fillFieldMap() {
|
func (a *adminRole) fillFieldMap() {
|
||||||
a.fieldMap = make(map[string]field.Expr, 8)
|
a.fieldMap = make(map[string]field.Expr, 8)
|
||||||
a.fieldMap["id"] = a.ID
|
a.fieldMap["id"] = a.ID
|
||||||
|
a.fieldMap["created_at"] = a.CreatedAt
|
||||||
|
a.fieldMap["updated_at"] = a.UpdatedAt
|
||||||
|
a.fieldMap["deleted_at"] = a.DeletedAt
|
||||||
a.fieldMap["name"] = a.Name
|
a.fieldMap["name"] = a.Name
|
||||||
a.fieldMap["description"] = a.Description
|
a.fieldMap["description"] = a.Description
|
||||||
a.fieldMap["active"] = a.Active
|
a.fieldMap["active"] = a.Active
|
||||||
a.fieldMap["sort"] = a.Sort
|
a.fieldMap["sort"] = a.Sort
|
||||||
a.fieldMap["created_at"] = a.CreatedAt
|
|
||||||
a.fieldMap["updated_at"] = a.UpdatedAt
|
|
||||||
a.fieldMap["deleted_at"] = a.DeletedAt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a adminRole) clone(db *gorm.DB) adminRole {
|
func (a adminRole) clone(db *gorm.DB) adminRole {
|
||||||
|
|||||||
@@ -1,339 +0,0 @@
|
|||||||
// 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 newAdminRoleLink(db *gorm.DB, opts ...gen.DOOption) adminRoleLink {
|
|
||||||
_adminRoleLink := adminRoleLink{}
|
|
||||||
|
|
||||||
_adminRoleLink.adminRoleLinkDo.UseDB(db, opts...)
|
|
||||||
_adminRoleLink.adminRoleLinkDo.UseModel(&models.AdminRoleLink{})
|
|
||||||
|
|
||||||
tableName := _adminRoleLink.adminRoleLinkDo.TableName()
|
|
||||||
_adminRoleLink.ALL = field.NewAsterisk(tableName)
|
|
||||||
_adminRoleLink.ID = field.NewInt32(tableName, "id")
|
|
||||||
_adminRoleLink.AdminID = field.NewInt32(tableName, "admin_id")
|
|
||||||
_adminRoleLink.RoleID = field.NewInt32(tableName, "role_id")
|
|
||||||
_adminRoleLink.CreatedAt = field.NewField(tableName, "created_at")
|
|
||||||
_adminRoleLink.UpdatedAt = field.NewField(tableName, "updated_at")
|
|
||||||
_adminRoleLink.DeletedAt = field.NewField(tableName, "deleted_at")
|
|
||||||
|
|
||||||
_adminRoleLink.fillFieldMap()
|
|
||||||
|
|
||||||
return _adminRoleLink
|
|
||||||
}
|
|
||||||
|
|
||||||
type adminRoleLink struct {
|
|
||||||
adminRoleLinkDo
|
|
||||||
|
|
||||||
ALL field.Asterisk
|
|
||||||
ID field.Int32 // 关联ID
|
|
||||||
AdminID field.Int32 // 管理员ID
|
|
||||||
RoleID field.Int32 // 角色ID
|
|
||||||
CreatedAt field.Field // 创建时间
|
|
||||||
UpdatedAt field.Field // 更新时间
|
|
||||||
DeletedAt field.Field // 删除时间
|
|
||||||
|
|
||||||
fieldMap map[string]field.Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLink) Table(newTableName string) *adminRoleLink {
|
|
||||||
a.adminRoleLinkDo.UseTable(newTableName)
|
|
||||||
return a.updateTableName(newTableName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLink) As(alias string) *adminRoleLink {
|
|
||||||
a.adminRoleLinkDo.DO = *(a.adminRoleLinkDo.As(alias).(*gen.DO))
|
|
||||||
return a.updateTableName(alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *adminRoleLink) updateTableName(table string) *adminRoleLink {
|
|
||||||
a.ALL = field.NewAsterisk(table)
|
|
||||||
a.ID = field.NewInt32(table, "id")
|
|
||||||
a.AdminID = field.NewInt32(table, "admin_id")
|
|
||||||
a.RoleID = field.NewInt32(table, "role_id")
|
|
||||||
a.CreatedAt = field.NewField(table, "created_at")
|
|
||||||
a.UpdatedAt = field.NewField(table, "updated_at")
|
|
||||||
a.DeletedAt = field.NewField(table, "deleted_at")
|
|
||||||
|
|
||||||
a.fillFieldMap()
|
|
||||||
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *adminRoleLink) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
|
|
||||||
_f, ok := a.fieldMap[fieldName]
|
|
||||||
if !ok || _f == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
_oe, ok := _f.(field.OrderExpr)
|
|
||||||
return _oe, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *adminRoleLink) fillFieldMap() {
|
|
||||||
a.fieldMap = make(map[string]field.Expr, 6)
|
|
||||||
a.fieldMap["id"] = a.ID
|
|
||||||
a.fieldMap["admin_id"] = a.AdminID
|
|
||||||
a.fieldMap["role_id"] = a.RoleID
|
|
||||||
a.fieldMap["created_at"] = a.CreatedAt
|
|
||||||
a.fieldMap["updated_at"] = a.UpdatedAt
|
|
||||||
a.fieldMap["deleted_at"] = a.DeletedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLink) clone(db *gorm.DB) adminRoleLink {
|
|
||||||
a.adminRoleLinkDo.ReplaceConnPool(db.Statement.ConnPool)
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLink) replaceDB(db *gorm.DB) adminRoleLink {
|
|
||||||
a.adminRoleLinkDo.ReplaceDB(db)
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
type adminRoleLinkDo struct{ gen.DO }
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Debug() *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Debug())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) WithContext(ctx context.Context) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.WithContext(ctx))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) ReadDB() *adminRoleLinkDo {
|
|
||||||
return a.Clauses(dbresolver.Read)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) WriteDB() *adminRoleLinkDo {
|
|
||||||
return a.Clauses(dbresolver.Write)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Session(config *gorm.Session) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Session(config))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Clauses(conds ...clause.Expression) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Clauses(conds...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Returning(value interface{}, columns ...string) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Returning(value, columns...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Not(conds ...gen.Condition) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Not(conds...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Or(conds ...gen.Condition) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Or(conds...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Select(conds ...field.Expr) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Select(conds...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Where(conds ...gen.Condition) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Where(conds...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Order(conds ...field.Expr) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Order(conds...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Distinct(cols ...field.Expr) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Distinct(cols...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Omit(cols ...field.Expr) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Omit(cols...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Join(table schema.Tabler, on ...field.Expr) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Join(table, on...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) LeftJoin(table schema.Tabler, on ...field.Expr) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.LeftJoin(table, on...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) RightJoin(table schema.Tabler, on ...field.Expr) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.RightJoin(table, on...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Group(cols ...field.Expr) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Group(cols...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Having(conds ...gen.Condition) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Having(conds...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Limit(limit int) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Limit(limit))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Offset(offset int) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Offset(offset))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Scopes(funcs...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Unscoped() *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Unscoped())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Create(values ...*models.AdminRoleLink) error {
|
|
||||||
if len(values) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return a.DO.Create(values)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) CreateInBatches(values []*models.AdminRoleLink, batchSize int) error {
|
|
||||||
return a.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 (a adminRoleLinkDo) Save(values ...*models.AdminRoleLink) error {
|
|
||||||
if len(values) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return a.DO.Save(values)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) First() (*models.AdminRoleLink, error) {
|
|
||||||
if result, err := a.DO.First(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return result.(*models.AdminRoleLink), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Take() (*models.AdminRoleLink, error) {
|
|
||||||
if result, err := a.DO.Take(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return result.(*models.AdminRoleLink), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Last() (*models.AdminRoleLink, error) {
|
|
||||||
if result, err := a.DO.Last(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return result.(*models.AdminRoleLink), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Find() ([]*models.AdminRoleLink, error) {
|
|
||||||
result, err := a.DO.Find()
|
|
||||||
return result.([]*models.AdminRoleLink), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.AdminRoleLink, err error) {
|
|
||||||
buf := make([]*models.AdminRoleLink, 0, batchSize)
|
|
||||||
err = a.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 (a adminRoleLinkDo) FindInBatches(result *[]*models.AdminRoleLink, batchSize int, fc func(tx gen.Dao, batch int) error) error {
|
|
||||||
return a.DO.FindInBatches(result, batchSize, fc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Attrs(attrs ...field.AssignExpr) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Attrs(attrs...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Assign(attrs ...field.AssignExpr) *adminRoleLinkDo {
|
|
||||||
return a.withDO(a.DO.Assign(attrs...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Joins(fields ...field.RelationField) *adminRoleLinkDo {
|
|
||||||
for _, _f := range fields {
|
|
||||||
a = *a.withDO(a.DO.Joins(_f))
|
|
||||||
}
|
|
||||||
return &a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Preload(fields ...field.RelationField) *adminRoleLinkDo {
|
|
||||||
for _, _f := range fields {
|
|
||||||
a = *a.withDO(a.DO.Preload(_f))
|
|
||||||
}
|
|
||||||
return &a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) FirstOrInit() (*models.AdminRoleLink, error) {
|
|
||||||
if result, err := a.DO.FirstOrInit(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return result.(*models.AdminRoleLink), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) FirstOrCreate() (*models.AdminRoleLink, error) {
|
|
||||||
if result, err := a.DO.FirstOrCreate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return result.(*models.AdminRoleLink), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) FindByPage(offset int, limit int) (result []*models.AdminRoleLink, count int64, err error) {
|
|
||||||
result, err = a.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 = a.Offset(-1).Limit(-1).Count()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
|
|
||||||
count, err = a.Count()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Offset(offset).Limit(limit).Scan(result)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Scan(result interface{}) (err error) {
|
|
||||||
return a.DO.Scan(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a adminRoleLinkDo) Delete(models ...*models.AdminRoleLink) (result gen.ResultInfo, err error) {
|
|
||||||
return a.DO.Delete(models)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *adminRoleLinkDo) withDO(do gen.Dao) *adminRoleLinkDo {
|
|
||||||
a.DO = *do.(*gen.DO)
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user