mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-23 23:10:26 +08:00
支持购买套餐/续费套餐/用户账户操作等
This commit is contained in:
80
internal/db/models/accounts/user_account_daily_stat_dao.go
Normal file
80
internal/db/models/accounts/user_account_daily_stat_dao.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserAccountDailyStatDAO dbs.DAO
|
||||||
|
|
||||||
|
func NewUserAccountDailyStatDAO() *UserAccountDailyStatDAO {
|
||||||
|
return dbs.NewDAO(&UserAccountDailyStatDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeUserAccountDailyStats",
|
||||||
|
Model: new(UserAccountDailyStat),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*UserAccountDailyStatDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedUserAccountDailyStatDAO *UserAccountDailyStatDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedUserAccountDailyStatDAO = NewUserAccountDailyStatDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDailyStat 更新当天统计数据
|
||||||
|
func (this *UserAccountDailyStatDAO) UpdateDailyStat(tx *dbs.Tx) error {
|
||||||
|
var day = timeutil.Format("Ymd")
|
||||||
|
var month = timeutil.Format("Ym")
|
||||||
|
income, err := SharedUserAccountLogDAO.SumDailyEventTypes(tx, day, userconfigs.AccountIncomeEventTypes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
expense, err := SharedUserAccountLogDAO.SumDailyEventTypes(tx, day, userconfigs.AccountExpenseEventTypes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if expense < 0 {
|
||||||
|
expense = -expense
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Query(tx).
|
||||||
|
InsertOrUpdateQuickly(maps.Map{
|
||||||
|
"day": day,
|
||||||
|
"month": month,
|
||||||
|
"income": income,
|
||||||
|
"expense": expense,
|
||||||
|
}, maps.Map{
|
||||||
|
"income": income,
|
||||||
|
"expense": expense,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindDailyStats 查看按天统计
|
||||||
|
func (this *UserAccountDailyStatDAO) FindDailyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*UserAccountDailyStat, err error) {
|
||||||
|
_, err = this.Query(tx).
|
||||||
|
Between("day", dayFrom, dayTo).
|
||||||
|
Slice(&result).
|
||||||
|
FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindMonthlyStats 查看某月统计
|
||||||
|
func (this *UserAccountDailyStatDAO) FindMonthlyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*UserAccountDailyStat, err error) {
|
||||||
|
_, err = this.Query(tx).
|
||||||
|
Result("SUM(income) AS income", "SUM(expense) AS expense", "month").
|
||||||
|
Between("day", dayFrom, dayTo).
|
||||||
|
Group("month").
|
||||||
|
Slice(&result).
|
||||||
|
FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
22
internal/db/models/accounts/user_account_daily_stat_model.go
Normal file
22
internal/db/models/accounts/user_account_daily_stat_model.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
// UserAccountDailyStat 账户每日统计
|
||||||
|
type UserAccountDailyStat struct {
|
||||||
|
Id uint32 `field:"id"` // ID
|
||||||
|
Day string `field:"day"` // YYYYMMDD
|
||||||
|
Month string `field:"month"` // YYYYMM
|
||||||
|
Income float64 `field:"income"` // 收入
|
||||||
|
Expense float64 `field:"expense"` // 支出
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserAccountDailyStatOperator struct {
|
||||||
|
Id interface{} // ID
|
||||||
|
Day interface{} // YYYYMMDD
|
||||||
|
Month interface{} // YYYYMM
|
||||||
|
Income interface{} // 收入
|
||||||
|
Expense interface{} // 支出
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserAccountDailyStatOperator() *UserAccountDailyStatOperator {
|
||||||
|
return &UserAccountDailyStatOperator{}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
package accounts
|
||||||
172
internal/db/models/accounts/user_account_dao.go
Normal file
172
internal/db/models/accounts/user_account_dao.go
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserAccountDAO dbs.DAO
|
||||||
|
|
||||||
|
func NewUserAccountDAO() *UserAccountDAO {
|
||||||
|
return dbs.NewDAO(&UserAccountDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeUserAccounts",
|
||||||
|
Model: new(UserAccount),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*UserAccountDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedUserAccountDAO *UserAccountDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedUserAccountDAO = NewUserAccountDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindUserAccountWithUserId 根据用户ID查找用户账户
|
||||||
|
func (this *UserAccountDAO) FindUserAccountWithUserId(tx *dbs.Tx, userId int64) (*UserAccount, error) {
|
||||||
|
if userId <= 0 {
|
||||||
|
return nil, errors.New("invalid userId '" + types.String(userId) + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户是否存在
|
||||||
|
user, err := models.SharedUserDAO.FindEnabledUser(tx, userId, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if user == nil {
|
||||||
|
return nil, errors.New("invalid userId '" + types.String(userId) + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := this.Query(tx).
|
||||||
|
Attr("userId", userId).
|
||||||
|
Find()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if account != nil {
|
||||||
|
return account.(*UserAccount), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var op = NewUserAccountOperator()
|
||||||
|
op.UserId = userId
|
||||||
|
_, err = this.SaveInt64(tx, op)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return this.FindUserAccountWithUserId(tx, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindUserAccountWithAccountId 根据ID查找用户账户
|
||||||
|
func (this *UserAccountDAO) FindUserAccountWithAccountId(tx *dbs.Tx, accountId int64) (*UserAccount, error) {
|
||||||
|
one, err := this.Query(tx).
|
||||||
|
Pk(accountId).
|
||||||
|
Find()
|
||||||
|
if one != nil {
|
||||||
|
return one.(*UserAccount), nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserAccount 操作用户账户
|
||||||
|
func (this *UserAccountDAO) UpdateUserAccount(tx *dbs.Tx, accountId int64, delta float32, eventType userconfigs.AccountEventType, description string, params maps.Map) error {
|
||||||
|
account, err := this.FindUserAccountWithAccountId(tx, accountId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if account == nil {
|
||||||
|
return errors.New("invalid account id '" + types.String(accountId) + "'")
|
||||||
|
}
|
||||||
|
var userId = int64(account.Id)
|
||||||
|
var deltaFloat64 = float64(delta)
|
||||||
|
if deltaFloat64 < 0 && account.Total < -deltaFloat64 {
|
||||||
|
return errors.New("not enough account quota to decrease")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 操作账户
|
||||||
|
err = this.Query(tx).
|
||||||
|
Pk(account.Id).
|
||||||
|
Set("total", dbs.SQL("total+:delta")).
|
||||||
|
Param("delta", delta).
|
||||||
|
UpdateQuickly()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成日志
|
||||||
|
err = SharedUserAccountLogDAO.CreateAccountLog(tx, userId, accountId, delta, 0, eventType, description, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserAccountFrozen 操作用户账户冻结余额
|
||||||
|
func (this *UserAccountDAO) UpdateUserAccountFrozen(tx *dbs.Tx, userId int64, delta float32, eventType userconfigs.AccountEventType, description string, params maps.Map) error {
|
||||||
|
account, err := this.FindUserAccountWithUserId(tx, userId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var deltaFloat64 = float64(delta)
|
||||||
|
if deltaFloat64 < 0 && account.TotalFrozen < -deltaFloat64 {
|
||||||
|
return errors.New("not enough account frozen quota to decrease")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 操作账户
|
||||||
|
err = this.Query(tx).
|
||||||
|
Pk(account.Id).
|
||||||
|
Set("totalFrozen", dbs.SQL("total+:delta")).
|
||||||
|
Param("delta", delta).
|
||||||
|
UpdateQuickly()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成日志
|
||||||
|
err = SharedUserAccountLogDAO.CreateAccountLog(tx, userId, int64(account.Id), 0, delta, eventType, description, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountAllAccounts 计算所有账户数量
|
||||||
|
func (this *UserAccountDAO) CountAllAccounts(tx *dbs.Tx, keyword string) (int64, error) {
|
||||||
|
var query = this.Query(tx)
|
||||||
|
if len(keyword) > 0 {
|
||||||
|
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword))")
|
||||||
|
query.Param("keyword", keyword)
|
||||||
|
} else {
|
||||||
|
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1)")
|
||||||
|
}
|
||||||
|
return query.Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAccounts 列出单页账户
|
||||||
|
func (this *UserAccountDAO) ListAccounts(tx *dbs.Tx, keyword string, offset int64, size int64) (result []*UserAccount, err error) {
|
||||||
|
var query = this.Query(tx)
|
||||||
|
if len(keyword) > 0 {
|
||||||
|
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword))")
|
||||||
|
query.Param("keyword", keyword)
|
||||||
|
} else {
|
||||||
|
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1)")
|
||||||
|
}
|
||||||
|
_, err = query.
|
||||||
|
DescPk().
|
||||||
|
Offset(offset).
|
||||||
|
Limit(size).
|
||||||
|
Slice(&result).
|
||||||
|
FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
6
internal/db/models/accounts/user_account_dao_test.go
Normal file
6
internal/db/models/accounts/user_account_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
128
internal/db/models/accounts/user_account_log_dao.go
Normal file
128
internal/db/models/accounts/user_account_log_dao.go
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserAccountLogDAO dbs.DAO
|
||||||
|
|
||||||
|
func NewUserAccountLogDAO() *UserAccountLogDAO {
|
||||||
|
return dbs.NewDAO(&UserAccountLogDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeUserAccountLogs",
|
||||||
|
Model: new(UserAccountLog),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*UserAccountLogDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedUserAccountLogDAO *UserAccountLogDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedUserAccountLogDAO = NewUserAccountLogDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAccountLog 生成用户账户日志
|
||||||
|
func (this *UserAccountLogDAO) CreateAccountLog(tx *dbs.Tx, userId int64, accountId int64, delta float32, deltaFrozen float32, eventType userconfigs.AccountEventType, description string, params maps.Map) error {
|
||||||
|
var op = NewUserAccountLogOperator()
|
||||||
|
op.UserId = userId
|
||||||
|
op.AccountId = accountId
|
||||||
|
op.Delta = delta
|
||||||
|
op.DeltaFrozen = deltaFrozen
|
||||||
|
|
||||||
|
account, err := SharedUserAccountDAO.FindUserAccountWithAccountId(tx, accountId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if account == nil {
|
||||||
|
return errors.New("invalid account id '" + types.String(accountId) + "'")
|
||||||
|
}
|
||||||
|
op.Total = account.Total
|
||||||
|
op.TotalFrozen = account.TotalFrozen
|
||||||
|
|
||||||
|
op.EventType = eventType
|
||||||
|
op.Description = description
|
||||||
|
|
||||||
|
if params == nil {
|
||||||
|
params = maps.Map{}
|
||||||
|
}
|
||||||
|
op.Params = params.AsJSON()
|
||||||
|
|
||||||
|
op.Day = timeutil.Format("Ymd")
|
||||||
|
err = this.Save(tx, op)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return SharedUserAccountDailyStatDAO.UpdateDailyStat(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountAccountLogs 计算日志数量
|
||||||
|
func (this *UserAccountLogDAO) CountAccountLogs(tx *dbs.Tx, userId int64, accountId int64, keyword string, eventType string) (int64, error) {
|
||||||
|
var query = this.Query(tx)
|
||||||
|
if userId > 0 {
|
||||||
|
query.Attr("userId", userId)
|
||||||
|
}
|
||||||
|
if accountId > 0 {
|
||||||
|
query.Attr("accountId", accountId)
|
||||||
|
}
|
||||||
|
if len(keyword) > 0 {
|
||||||
|
query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)")
|
||||||
|
query.Param("keyword", "%"+keyword+"%")
|
||||||
|
}
|
||||||
|
if len(eventType) > 0 {
|
||||||
|
query.Attr("eventType", eventType)
|
||||||
|
}
|
||||||
|
return query.Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAccountLogs 列出单页日志
|
||||||
|
func (this *UserAccountLogDAO) ListAccountLogs(tx *dbs.Tx, userId int64, accountId int64, keyword string, eventType string, offset int64, size int64) (result []*UserAccountLog, err error) {
|
||||||
|
var query = this.Query(tx)
|
||||||
|
if userId > 0 {
|
||||||
|
query.Attr("userId", userId)
|
||||||
|
}
|
||||||
|
if accountId > 0 {
|
||||||
|
query.Attr("accountId", accountId)
|
||||||
|
}
|
||||||
|
if len(keyword) > 0 {
|
||||||
|
query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)")
|
||||||
|
query.Param("keyword", "%"+keyword+"%")
|
||||||
|
}
|
||||||
|
if len(eventType) > 0 {
|
||||||
|
query.Attr("eventType", eventType)
|
||||||
|
}
|
||||||
|
_, err = query.
|
||||||
|
DescPk().
|
||||||
|
Offset(offset).
|
||||||
|
Limit(size).
|
||||||
|
Slice(&result).
|
||||||
|
FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SumDailyEventTypes 统计某天数据总和
|
||||||
|
func (this *UserAccountLogDAO) SumDailyEventTypes(tx *dbs.Tx, day string, eventTypes []userconfigs.AccountEventType) (float32, error) {
|
||||||
|
if len(eventTypes) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
result, err := this.Query(tx).
|
||||||
|
Attr("day", day).
|
||||||
|
Attr("eventType", eventTypes).
|
||||||
|
Sum("delta", 0)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return types.Float32(result), nil
|
||||||
|
}
|
||||||
6
internal/db/models/accounts/user_account_log_dao_test.go
Normal file
6
internal/db/models/accounts/user_account_log_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
36
internal/db/models/accounts/user_account_log_model.go
Normal file
36
internal/db/models/accounts/user_account_log_model.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
// UserAccountLog 用户账户日志
|
||||||
|
type UserAccountLog struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
UserId uint64 `field:"userId"` // 用户ID
|
||||||
|
AccountId uint64 `field:"accountId"` // 账户ID
|
||||||
|
Delta float64 `field:"delta"` // 操作余额的数量(可为负)
|
||||||
|
DeltaFrozen float64 `field:"deltaFrozen"` // 操作冻结的数量(可为负)
|
||||||
|
Total float64 `field:"total"` // 操作后余额
|
||||||
|
TotalFrozen float64 `field:"totalFrozen"` // 操作后冻结余额
|
||||||
|
EventType string `field:"eventType"` // 类型
|
||||||
|
Description string `field:"description"` // 描述文字
|
||||||
|
Day string `field:"day"` // YYYYMMDD
|
||||||
|
CreatedAt uint64 `field:"createdAt"` // 时间
|
||||||
|
Params string `field:"params"` // 参数
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserAccountLogOperator struct {
|
||||||
|
Id interface{} // ID
|
||||||
|
UserId interface{} // 用户ID
|
||||||
|
AccountId interface{} // 账户ID
|
||||||
|
Delta interface{} // 操作余额的数量(可为负)
|
||||||
|
DeltaFrozen interface{} // 操作冻结的数量(可为负)
|
||||||
|
Total interface{} // 操作后余额
|
||||||
|
TotalFrozen interface{} // 操作后冻结余额
|
||||||
|
EventType interface{} // 类型
|
||||||
|
Description interface{} // 描述文字
|
||||||
|
Day interface{} // YYYYMMDD
|
||||||
|
CreatedAt interface{} // 时间
|
||||||
|
Params interface{} // 参数
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserAccountLogOperator() *UserAccountLogOperator {
|
||||||
|
return &UserAccountLogOperator{}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
package accounts
|
||||||
20
internal/db/models/accounts/user_account_model.go
Normal file
20
internal/db/models/accounts/user_account_model.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
// UserAccount 用户账号
|
||||||
|
type UserAccount struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
UserId uint64 `field:"userId"` // 用户ID
|
||||||
|
Total float64 `field:"total"` // 可用总余额
|
||||||
|
TotalFrozen float64 `field:"totalFrozen"` // 冻结余额
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserAccountOperator struct {
|
||||||
|
Id interface{} // ID
|
||||||
|
UserId interface{} // 用户ID
|
||||||
|
Total interface{} // 可用总余额
|
||||||
|
TotalFrozen interface{} // 冻结余额
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserAccountOperator() *UserAccountOperator {
|
||||||
|
return &UserAccountOperator{}
|
||||||
|
}
|
||||||
1
internal/db/models/accounts/user_account_model_ext.go
Normal file
1
internal/db/models/accounts/user_account_model_ext.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package accounts
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -85,7 +86,7 @@ func (this *ClientBrowserDAO) FindBrowserIdWithNameCacheable(tx *dbs.Tx, browser
|
|||||||
|
|
||||||
browserId, err := this.Query(tx).
|
browserId, err := this.Query(tx).
|
||||||
Where("JSON_CONTAINS(codes, :browserName)").
|
Where("JSON_CONTAINS(codes, :browserName)").
|
||||||
Param("browserName", "\""+browserName+"\""). // 查询的需要是个JSON字符串,所以这里加双引号
|
Param("browserName", strconv.Quote(browserName)). // 查询的需要是个JSON字符串,所以这里加双引号
|
||||||
ResultPk().
|
ResultPk().
|
||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -85,7 +86,7 @@ func (this *ClientSystemDAO) FindSystemIdWithNameCacheable(tx *dbs.Tx, systemNam
|
|||||||
|
|
||||||
systemId, err := this.Query(tx).
|
systemId, err := this.Query(tx).
|
||||||
Where("JSON_CONTAINS(codes, :systemName)").
|
Where("JSON_CONTAINS(codes, :systemName)").
|
||||||
Param("systemName", "\""+systemName+"\""). // 查询的需要是个JSON字符串,所以这里加双引号
|
Param("systemName", strconv.Quote(systemName)). // 查询的需要是个JSON字符串,所以这里加双引号
|
||||||
ResultPk().
|
ResultPk().
|
||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -119,7 +120,7 @@ func (this *RegionCityDAO) FindCityIdWithNameCacheable(tx *dbs.Tx, provinceId in
|
|||||||
cityId, err := this.Query(tx).
|
cityId, err := this.Query(tx).
|
||||||
Attr("provinceId", provinceId).
|
Attr("provinceId", provinceId).
|
||||||
Where("JSON_CONTAINS(codes, :cityName)").
|
Where("JSON_CONTAINS(codes, :cityName)").
|
||||||
Param("cityName", "\""+cityName+"\""). // 查询的需要是个JSON字符串,所以这里加双引号
|
Param("cityName", strconv.Quote(cityName)). // 查询的需要是个JSON字符串,所以这里加双引号
|
||||||
ResultPk().
|
ResultPk().
|
||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
"github.com/mozillazg/go-pinyin"
|
"github.com/mozillazg/go-pinyin"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string)
|
|||||||
func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName string) (int64, error) {
|
func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName string) (int64, error) {
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
Where("JSON_CONTAINS(codes, :countryName)").
|
Where("JSON_CONTAINS(codes, :countryName)").
|
||||||
Param("countryName", "\""+countryName+"\""). // 查询的需要是个JSON字符串,所以这里加双引号
|
Param("countryName", strconv.Quote(countryName)). // 查询的需要是个JSON字符串,所以这里加双引号
|
||||||
ResultPk().
|
ResultPk().
|
||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -85,7 +86,7 @@ func (this *RegionProviderDAO) FindProviderIdWithNameCacheable(tx *dbs.Tx, provi
|
|||||||
|
|
||||||
providerId, err := this.Query(tx).
|
providerId, err := this.Query(tx).
|
||||||
Where("JSON_CONTAINS(codes, :providerName)").
|
Where("JSON_CONTAINS(codes, :providerName)").
|
||||||
Param("providerName", "\""+providerName+"\""). // 查询的需要是个JSON字符串,所以这里加双引号
|
Param("providerName", strconv.Quote(providerName)). // 查询的需要是个JSON字符串,所以这里加双引号
|
||||||
ResultPk().
|
ResultPk().
|
||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -88,7 +89,7 @@ func (this *RegionProvinceDAO) FindProvinceIdWithName(tx *dbs.Tx, countryId int6
|
|||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
Attr("countryId", countryId).
|
Attr("countryId", countryId).
|
||||||
Where("JSON_CONTAINS(codes, :provinceName)").
|
Where("JSON_CONTAINS(codes, :provinceName)").
|
||||||
Param("provinceName", "\""+provinceName+"\""). // 查询的需要是个JSON字符串,所以这里加双引号
|
Param("provinceName", strconv.Quote(provinceName)). // 查询的需要是个JSON字符串,所以这里加双引号
|
||||||
ResultPk().
|
ResultPk().
|
||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
@@ -55,15 +56,27 @@ func (this *UserDAO) DisableUser(tx *dbs.Tx, id int64) (rowsAffected int64, err
|
|||||||
Update()
|
Update()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindEnabledUser 查找启用中的条目
|
// FindEnabledUser 查找启用的用户
|
||||||
func (this *UserDAO) FindEnabledUser(tx *dbs.Tx, id int64) (*User, error) {
|
func (this *UserDAO) FindEnabledUser(tx *dbs.Tx, userId int64, cacheMap maps.Map) (*User, error) {
|
||||||
|
if cacheMap == nil {
|
||||||
|
cacheMap = maps.Map{}
|
||||||
|
}
|
||||||
|
var cacheKey = this.Table + ":FindEnabledUser:" + types.String(userId)
|
||||||
|
cache, ok := cacheMap[cacheKey]
|
||||||
|
if ok {
|
||||||
|
return cache.(*User), nil
|
||||||
|
}
|
||||||
|
|
||||||
result, err := this.Query(tx).
|
result, err := this.Query(tx).
|
||||||
Pk(id).
|
Pk(userId).
|
||||||
Attr("state", UserStateEnabled).
|
Attr("state", UserStateEnabled).
|
||||||
Find()
|
Find()
|
||||||
if result == nil {
|
if result == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cacheMap[cacheKey] = result
|
||||||
|
|
||||||
return result.(*User), err
|
return result.(*User), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,3 +136,14 @@ func (this *UserPlanDAO) UpdateUserPlan(tx *dbs.Tx, userPlanId int64, planId int
|
|||||||
op.IsOn = isOn
|
op.IsOn = isOn
|
||||||
return this.Save(tx, op)
|
return this.Save(tx, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateUserPlanDayTo 修改套餐日期
|
||||||
|
func (this *UserPlanDAO) UpdateUserPlanDayTo(tx *dbs.Tx, userPlanId int64, dayTo string) error {
|
||||||
|
if userPlanId <= 0 {
|
||||||
|
return errors.New("invalid userPlanId")
|
||||||
|
}
|
||||||
|
var op = NewUserPlanOperator()
|
||||||
|
op.Id = userPlanId
|
||||||
|
op.DayTo = dayTo
|
||||||
|
return this.Save(tx, op)
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
|
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
|
||||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NSDomainService 域名相关服务
|
// NSDomainService 域名相关服务
|
||||||
@@ -89,7 +90,7 @@ func (this *NSDomainService) FindEnabledNSDomain(ctx context.Context, req *pb.Fi
|
|||||||
// 用户
|
// 用户
|
||||||
var pbUser *pb.User
|
var pbUser *pb.User
|
||||||
if domain.UserId > 0 {
|
if domain.UserId > 0 {
|
||||||
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(domain.UserId))
|
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(domain.UserId), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -148,6 +149,7 @@ func (this *NSDomainService) ListEnabledNSDomains(ctx context.Context, req *pb.L
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
pbDomains := []*pb.NSDomain{}
|
pbDomains := []*pb.NSDomain{}
|
||||||
|
var cacheMap = maps.Map{}
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
// 集群
|
// 集群
|
||||||
cluster, err := models.SharedNSClusterDAO.FindEnabledNSCluster(tx, int64(domain.ClusterId))
|
cluster, err := models.SharedNSClusterDAO.FindEnabledNSCluster(tx, int64(domain.ClusterId))
|
||||||
@@ -161,7 +163,7 @@ func (this *NSDomainService) ListEnabledNSDomains(ctx context.Context, req *pb.L
|
|||||||
// 用户
|
// 用户
|
||||||
var pbUser *pb.User
|
var pbUser *pb.User
|
||||||
if domain.UserId > 0 {
|
if domain.UserId > 0 {
|
||||||
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(domain.UserId))
|
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(domain.UserId), cacheMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ func (this *UserService) FindEnabledUser(ctx context.Context, req *pb.FindEnable
|
|||||||
|
|
||||||
tx := this.NullTx()
|
tx := this.NullTx()
|
||||||
|
|
||||||
user, err := models.SharedUserDAO.FindEnabledUser(tx, req.UserId)
|
user, err := models.SharedUserDAO.FindEnabledUser(tx, req.UserId, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 计算日期之间的所有日期,格式为YYYYMMDD
|
// RangeDays 计算日期之间的所有日期,格式为YYYYMMDD
|
||||||
func RangeDays(dayFrom string, dayTo string) ([]string, error) {
|
func RangeDays(dayFrom string, dayTo string) ([]string, error) {
|
||||||
ok, err := regexp.MatchString(`^\d{8}$`, dayFrom)
|
ok, err := regexp.MatchString(`^\d{8}$`, dayFrom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -56,7 +57,56 @@ func RangeDays(dayFrom string, dayTo string) ([]string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算小时之间的所有小时,格式为YYYYMMDDHH
|
// RangeMonths 计算日期之间的所有月份,格式为YYYYMM
|
||||||
|
func RangeMonths(dayFrom string, dayTo string) ([]string, error) {
|
||||||
|
ok, err := regexp.MatchString(`^\d{8}$`, dayFrom)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("invalid 'dayFrom'")
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err = regexp.MatchString(`^\d{8}$`, dayTo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("invalid 'dayTo'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if dayFrom > dayTo {
|
||||||
|
dayFrom, dayTo = dayTo, dayFrom
|
||||||
|
}
|
||||||
|
|
||||||
|
result := []string{dayFrom[:6]}
|
||||||
|
|
||||||
|
year := types.Int(dayFrom[:4])
|
||||||
|
month := types.Int(dayFrom[4:6])
|
||||||
|
day := types.Int(dayFrom[6:])
|
||||||
|
t := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local)
|
||||||
|
for {
|
||||||
|
t = t.AddDate(0, 0, 20)
|
||||||
|
newDay := timeutil.Format("Ymd", t)
|
||||||
|
if newDay <= dayTo {
|
||||||
|
var monthString = newDay[:6]
|
||||||
|
if !lists.ContainsString(result, monthString) {
|
||||||
|
result = append(result, monthString)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var endMonth = dayTo[:6]
|
||||||
|
if !lists.ContainsString(result, endMonth) {
|
||||||
|
result = append(result, endMonth)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RangeHours 计算小时之间的所有小时,格式为YYYYMMDDHH
|
||||||
func RangeHours(hourFrom string, hourTo string) ([]string, error) {
|
func RangeHours(hourFrom string, hourTo string) ([]string, error) {
|
||||||
ok, err := regexp.MatchString(`^\d{10}$`, hourFrom)
|
ok, err := regexp.MatchString(`^\d{10}$`, hourFrom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ func TestRangeDays(t *testing.T) {
|
|||||||
t.Log(days)
|
t.Log(days)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRangeMonth(t *testing.T) {
|
||||||
|
days, err := RangeMonths("20200101", "20210115")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(days)
|
||||||
|
}
|
||||||
|
|
||||||
func TestRangeHours(t *testing.T) {
|
func TestRangeHours(t *testing.T) {
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user