后台面板
This commit is contained in:
210
app/main/api/internal/service/adminPromotionLinkStatsService.go
Normal file
210
app/main/api/internal/service/adminPromotionLinkStatsService.go
Normal file
@@ -0,0 +1,210 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"qnc-server/app/main/model"
|
||||
"qnc-server/common/xerr"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AdminPromotionLinkStatsService struct {
|
||||
logx.Logger
|
||||
AdminPromotionLinkModel model.AdminPromotionLinkModel
|
||||
AdminPromotionLinkStatsTotalModel model.AdminPromotionLinkStatsTotalModel
|
||||
AdminPromotionLinkStatsHistoryModel model.AdminPromotionLinkStatsHistoryModel
|
||||
}
|
||||
|
||||
func NewAdminPromotionLinkStatsService(
|
||||
AdminPromotionLinkModel model.AdminPromotionLinkModel,
|
||||
AdminPromotionLinkStatsTotalModel model.AdminPromotionLinkStatsTotalModel,
|
||||
AdminPromotionLinkStatsHistoryModel model.AdminPromotionLinkStatsHistoryModel,
|
||||
) *AdminPromotionLinkStatsService {
|
||||
return &AdminPromotionLinkStatsService{
|
||||
Logger: logx.WithContext(context.Background()),
|
||||
AdminPromotionLinkModel: AdminPromotionLinkModel,
|
||||
AdminPromotionLinkStatsTotalModel: AdminPromotionLinkStatsTotalModel,
|
||||
AdminPromotionLinkStatsHistoryModel: AdminPromotionLinkStatsHistoryModel,
|
||||
}
|
||||
}
|
||||
|
||||
// ensureTotalStats 确保总统计记录存在,如果不存在则创建
|
||||
func (s *AdminPromotionLinkStatsService) ensureTotalStats(ctx context.Context, session sqlx.Session, linkId int64) (*model.AdminPromotionLinkStatsTotal, error) {
|
||||
totalStats, err := s.AdminPromotionLinkStatsTotalModel.FindOneByLinkId(ctx, linkId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
// 如果记录不存在,创建新记录
|
||||
totalStats = &model.AdminPromotionLinkStatsTotal{
|
||||
LinkId: linkId,
|
||||
ClickCount: 0,
|
||||
PayCount: 0,
|
||||
PayAmount: 0,
|
||||
}
|
||||
_, err = s.AdminPromotionLinkStatsTotalModel.Insert(ctx, session, totalStats)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建总统计记录失败: %+v", err)
|
||||
}
|
||||
// 重新获取创建后的记录
|
||||
totalStats, err = s.AdminPromotionLinkStatsTotalModel.FindOneByLinkId(ctx, linkId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取新创建的总统计记录失败: %+v", err)
|
||||
}
|
||||
} else {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询总统计失败: %+v", err)
|
||||
}
|
||||
}
|
||||
return totalStats, nil
|
||||
}
|
||||
|
||||
// ensureHistoryStats 确保历史统计记录存在,如果不存在则创建
|
||||
func (s *AdminPromotionLinkStatsService) ensureHistoryStats(ctx context.Context, session sqlx.Session, linkId int64, today time.Time) (*model.AdminPromotionLinkStatsHistory, error) {
|
||||
historyStats, err := s.AdminPromotionLinkStatsHistoryModel.FindOneByLinkIdStatsDate(ctx, linkId, today)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
// 如果记录不存在,创建新记录
|
||||
historyStats = &model.AdminPromotionLinkStatsHistory{
|
||||
LinkId: linkId,
|
||||
StatsDate: today,
|
||||
ClickCount: 0,
|
||||
PayCount: 0,
|
||||
PayAmount: 0,
|
||||
}
|
||||
_, err = s.AdminPromotionLinkStatsHistoryModel.Insert(ctx, session, historyStats)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建今日统计记录失败: %+v", err)
|
||||
}
|
||||
// 重新获取创建后的记录
|
||||
historyStats, err = s.AdminPromotionLinkStatsHistoryModel.FindOneByLinkIdStatsDate(ctx, linkId, today)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取新创建的今日统计记录失败: %+v", err)
|
||||
}
|
||||
} else {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询今日统计记录失败: %+v", err)
|
||||
}
|
||||
}
|
||||
return historyStats, nil
|
||||
}
|
||||
|
||||
// UpdateLinkStats 更新推广链接统计
|
||||
func (s *AdminPromotionLinkStatsService) UpdateLinkStats(ctx context.Context, linkId int64) error {
|
||||
return s.AdminPromotionLinkStatsTotalModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 确保总统计记录存在
|
||||
totalStats, err := s.ensureTotalStats(ctx, session, linkId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新总统计
|
||||
totalStats.ClickCount++
|
||||
totalStats.LastClickTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||
err = s.AdminPromotionLinkStatsTotalModel.UpdateWithVersion(ctx, session, totalStats)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新总统计失败: %+v", err)
|
||||
}
|
||||
|
||||
// 确保历史统计记录存在
|
||||
now := time.Now()
|
||||
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
|
||||
historyStats, err := s.ensureHistoryStats(ctx, session, linkId, today)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新历史统计
|
||||
historyStats.ClickCount++
|
||||
historyStats.LastClickTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||
err = s.AdminPromotionLinkStatsHistoryModel.UpdateWithVersion(ctx, session, historyStats)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新历史统计失败: %+v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// UpdatePaymentStats 更新付费统计
|
||||
func (s *AdminPromotionLinkStatsService) UpdatePaymentStats(ctx context.Context, linkId int64, amount float64) error {
|
||||
return s.AdminPromotionLinkStatsTotalModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 确保总统计记录存在
|
||||
totalStats, err := s.ensureTotalStats(ctx, session, linkId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新总统计
|
||||
totalStats.PayCount++
|
||||
totalStats.PayAmount += amount
|
||||
totalStats.LastPayTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||
err = s.AdminPromotionLinkStatsTotalModel.UpdateWithVersion(ctx, session, totalStats)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新总统计失败: %+v", err)
|
||||
}
|
||||
|
||||
// 确保历史统计记录存在
|
||||
now := time.Now()
|
||||
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
|
||||
historyStats, err := s.ensureHistoryStats(ctx, session, linkId, today)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新历史统计
|
||||
historyStats.PayCount++
|
||||
historyStats.PayAmount += amount
|
||||
historyStats.LastPayTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||
err = s.AdminPromotionLinkStatsHistoryModel.UpdateWithVersion(ctx, session, historyStats)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新历史统计失败: %+v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// CreateLinkStats 创建新的推广链接统计记录
|
||||
func (s *AdminPromotionLinkStatsService) CreateLinkStats(ctx context.Context, linkId int64) error {
|
||||
return s.AdminPromotionLinkStatsTotalModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 检查总统计记录是否已存在
|
||||
_, err := s.AdminPromotionLinkStatsTotalModel.FindOneByLinkId(ctx, linkId)
|
||||
if err == nil {
|
||||
// 记录已存在,不需要创建
|
||||
return nil
|
||||
}
|
||||
if err != model.ErrNotFound {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询总统计记录失败: %+v", err)
|
||||
}
|
||||
|
||||
// 创建总统计记录
|
||||
totalStats := &model.AdminPromotionLinkStatsTotal{
|
||||
LinkId: linkId,
|
||||
ClickCount: 0,
|
||||
PayCount: 0,
|
||||
PayAmount: 0,
|
||||
}
|
||||
_, err = s.AdminPromotionLinkStatsTotalModel.Insert(ctx, session, totalStats)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建总统计记录失败: %+v", err)
|
||||
}
|
||||
|
||||
// 创建今日历史统计记录
|
||||
now := time.Now()
|
||||
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
|
||||
historyStats := &model.AdminPromotionLinkStatsHistory{
|
||||
LinkId: linkId,
|
||||
StatsDate: today,
|
||||
ClickCount: 0,
|
||||
PayCount: 0,
|
||||
PayAmount: 0,
|
||||
}
|
||||
_, err = s.AdminPromotionLinkStatsHistoryModel.Insert(ctx, session, historyStats)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建历史统计记录失败: %+v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -2,11 +2,13 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/app/user/model"
|
||||
"qnc-server/app/main/api/internal/config"
|
||||
"qnc-server/app/main/api/internal/types"
|
||||
"qnc-server/app/main/model"
|
||||
"qnc-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
@@ -28,6 +30,7 @@ type AgentService struct {
|
||||
AgentPlatformDeductionModel model.AgentPlatformDeductionModel
|
||||
AgentActiveStatModel model.AgentActiveStatModel
|
||||
AgentWithdrawalModel model.AgentWithdrawalModel
|
||||
AsynqService *AsynqService
|
||||
}
|
||||
|
||||
func NewAgentService(c config.Config, agentModel model.AgentModel, agentAuditModel model.AgentAuditModel,
|
||||
@@ -37,7 +40,7 @@ func NewAgentService(c config.Config, agentModel model.AgentModel, agentAuditMod
|
||||
agentMembershipRechargeOrderModel model.AgentMembershipRechargeOrderModel,
|
||||
agentMembershipUserConfigModel model.AgentMembershipUserConfigModel,
|
||||
agentProductConfigModel model.AgentProductConfigModel, agentPlatformDeductionModel model.AgentPlatformDeductionModel,
|
||||
agentActiveStatModel model.AgentActiveStatModel, agentWithdrawalModel model.AgentWithdrawalModel) *AgentService {
|
||||
agentActiveStatModel model.AgentActiveStatModel, asynqService *AsynqService, agentWithdrawalModel model.AgentWithdrawalModel) *AgentService {
|
||||
|
||||
return &AgentService{
|
||||
config: c,
|
||||
@@ -57,6 +60,7 @@ func NewAgentService(c config.Config, agentModel model.AgentModel, agentAuditMod
|
||||
AgentPlatformDeductionModel: agentPlatformDeductionModel,
|
||||
AgentActiveStatModel: agentActiveStatModel,
|
||||
AgentWithdrawalModel: agentWithdrawalModel,
|
||||
AsynqService: asynqService,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,12 +138,18 @@ func (l *AgentService) AgentProcess(ctx context.Context, order *model.Order) err
|
||||
return findAgentWalletModelErr
|
||||
}
|
||||
|
||||
ancestorWallet.Balance += ancestorCommissionAmount
|
||||
ancestorWallet.FrozenBalance += ancestorCommissionAmount
|
||||
ancestorWallet.TotalEarnings += ancestorCommissionAmount
|
||||
updateErr := l.AgentWalletModel.UpdateWithVersion(transCtx, session, ancestorWallet)
|
||||
if updateErr != nil {
|
||||
return updateErr
|
||||
}
|
||||
// 发送解冻任务
|
||||
err := l.AsynqService.SendUnfreezeAgentBalanceTask(AncestorId, order.Id, ancestorCommissionAmount)
|
||||
if err != nil {
|
||||
logx.Errorf("创建解冻任务失败: %v, 代理ID: %d, 订单号: %d", err, AncestorId, order.Id)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +177,9 @@ func (l *AgentService) AgentCommission(ctx context.Context, agentID int64, order
|
||||
}
|
||||
// 推广人最终获得代理佣金
|
||||
finalCommission := order.Amount - deductedAmount
|
||||
agentWalletModel.Balance += finalCommission
|
||||
|
||||
// 更新冻结余额而不是直接更新余额
|
||||
agentWalletModel.FrozenBalance += finalCommission
|
||||
agentWalletModel.TotalEarnings += finalCommission
|
||||
|
||||
agentCommission := model.AgentCommission{
|
||||
@@ -185,6 +197,19 @@ func (l *AgentService) AgentCommission(ctx context.Context, agentID int64, order
|
||||
if updateAgentWalletErr != nil {
|
||||
return updateAgentWalletErr
|
||||
}
|
||||
// 创建24小时后解冻任务
|
||||
unfreezePayload := types.UnfreezeAgentBalancePayload{
|
||||
AgentID: agentID,
|
||||
OrderID: order.Id,
|
||||
Amount: finalCommission,
|
||||
}
|
||||
|
||||
// 发送解冻任务
|
||||
err := l.AsynqService.SendUnfreezeAgentBalanceTask(unfreezePayload.AgentID, unfreezePayload.OrderID, unfreezePayload.Amount)
|
||||
if err != nil {
|
||||
logx.Errorf("创建解冻任务失败: %v, 代理ID: %d, 订单号: %d", err, agentID, order.Id)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/app/main/api/internal/config"
|
||||
"qnc-server/pkg/lzkit/lzUtils"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/app/user/model"
|
||||
"qnc-server/app/main/api/internal/config"
|
||||
"qnc-server/app/main/model"
|
||||
"qnc-server/pkg/lzkit/crypto"
|
||||
"qnc-server/pkg/lzkit/lzUtils"
|
||||
"sort"
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/app/main/api/internal/config"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@ package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
"qnc-server/app/main/api/internal/config"
|
||||
"qnc-server/app/main/api/internal/types"
|
||||
"time"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
@@ -58,3 +59,43 @@ func (s *AsynqService) SendQueryTask(orderID int64) error {
|
||||
logx.Infof("发送异步任务成功,任务ID: %s, 队列: %s, 订单号: %d", info.ID, info.Queue, orderID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendUnfreezeAgentBalanceTask 发送解冻代理金额的延迟任务
|
||||
func (s *AsynqService) SendUnfreezeAgentBalanceTask(agentID, orderID int64, amount float64) error {
|
||||
// 准备任务的 payload
|
||||
payload := types.UnfreezeAgentBalancePayload{
|
||||
AgentID: agentID,
|
||||
OrderID: orderID,
|
||||
Amount: amount,
|
||||
FreezeTime: time.Now().Unix(),
|
||||
}
|
||||
|
||||
payloadBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
logx.Errorf("发送解冻代理金额任务失败 (无法编码 payload): %v, 代理ID: %d, 订单号: %d", err, agentID, orderID)
|
||||
return err
|
||||
}
|
||||
|
||||
// 设置任务选项
|
||||
options := []asynq.Option{
|
||||
asynq.MaxRetry(3), // 最大重试3次
|
||||
asynq.ProcessIn(24 * time.Hour), // 24小时后执行
|
||||
asynq.Timeout(5 * time.Minute), // 任务超时时间
|
||||
asynq.Retention(24 * time.Hour), // 任务结果保留时间
|
||||
asynq.Queue("agent_balance"), // 使用专门的队列
|
||||
}
|
||||
|
||||
// 创建任务
|
||||
task := asynq.NewTask(types.MsgDelayedTask, payloadBytes, options...)
|
||||
|
||||
// 将任务加入队列
|
||||
info, err := s.client.Enqueue(task)
|
||||
if err != nil {
|
||||
logx.Errorf("发送解冻代理金额任务失败 (加入队列失败): %v, 代理ID: %d, 订单号: %d", err, agentID, orderID)
|
||||
return err
|
||||
}
|
||||
|
||||
logx.Infof("发送解冻代理金额任务成功,任务ID: %s, 队列: %s, 代理ID: %d, 订单号: %d, 金额: %.2f",
|
||||
info.ID, info.Queue, agentID, orderID, amount)
|
||||
return nil
|
||||
}
|
||||
|
||||
47
app/main/api/internal/service/dictService.go
Normal file
47
app/main/api/internal/service/dictService.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"qnc-server/app/main/model"
|
||||
)
|
||||
|
||||
type DictService struct {
|
||||
adminDictTypeModel model.AdminDictTypeModel
|
||||
adminDictDataModel model.AdminDictDataModel
|
||||
}
|
||||
|
||||
func NewDictService(adminDictTypeModel model.AdminDictTypeModel, adminDictDataModel model.AdminDictDataModel) *DictService {
|
||||
return &DictService{adminDictTypeModel: adminDictTypeModel, adminDictDataModel: adminDictDataModel}
|
||||
}
|
||||
func (s *DictService) GetDictLabel(ctx context.Context, dictType string, dictValue int64) (string, error) {
|
||||
dictTypeModel, err := s.adminDictTypeModel.FindOneByDictType(ctx, dictType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if dictTypeModel.Status != 1 {
|
||||
return "", errors.New("字典类型未启用")
|
||||
}
|
||||
dictData, err := s.adminDictDataModel.FindOneByDictTypeDictValue(ctx, dictTypeModel.DictType, dictValue)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if dictData.Status != 1 {
|
||||
return "", errors.New("字典数据未启用")
|
||||
}
|
||||
return dictData.DictLabel, nil
|
||||
}
|
||||
func (s *DictService) GetDictValue(ctx context.Context, dictType string, dictLabel string) (int64, error) {
|
||||
dictTypeModel, err := s.adminDictTypeModel.FindOneByDictType(ctx, dictType)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if dictTypeModel.Status != 1 {
|
||||
return 0, errors.New("字典类型未启用")
|
||||
}
|
||||
dictData, err := s.adminDictDataModel.FindOneByDictTypeDictLabel(ctx, dictTypeModel.DictType, dictLabel)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return dictData.DictValue, nil
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"qnc-server/app/user/model"
|
||||
"qnc-server/app/main/model"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/app/main/api/internal/config"
|
||||
"qnc-server/pkg/lzkit/crypto"
|
||||
"strings"
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/app/user/model"
|
||||
"qnc-server/app/main/api/internal/config"
|
||||
"qnc-server/app/main/model"
|
||||
"qnc-server/common/ctxdata"
|
||||
"qnc-server/pkg/lzkit/lzUtils"
|
||||
"strconv"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/app/main/api/internal/config"
|
||||
"qnc-server/pkg/lzkit/crypto"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/app/main/api/internal/config"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user