temp
This commit is contained in:
@@ -130,7 +130,8 @@ func (db *DB) GetStats() (map[string]interface{}, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BeginTx 开始事务
|
||||
// BeginTx 开始事务(已废弃,请使用shared/database.TransactionManager)
|
||||
// @deprecated 请使用 shared/database.TransactionManager
|
||||
func (db *DB) BeginTx() *gorm.DB {
|
||||
return db.DB.Begin()
|
||||
}
|
||||
@@ -153,47 +154,5 @@ func (db *DB) WithContext(ctx interface{}) *gorm.DB {
|
||||
return db.DB
|
||||
}
|
||||
|
||||
// 事务包装器
|
||||
type TxWrapper struct {
|
||||
tx *gorm.DB
|
||||
}
|
||||
|
||||
// NewTxWrapper 创建事务包装器
|
||||
func (db *DB) NewTxWrapper() *TxWrapper {
|
||||
return &TxWrapper{
|
||||
tx: db.BeginTx(),
|
||||
}
|
||||
}
|
||||
|
||||
// Commit 提交事务
|
||||
func (tx *TxWrapper) Commit() error {
|
||||
return tx.tx.Commit().Error
|
||||
}
|
||||
|
||||
// Rollback 回滚事务
|
||||
func (tx *TxWrapper) Rollback() error {
|
||||
return tx.tx.Rollback().Error
|
||||
}
|
||||
|
||||
// GetDB 获取事务数据库实例
|
||||
func (tx *TxWrapper) GetDB() *gorm.DB {
|
||||
return tx.tx
|
||||
}
|
||||
|
||||
// WithTx 在事务中执行函数
|
||||
func (db *DB) WithTx(fn func(*gorm.DB) error) error {
|
||||
tx := db.BeginTx()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := fn(tx); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit().Error
|
||||
}
|
||||
// 注意:事务相关功能已迁移到 shared/database.TransactionManager
|
||||
// 请使用 TransactionManager 进行事务管理
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/admin/entities"
|
||||
"tyapi-server/internal/domains/admin/repositories"
|
||||
"tyapi-server/internal/domains/admin/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// GormAdminLoginLogRepository 管理员登录日志GORM仓储实现
|
||||
type GormAdminLoginLogRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.AdminLoginLogRepository = (*GormAdminLoginLogRepository)(nil)
|
||||
|
||||
// NewGormAdminLoginLogRepository 创建管理员登录日志GORM仓储
|
||||
func NewGormAdminLoginLogRepository(db *gorm.DB, logger *zap.Logger) repositories.AdminLoginLogRepository {
|
||||
return &GormAdminLoginLogRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建登录日志
|
||||
func (r *GormAdminLoginLogRepository) Create(ctx context.Context, log entities.AdminLoginLog) (entities.AdminLoginLog, error) {
|
||||
r.logger.Info("创建管理员登录日志", zap.String("admin_id", log.AdminID))
|
||||
err := r.db.WithContext(ctx).Create(&log).Error
|
||||
return log, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取登录日志
|
||||
func (r *GormAdminLoginLogRepository) GetByID(ctx context.Context, id string) (entities.AdminLoginLog, error) {
|
||||
var log entities.AdminLoginLog
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&log).Error
|
||||
return log, err
|
||||
}
|
||||
|
||||
// Update 更新登录日志
|
||||
func (r *GormAdminLoginLogRepository) Update(ctx context.Context, log entities.AdminLoginLog) error {
|
||||
r.logger.Info("更新管理员登录日志", zap.String("id", log.ID))
|
||||
return r.db.WithContext(ctx).Save(&log).Error
|
||||
}
|
||||
|
||||
// Delete 删除登录日志
|
||||
func (r *GormAdminLoginLogRepository) Delete(ctx context.Context, id string) error {
|
||||
r.logger.Info("删除管理员登录日志", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.AdminLoginLog{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// SoftDelete 软删除登录日志
|
||||
func (r *GormAdminLoginLogRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
r.logger.Info("软删除管理员登录日志", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.AdminLoginLog{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// Restore 恢复登录日志
|
||||
func (r *GormAdminLoginLogRepository) Restore(ctx context.Context, id string) error {
|
||||
r.logger.Info("恢复管理员登录日志", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Unscoped().Model(&entities.AdminLoginLog{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
||||
}
|
||||
|
||||
// Count 统计登录日志数量
|
||||
func (r *GormAdminLoginLogRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.AdminLoginLog{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("admin_id LIKE ? OR ip_address LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
return count, query.Count(&count).Error
|
||||
}
|
||||
|
||||
// Exists 检查登录日志是否存在
|
||||
func (r *GormAdminLoginLogRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.AdminLoginLog{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建登录日志
|
||||
func (r *GormAdminLoginLogRepository) CreateBatch(ctx context.Context, logs []entities.AdminLoginLog) error {
|
||||
r.logger.Info("批量创建管理员登录日志", zap.Int("count", len(logs)))
|
||||
return r.db.WithContext(ctx).Create(&logs).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取登录日志
|
||||
func (r *GormAdminLoginLogRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.AdminLoginLog, error) {
|
||||
var logs []entities.AdminLoginLog
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&logs).Error
|
||||
return logs, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新登录日志
|
||||
func (r *GormAdminLoginLogRepository) UpdateBatch(ctx context.Context, logs []entities.AdminLoginLog) error {
|
||||
r.logger.Info("批量更新管理员登录日志", zap.Int("count", len(logs)))
|
||||
return r.db.WithContext(ctx).Save(&logs).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除登录日志
|
||||
func (r *GormAdminLoginLogRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除管理员登录日志", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.AdminLoginLog{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取登录日志列表
|
||||
func (r *GormAdminLoginLogRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.AdminLoginLog, error) {
|
||||
var logs []entities.AdminLoginLog
|
||||
query := r.db.WithContext(ctx).Model(&entities.AdminLoginLog{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("admin_id LIKE ? OR ip_address LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
return logs, query.Find(&logs).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormAdminLoginLogRepository) WithTx(tx interface{}) interfaces.Repository[entities.AdminLoginLog] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormAdminLoginLogRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// ListLogs 获取登录日志列表(带分页和筛选)
|
||||
func (r *GormAdminLoginLogRepository) ListLogs(ctx context.Context, query *queries.ListAdminLoginLogQuery) ([]*entities.AdminLoginLog, int64, error) {
|
||||
var logs []entities.AdminLoginLog
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.AdminLoginLog{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.AdminID != "" {
|
||||
dbQuery = dbQuery.Where("admin_id = ?", query.AdminID)
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&logs).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
logPtrs := make([]*entities.AdminLoginLog, len(logs))
|
||||
for i := range logs {
|
||||
logPtrs[i] = &logs[i]
|
||||
}
|
||||
|
||||
return logPtrs, total, nil
|
||||
}
|
||||
|
||||
// GetTodayLoginCount 获取今日登录次数
|
||||
func (r *GormAdminLoginLogRepository) GetTodayLoginCount(ctx context.Context) (int64, error) {
|
||||
var count int64
|
||||
today := time.Now().Truncate(24 * time.Hour)
|
||||
err := r.db.WithContext(ctx).Model(&entities.AdminLoginLog{}).Where("created_at >= ?", today).Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// GetLoginCountByAdmin 获取指定管理员在指定天数内的登录次数
|
||||
func (r *GormAdminLoginLogRepository) GetLoginCountByAdmin(ctx context.Context, adminID string, days int) (int64, error) {
|
||||
var count int64
|
||||
startDate := time.Now().AddDate(0, 0, -days)
|
||||
err := r.db.WithContext(ctx).Model(&entities.AdminLoginLog{}).Where("admin_id = ? AND created_at >= ?", adminID, startDate).Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/admin/entities"
|
||||
"tyapi-server/internal/domains/admin/repositories"
|
||||
"tyapi-server/internal/domains/admin/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// GormAdminOperationLogRepository 管理员操作日志GORM仓储实现
|
||||
type GormAdminOperationLogRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.AdminOperationLogRepository = (*GormAdminOperationLogRepository)(nil)
|
||||
|
||||
// NewGormAdminOperationLogRepository 创建管理员操作日志GORM仓储
|
||||
func NewGormAdminOperationLogRepository(db *gorm.DB, logger *zap.Logger) repositories.AdminOperationLogRepository {
|
||||
return &GormAdminOperationLogRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建操作日志
|
||||
func (r *GormAdminOperationLogRepository) Create(ctx context.Context, log entities.AdminOperationLog) (entities.AdminOperationLog, error) {
|
||||
r.logger.Info("创建管理员操作日志", zap.String("admin_id", log.AdminID), zap.String("action", log.Action))
|
||||
err := r.db.WithContext(ctx).Create(&log).Error
|
||||
return log, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取操作日志
|
||||
func (r *GormAdminOperationLogRepository) GetByID(ctx context.Context, id string) (entities.AdminOperationLog, error) {
|
||||
var log entities.AdminOperationLog
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&log).Error
|
||||
return log, err
|
||||
}
|
||||
|
||||
// Update 更新操作日志
|
||||
func (r *GormAdminOperationLogRepository) Update(ctx context.Context, log entities.AdminOperationLog) error {
|
||||
r.logger.Info("更新管理员操作日志", zap.String("id", log.ID))
|
||||
return r.db.WithContext(ctx).Save(&log).Error
|
||||
}
|
||||
|
||||
// Delete 删除操作日志
|
||||
func (r *GormAdminOperationLogRepository) Delete(ctx context.Context, id string) error {
|
||||
r.logger.Info("删除管理员操作日志", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.AdminOperationLog{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// SoftDelete 软删除操作日志
|
||||
func (r *GormAdminOperationLogRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
r.logger.Info("软删除管理员操作日志", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.AdminOperationLog{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// Restore 恢复操作日志
|
||||
func (r *GormAdminOperationLogRepository) Restore(ctx context.Context, id string) error {
|
||||
r.logger.Info("恢复管理员操作日志", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Unscoped().Model(&entities.AdminOperationLog{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
||||
}
|
||||
|
||||
// Count 统计操作日志数量
|
||||
func (r *GormAdminOperationLogRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.AdminOperationLog{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("admin_id LIKE ? OR action LIKE ? OR module LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
return count, query.Count(&count).Error
|
||||
}
|
||||
|
||||
// Exists 检查操作日志是否存在
|
||||
func (r *GormAdminOperationLogRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.AdminOperationLog{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建操作日志
|
||||
func (r *GormAdminOperationLogRepository) CreateBatch(ctx context.Context, logs []entities.AdminOperationLog) error {
|
||||
r.logger.Info("批量创建管理员操作日志", zap.Int("count", len(logs)))
|
||||
return r.db.WithContext(ctx).Create(&logs).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取操作日志
|
||||
func (r *GormAdminOperationLogRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.AdminOperationLog, error) {
|
||||
var logs []entities.AdminOperationLog
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&logs).Error
|
||||
return logs, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新操作日志
|
||||
func (r *GormAdminOperationLogRepository) UpdateBatch(ctx context.Context, logs []entities.AdminOperationLog) error {
|
||||
r.logger.Info("批量更新管理员操作日志", zap.Int("count", len(logs)))
|
||||
return r.db.WithContext(ctx).Save(&logs).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除操作日志
|
||||
func (r *GormAdminOperationLogRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除管理员操作日志", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.AdminOperationLog{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取操作日志列表
|
||||
func (r *GormAdminOperationLogRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.AdminOperationLog, error) {
|
||||
var logs []entities.AdminOperationLog
|
||||
query := r.db.WithContext(ctx).Model(&entities.AdminOperationLog{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("admin_id LIKE ? OR action LIKE ? OR module LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
return logs, query.Find(&logs).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormAdminOperationLogRepository) WithTx(tx interface{}) interfaces.Repository[entities.AdminOperationLog] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormAdminOperationLogRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// ListLogs 获取操作日志列表(带分页和筛选)
|
||||
func (r *GormAdminOperationLogRepository) ListLogs(ctx context.Context, query *queries.ListAdminOperationLogQuery) ([]*entities.AdminOperationLog, int64, error) {
|
||||
var logs []entities.AdminOperationLog
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.AdminOperationLog{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.AdminID != "" {
|
||||
dbQuery = dbQuery.Where("admin_id = ?", query.AdminID)
|
||||
}
|
||||
if query.Module != "" {
|
||||
dbQuery = dbQuery.Where("module = ?", query.Module)
|
||||
}
|
||||
if query.Action != "" {
|
||||
dbQuery = dbQuery.Where("action = ?", query.Action)
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&logs).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
logPtrs := make([]*entities.AdminOperationLog, len(logs))
|
||||
for i := range logs {
|
||||
logPtrs[i] = &logs[i]
|
||||
}
|
||||
|
||||
return logPtrs, total, nil
|
||||
}
|
||||
|
||||
// GetTotalOperations 获取总操作数
|
||||
func (r *GormAdminOperationLogRepository) GetTotalOperations(ctx context.Context) (int64, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.AdminOperationLog{}).Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// GetOperationsByAdmin 获取指定管理员在指定天数内的操作数
|
||||
func (r *GormAdminOperationLogRepository) GetOperationsByAdmin(ctx context.Context, adminID string, days int) (int64, error) {
|
||||
var count int64
|
||||
startDate := time.Now().AddDate(0, 0, -days)
|
||||
err := r.db.WithContext(ctx).Model(&entities.AdminOperationLog{}).Where("admin_id = ? AND created_at >= ?", adminID, startDate).Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// BatchCreate 批量创建操作日志
|
||||
func (r *GormAdminOperationLogRepository) BatchCreate(ctx context.Context, logs []entities.AdminOperationLog) error {
|
||||
r.logger.Info("批量创建管理员操作日志", zap.Int("count", len(logs)))
|
||||
return r.db.WithContext(ctx).Create(&logs).Error
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/admin/entities"
|
||||
"tyapi-server/internal/domains/admin/repositories"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// GormAdminPermissionRepository 管理员权限GORM仓储实现
|
||||
type GormAdminPermissionRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.AdminPermissionRepository = (*GormAdminPermissionRepository)(nil)
|
||||
|
||||
// NewGormAdminPermissionRepository 创建管理员权限GORM仓储
|
||||
func NewGormAdminPermissionRepository(db *gorm.DB, logger *zap.Logger) repositories.AdminPermissionRepository {
|
||||
return &GormAdminPermissionRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建权限
|
||||
func (r *GormAdminPermissionRepository) Create(ctx context.Context, permission entities.AdminPermission) (entities.AdminPermission, error) {
|
||||
r.logger.Info("创建管理员权限", zap.String("code", permission.Code))
|
||||
err := r.db.WithContext(ctx).Create(&permission).Error
|
||||
return permission, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取权限
|
||||
func (r *GormAdminPermissionRepository) GetByID(ctx context.Context, id string) (entities.AdminPermission, error) {
|
||||
var permission entities.AdminPermission
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&permission).Error
|
||||
return permission, err
|
||||
}
|
||||
|
||||
// Update 更新权限
|
||||
func (r *GormAdminPermissionRepository) Update(ctx context.Context, permission entities.AdminPermission) error {
|
||||
r.logger.Info("更新管理员权限", zap.String("id", permission.ID))
|
||||
return r.db.WithContext(ctx).Save(&permission).Error
|
||||
}
|
||||
|
||||
// Delete 删除权限
|
||||
func (r *GormAdminPermissionRepository) Delete(ctx context.Context, id string) error {
|
||||
r.logger.Info("删除管理员权限", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.AdminPermission{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// SoftDelete 软删除权限
|
||||
func (r *GormAdminPermissionRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
r.logger.Info("软删除管理员权限", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.AdminPermission{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// Restore 恢复权限
|
||||
func (r *GormAdminPermissionRepository) Restore(ctx context.Context, id string) error {
|
||||
r.logger.Info("恢复管理员权限", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Unscoped().Model(&entities.AdminPermission{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
||||
}
|
||||
|
||||
// Count 统计权限数量
|
||||
func (r *GormAdminPermissionRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.AdminPermission{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("code LIKE ? OR name LIKE ? OR module LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
return count, query.Count(&count).Error
|
||||
}
|
||||
|
||||
// Exists 检查权限是否存在
|
||||
func (r *GormAdminPermissionRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.AdminPermission{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建权限
|
||||
func (r *GormAdminPermissionRepository) CreateBatch(ctx context.Context, permissions []entities.AdminPermission) error {
|
||||
r.logger.Info("批量创建管理员权限", zap.Int("count", len(permissions)))
|
||||
return r.db.WithContext(ctx).Create(&permissions).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取权限
|
||||
func (r *GormAdminPermissionRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.AdminPermission, error) {
|
||||
var permissions []entities.AdminPermission
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&permissions).Error
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新权限
|
||||
func (r *GormAdminPermissionRepository) UpdateBatch(ctx context.Context, permissions []entities.AdminPermission) error {
|
||||
r.logger.Info("批量更新管理员权限", zap.Int("count", len(permissions)))
|
||||
return r.db.WithContext(ctx).Save(&permissions).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除权限
|
||||
func (r *GormAdminPermissionRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除管理员权限", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.AdminPermission{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取权限列表
|
||||
func (r *GormAdminPermissionRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.AdminPermission, error) {
|
||||
var permissions []entities.AdminPermission
|
||||
query := r.db.WithContext(ctx).Model(&entities.AdminPermission{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("code LIKE ? OR name LIKE ? OR module LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
return permissions, query.Find(&permissions).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormAdminPermissionRepository) WithTx(tx interface{}) interfaces.Repository[entities.AdminPermission] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormAdminPermissionRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// FindByCode 根据权限代码查找权限
|
||||
func (r *GormAdminPermissionRepository) FindByCode(ctx context.Context, code string) (*entities.AdminPermission, error) {
|
||||
var permission entities.AdminPermission
|
||||
err := r.db.WithContext(ctx).Where("code = ?", code).First(&permission).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &permission, nil
|
||||
}
|
||||
|
||||
// FindByModule 根据模块查找权限
|
||||
func (r *GormAdminPermissionRepository) FindByModule(ctx context.Context, module string) ([]entities.AdminPermission, error) {
|
||||
var permissions []entities.AdminPermission
|
||||
err := r.db.WithContext(ctx).Where("module = ?", module).Find(&permissions).Error
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// ListActive 获取所有激活的权限
|
||||
func (r *GormAdminPermissionRepository) ListActive(ctx context.Context) ([]entities.AdminPermission, error) {
|
||||
var permissions []entities.AdminPermission
|
||||
err := r.db.WithContext(ctx).Where("is_active = ?", true).Find(&permissions).Error
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// GetPermissionsByRole 根据角色获取权限
|
||||
func (r *GormAdminPermissionRepository) GetPermissionsByRole(ctx context.Context, role entities.AdminRole) ([]entities.AdminPermission, error) {
|
||||
var permissions []entities.AdminPermission
|
||||
|
||||
query := r.db.WithContext(ctx).
|
||||
Joins("JOIN admin_role_permissions ON admin_permissions.id = admin_role_permissions.permission_id").
|
||||
Where("admin_role_permissions.role = ? AND admin_permissions.is_active = ?", role, true)
|
||||
|
||||
return permissions, query.Find(&permissions).Error
|
||||
}
|
||||
|
||||
// AssignPermissionsToRole 为角色分配权限
|
||||
func (r *GormAdminPermissionRepository) AssignPermissionsToRole(ctx context.Context, role entities.AdminRole, permissionIDs []string) error {
|
||||
// 先删除现有权限
|
||||
if err := r.db.WithContext(ctx).Where("role = ?", role).Delete(&entities.AdminRolePermission{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 批量插入新权限
|
||||
var rolePermissions []entities.AdminRolePermission
|
||||
for _, permissionID := range permissionIDs {
|
||||
rolePermissions = append(rolePermissions, entities.AdminRolePermission{
|
||||
Role: role,
|
||||
PermissionID: permissionID,
|
||||
})
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Create(&rolePermissions).Error
|
||||
}
|
||||
|
||||
// RemovePermissionsFromRole 从角色移除权限
|
||||
func (r *GormAdminPermissionRepository) RemovePermissionsFromRole(ctx context.Context, role entities.AdminRole, permissionIDs []string) error {
|
||||
return r.db.WithContext(ctx).Where("role = ? AND permission_id IN ?", role, permissionIDs).Delete(&entities.AdminRolePermission{}).Error
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/admin/entities"
|
||||
"tyapi-server/internal/domains/admin/repositories"
|
||||
"tyapi-server/internal/domains/admin/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// GormAdminRepository 管理员GORM仓储实现
|
||||
type GormAdminRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.AdminRepository = (*GormAdminRepository)(nil)
|
||||
|
||||
// NewGormAdminRepository 创建管理员GORM仓储
|
||||
func NewGormAdminRepository(db *gorm.DB, logger *zap.Logger) *GormAdminRepository {
|
||||
return &GormAdminRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建管理员
|
||||
func (r *GormAdminRepository) Create(ctx context.Context, admin entities.Admin) (entities.Admin, error) {
|
||||
r.logger.Info("创建管理员", zap.String("username", admin.Username))
|
||||
err := r.db.WithContext(ctx).Create(&admin).Error
|
||||
return admin, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取管理员
|
||||
func (r *GormAdminRepository) GetByID(ctx context.Context, id string) (entities.Admin, error) {
|
||||
var admin entities.Admin
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&admin).Error
|
||||
return admin, err
|
||||
}
|
||||
|
||||
// Update 更新管理员
|
||||
func (r *GormAdminRepository) Update(ctx context.Context, admin entities.Admin) error {
|
||||
r.logger.Info("更新管理员", zap.String("id", admin.ID))
|
||||
return r.db.WithContext(ctx).Save(&admin).Error
|
||||
}
|
||||
|
||||
// Delete 删除管理员
|
||||
func (r *GormAdminRepository) Delete(ctx context.Context, id string) error {
|
||||
r.logger.Info("删除管理员", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.Admin{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// SoftDelete 软删除管理员
|
||||
func (r *GormAdminRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
r.logger.Info("软删除管理员", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.Admin{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// Restore 恢复管理员
|
||||
func (r *GormAdminRepository) Restore(ctx context.Context, id string) error {
|
||||
r.logger.Info("恢复管理员", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Unscoped().Model(&entities.Admin{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
||||
}
|
||||
|
||||
// Count 统计管理员数量
|
||||
func (r *GormAdminRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.Admin{})
|
||||
|
||||
// 应用过滤条件
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
// 应用搜索条件
|
||||
if options.Search != "" {
|
||||
query = query.Where("username LIKE ? OR email LIKE ? OR real_name LIKE ?",
|
||||
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
return count, query.Count(&count).Error
|
||||
}
|
||||
|
||||
// Exists 检查管理员是否存在
|
||||
func (r *GormAdminRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.Admin{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建管理员
|
||||
func (r *GormAdminRepository) CreateBatch(ctx context.Context, admins []entities.Admin) error {
|
||||
r.logger.Info("批量创建管理员", zap.Int("count", len(admins)))
|
||||
return r.db.WithContext(ctx).Create(&admins).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取管理员
|
||||
func (r *GormAdminRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.Admin, error) {
|
||||
var admins []entities.Admin
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&admins).Error
|
||||
return admins, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新管理员
|
||||
func (r *GormAdminRepository) UpdateBatch(ctx context.Context, admins []entities.Admin) error {
|
||||
r.logger.Info("批量更新管理员", zap.Int("count", len(admins)))
|
||||
return r.db.WithContext(ctx).Save(&admins).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除管理员
|
||||
func (r *GormAdminRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除管理员", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.Admin{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取管理员列表
|
||||
func (r *GormAdminRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.Admin, error) {
|
||||
var admins []entities.Admin
|
||||
query := r.db.WithContext(ctx).Model(&entities.Admin{})
|
||||
|
||||
// 应用过滤条件
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
// 应用搜索条件
|
||||
if options.Search != "" {
|
||||
query = query.Where("username LIKE ? OR email LIKE ? OR real_name LIKE ?",
|
||||
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
// 应用排序
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
return admins, query.Find(&admins).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormAdminRepository) WithTx(tx interface{}) interfaces.Repository[entities.Admin] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormAdminRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// FindByUsername 根据用户名查找管理员
|
||||
func (r *GormAdminRepository) FindByUsername(ctx context.Context, username string) (*entities.Admin, error) {
|
||||
var admin entities.Admin
|
||||
err := r.db.WithContext(ctx).Where("username = ?", username).First(&admin).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin, nil
|
||||
}
|
||||
|
||||
// FindByEmail 根据邮箱查找管理员
|
||||
func (r *GormAdminRepository) FindByEmail(ctx context.Context, email string) (*entities.Admin, error) {
|
||||
var admin entities.Admin
|
||||
err := r.db.WithContext(ctx).Where("email = ?", email).First(&admin).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin, nil
|
||||
}
|
||||
|
||||
// ListAdmins 获取管理员列表(带分页和筛选)
|
||||
func (r *GormAdminRepository) ListAdmins(ctx context.Context, query *queries.ListAdminsQuery) ([]*entities.Admin, int64, error) {
|
||||
var admins []entities.Admin
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.Admin{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.Username != "" {
|
||||
dbQuery = dbQuery.Where("username LIKE ?", "%"+query.Username+"%")
|
||||
}
|
||||
if query.Email != "" {
|
||||
dbQuery = dbQuery.Where("email LIKE ?", "%"+query.Email+"%")
|
||||
}
|
||||
if query.Role != "" {
|
||||
dbQuery = dbQuery.Where("role = ?", query.Role)
|
||||
}
|
||||
if query.IsActive != nil {
|
||||
dbQuery = dbQuery.Where("is_active = ?", *query.IsActive)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&admins).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
adminPtrs := make([]*entities.Admin, len(admins))
|
||||
for i := range admins {
|
||||
adminPtrs[i] = &admins[i]
|
||||
}
|
||||
|
||||
return adminPtrs, total, nil
|
||||
}
|
||||
|
||||
// GetStats 获取管理员统计信息
|
||||
func (r *GormAdminRepository) GetStats(ctx context.Context, query *queries.GetAdminInfoQuery) (*repositories.AdminStats, error) {
|
||||
var stats repositories.AdminStats
|
||||
|
||||
// 总管理员数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Admin{}).Count(&stats.TotalAdmins).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 激活管理员数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Admin{}).Where("is_active = ?", true).Count(&stats.ActiveAdmins).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 今日登录数
|
||||
today := time.Now().Truncate(24 * time.Hour)
|
||||
if err := r.db.WithContext(ctx).Model(&entities.AdminLoginLog{}).Where("created_at >= ?", today).Count(&stats.TodayLogins).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 总操作数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.AdminOperationLog{}).Count(&stats.TotalOperations).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &stats, nil
|
||||
}
|
||||
|
||||
// GetPermissionsByRole 根据角色获取权限
|
||||
func (r *GormAdminRepository) GetPermissionsByRole(ctx context.Context, role entities.AdminRole) ([]entities.AdminPermission, error) {
|
||||
var permissions []entities.AdminPermission
|
||||
|
||||
query := r.db.WithContext(ctx).
|
||||
Joins("JOIN admin_role_permissions ON admin_permissions.id = admin_role_permissions.permission_id").
|
||||
Where("admin_role_permissions.role = ? AND admin_permissions.is_active = ?", role, true)
|
||||
|
||||
return permissions, query.Find(&permissions).Error
|
||||
}
|
||||
|
||||
// UpdatePermissions 更新管理员权限
|
||||
func (r *GormAdminRepository) UpdatePermissions(ctx context.Context, adminID string, permissions []string) error {
|
||||
permissionsJSON, err := json.Marshal(permissions)
|
||||
if err != nil {
|
||||
return fmt.Errorf("序列化权限失败: %w", err)
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).
|
||||
Model(&entities.Admin{}).
|
||||
Where("id = ?", adminID).
|
||||
Update("permissions", string(permissionsJSON)).Error
|
||||
}
|
||||
|
||||
// UpdateLoginStats 更新登录统计
|
||||
func (r *GormAdminRepository) UpdateLoginStats(ctx context.Context, adminID string) error {
|
||||
return r.db.WithContext(ctx).
|
||||
Model(&entities.Admin{}).
|
||||
Where("id = ?", adminID).
|
||||
Updates(map[string]interface{}{
|
||||
"last_login_at": time.Now(),
|
||||
"login_count": gorm.Expr("login_count + 1"),
|
||||
}).Error
|
||||
}
|
||||
|
||||
// UpdateReviewStats 更新审核统计
|
||||
func (r *GormAdminRepository) UpdateReviewStats(ctx context.Context, adminID string, approved bool) error {
|
||||
updates := map[string]interface{}{
|
||||
"review_count": gorm.Expr("review_count + 1"),
|
||||
}
|
||||
|
||||
if approved {
|
||||
updates["approved_count"] = gorm.Expr("approved_count + 1")
|
||||
} else {
|
||||
updates["rejected_count"] = gorm.Expr("rejected_count + 1")
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).
|
||||
Model(&entities.Admin{}).
|
||||
Where("id = ?", adminID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
@@ -43,6 +44,26 @@ func (r *GormCertificationRepository) Create(ctx context.Context, cert entities.
|
||||
func (r *GormCertificationRepository) GetByID(ctx context.Context, id string) (entities.Certification, error) {
|
||||
var cert entities.Certification
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&cert).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.Certification{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.Certification{}, err
|
||||
}
|
||||
return cert, err
|
||||
}
|
||||
|
||||
// GetByAuthFlowID 根据认证流程ID获取认证申请
|
||||
func (r *GormCertificationRepository) GetByAuthFlowID(ctx context.Context, authFlowID string) (entities.Certification, error) {
|
||||
var cert entities.Certification
|
||||
err := r.db.WithContext(ctx).Where("auth_flow_id = ?", authFlowID).First(&cert).Error
|
||||
return cert, err
|
||||
}
|
||||
|
||||
// GetByEsignFlowID 根据签署流程ID获取认证申请
|
||||
func (r *GormCertificationRepository) GetByEsignFlowID(ctx context.Context, esignFlowID string) (entities.Certification, error) {
|
||||
var cert entities.Certification
|
||||
err := r.db.WithContext(ctx).Where("esign_flow_id = ?", esignFlowID).First(&cert).Error
|
||||
return cert, err
|
||||
}
|
||||
|
||||
@@ -179,9 +200,6 @@ func (r *GormCertificationRepository) ListCertifications(ctx context.Context, qu
|
||||
if query.Status != "" {
|
||||
dbQuery = dbQuery.Where("status = ?", query.Status)
|
||||
}
|
||||
if query.AdminID != "" {
|
||||
dbQuery = dbQuery.Where("admin_id = ?", query.AdminID)
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
@@ -189,8 +207,8 @@ func (r *GormCertificationRepository) ListCertifications(ctx context.Context, qu
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
if query.EnterpriseName != "" {
|
||||
dbQuery = dbQuery.Joins("JOIN enterprises ON certifications.enterprise_id = enterprises.id").
|
||||
Where("enterprises.enterprise_name LIKE ?", "%"+query.EnterpriseName+"%")
|
||||
// 简化企业名称查询,暂时不关联企业表
|
||||
dbQuery = dbQuery.Where("user_id IN (SELECT user_id FROM enterprise_infos WHERE company_name LIKE ?)", "%"+query.EnterpriseName+"%")
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
@@ -199,24 +217,26 @@ func (r *GormCertificationRepository) ListCertifications(ctx context.Context, qu
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
if query.Page > 0 && query.PageSize > 0 {
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
}
|
||||
|
||||
// 默认排序
|
||||
// 排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 查询数据
|
||||
// 执行查询
|
||||
if err := dbQuery.Find(&certs).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
certPtrs := make([]*entities.Certification, len(certs))
|
||||
var result []*entities.Certification
|
||||
for i := range certs {
|
||||
certPtrs[i] = &certs[i]
|
||||
result = append(result, &certs[i])
|
||||
}
|
||||
|
||||
return certPtrs, total, nil
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取认证申请
|
||||
@@ -224,6 +244,9 @@ func (r *GormCertificationRepository) GetByUserID(ctx context.Context, userID st
|
||||
var cert entities.Certification
|
||||
err := r.db.WithContext(ctx).Where("user_id = ?", userID).First(&cert).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &cert, nil
|
||||
@@ -237,82 +260,73 @@ func (r *GormCertificationRepository) GetByStatus(ctx context.Context, status st
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certPtrs := make([]*entities.Certification, len(certs))
|
||||
var result []*entities.Certification
|
||||
for i := range certs {
|
||||
certPtrs[i] = &certs[i]
|
||||
result = append(result, &certs[i])
|
||||
}
|
||||
|
||||
return certPtrs, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UpdateStatus 更新认证状态
|
||||
func (r *GormCertificationRepository) UpdateStatus(ctx context.Context, certificationID string, status string, adminID *string, notes string) error {
|
||||
func (r *GormCertificationRepository) UpdateStatus(ctx context.Context, certificationID string, status string) error {
|
||||
r.logger.Info("更新认证状态",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("status", status),
|
||||
)
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
"status": status,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
if adminID != nil {
|
||||
updates["admin_id"] = *adminID
|
||||
}
|
||||
|
||||
if notes != "" {
|
||||
updates["approval_notes"] = notes
|
||||
}
|
||||
|
||||
// 根据状态设置相应的时间戳
|
||||
// 根据状态更新时间戳
|
||||
switch status {
|
||||
case "INFO_SUBMITTED":
|
||||
case "info_submitted":
|
||||
updates["info_submitted_at"] = time.Now()
|
||||
case "FACE_VERIFIED":
|
||||
updates["face_verified_at"] = time.Now()
|
||||
case "CONTRACT_APPLIED":
|
||||
case "enterprise_verified":
|
||||
updates["enterprise_verified_at"] = time.Now()
|
||||
case "contract_applied":
|
||||
updates["contract_applied_at"] = time.Now()
|
||||
case "CONTRACT_APPROVED":
|
||||
updates["contract_approved_at"] = time.Now()
|
||||
case "CONTRACT_SIGNED":
|
||||
case "contract_signed":
|
||||
updates["contract_signed_at"] = time.Now()
|
||||
case "COMPLETED":
|
||||
case "completed":
|
||||
updates["completed_at"] = time.Now()
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).
|
||||
Model(&entities.Certification{}).
|
||||
return r.db.WithContext(ctx).Model(&entities.Certification{}).
|
||||
Where("id = ?", certificationID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// GetPendingCertifications 获取待审核的认证申请
|
||||
// GetPendingCertifications 获取待处理的认证申请
|
||||
func (r *GormCertificationRepository) GetPendingCertifications(ctx context.Context) ([]*entities.Certification, error) {
|
||||
return r.GetByStatus(ctx, "CONTRACT_PENDING")
|
||||
return r.GetByStatus(ctx, "pending")
|
||||
}
|
||||
|
||||
// GetStats 获取认证统计信息
|
||||
func (r *GormCertificationRepository) GetStats(ctx context.Context) (*repositories.CertificationStats, error) {
|
||||
var stats repositories.CertificationStats
|
||||
|
||||
// 总认证申请数
|
||||
// 总认证数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Count(&stats.TotalCertifications).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 待审核认证申请数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ?", "CONTRACT_PENDING").Count(&stats.PendingCertifications).Error; err != nil {
|
||||
// 待处理认证数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ?", "pending").Count(&stats.PendingCertifications).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 已完成认证申请数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ?", "COMPLETED").Count(&stats.CompletedCertifications).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 被拒绝认证申请数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ?", "REJECTED").Count(&stats.RejectedCertifications).Error; err != nil {
|
||||
// 已完成认证数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ?", "completed").Count(&stats.CompletedCertifications).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 今日提交数
|
||||
today := time.Now().Truncate(24 * time.Hour)
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("created_at >= ?", today).Count(&stats.TodaySubmissions).Error; err != nil {
|
||||
today := time.Now().Format("2006-01-02")
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).
|
||||
Where("DATE(created_at) = ?", today).
|
||||
Count(&stats.TodaySubmissions).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -323,29 +337,32 @@ func (r *GormCertificationRepository) GetStats(ctx context.Context) (*repositori
|
||||
func (r *GormCertificationRepository) GetStatsByDateRange(ctx context.Context, startDate, endDate string) (*repositories.CertificationStats, error) {
|
||||
var stats repositories.CertificationStats
|
||||
|
||||
// 总认证申请数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("created_at BETWEEN ? AND ?", startDate, endDate).Count(&stats.TotalCertifications).Error; err != nil {
|
||||
// 总认证数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).
|
||||
Where("created_at BETWEEN ? AND ?", startDate, endDate).
|
||||
Count(&stats.TotalCertifications).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 待审核认证申请数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ? AND created_at BETWEEN ? AND ?", "CONTRACT_PENDING", startDate, endDate).Count(&stats.PendingCertifications).Error; err != nil {
|
||||
// 待处理认证数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).
|
||||
Where("status = ? AND created_at BETWEEN ? AND ?", "pending", startDate, endDate).
|
||||
Count(&stats.PendingCertifications).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 已完成认证申请数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ? AND created_at BETWEEN ? AND ?", "COMPLETED", startDate, endDate).Count(&stats.CompletedCertifications).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 被拒绝认证申请数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ? AND created_at BETWEEN ? AND ?", "REJECTED", startDate, endDate).Count(&stats.RejectedCertifications).Error; err != nil {
|
||||
// 已完成认证数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).
|
||||
Where("status = ? AND created_at BETWEEN ? AND ?", "completed", startDate, endDate).
|
||||
Count(&stats.CompletedCertifications).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 今日提交数
|
||||
today := time.Now().Truncate(24 * time.Hour)
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("created_at >= ?", today).Count(&stats.TodaySubmissions).Error; err != nil {
|
||||
today := time.Now().Format("2006-01-02")
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).
|
||||
Where("DATE(created_at) = ?", today).
|
||||
Count(&stats.TodaySubmissions).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,422 +0,0 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/domains/certification/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// GormContractRecordRepository GORM合同记录仓储实现
|
||||
type GormContractRecordRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.ContractRecordRepository = (*GormContractRecordRepository)(nil)
|
||||
|
||||
// NewGormContractRecordRepository 创建GORM合同记录仓储
|
||||
func NewGormContractRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.ContractRecordRepository {
|
||||
return &GormContractRecordRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建合同记录
|
||||
func (r *GormContractRecordRepository) Create(ctx context.Context, record entities.ContractRecord) (entities.ContractRecord, error) {
|
||||
if err := r.db.WithContext(ctx).Create(&record).Error; err != nil {
|
||||
r.logger.Error("创建合同记录失败",
|
||||
zap.String("certification_id", record.CertificationID),
|
||||
zap.String("contract_type", record.ContractType),
|
||||
zap.Error(err),
|
||||
)
|
||||
return entities.ContractRecord{}, fmt.Errorf("创建合同记录失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("合同记录创建成功",
|
||||
zap.String("id", record.ID),
|
||||
zap.String("contract_type", record.ContractType),
|
||||
)
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取合同记录
|
||||
func (r *GormContractRecordRepository) GetByID(ctx context.Context, id string) (entities.ContractRecord, error) {
|
||||
var record entities.ContractRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).First(&record, "id = ?", id).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return entities.ContractRecord{}, fmt.Errorf("合同记录不存在")
|
||||
}
|
||||
r.logger.Error("获取合同记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return entities.ContractRecord{}, fmt.Errorf("获取合同记录失败: %w", err)
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// Update 更新合同记录
|
||||
func (r *GormContractRecordRepository) Update(ctx context.Context, record entities.ContractRecord) error {
|
||||
if err := r.db.WithContext(ctx).Save(&record).Error; err != nil {
|
||||
r.logger.Error("更新合同记录失败",
|
||||
zap.String("id", record.ID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("更新合同记录失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete 删除合同记录
|
||||
func (r *GormContractRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Delete(&entities.ContractRecord{}, "id = ?", id).Error; err != nil {
|
||||
r.logger.Error("删除合同记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("删除合同记录失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SoftDelete 软删除合同记录
|
||||
func (r *GormContractRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// Restore 恢复合同记录
|
||||
func (r *GormContractRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Unscoped().Model(&entities.ContractRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error; err != nil {
|
||||
r.logger.Error("恢复合同记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("恢复合同记录失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("合同记录恢复成功", zap.String("id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Count 统计合同记录数量
|
||||
func (r *GormContractRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.ContractRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("contract_type LIKE ? OR contract_name LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
return count, query.Count(&count).Error
|
||||
}
|
||||
|
||||
// Exists 检查合同记录是否存在
|
||||
func (r *GormContractRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.ContractRecord{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建合同记录
|
||||
func (r *GormContractRecordRepository) CreateBatch(ctx context.Context, records []entities.ContractRecord) error {
|
||||
r.logger.Info("批量创建合同记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Create(&records).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取合同记录
|
||||
func (r *GormContractRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.ContractRecord, error) {
|
||||
var records []entities.ContractRecord
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新合同记录
|
||||
func (r *GormContractRecordRepository) UpdateBatch(ctx context.Context, records []entities.ContractRecord) error {
|
||||
r.logger.Info("批量更新合同记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Save(&records).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除合同记录
|
||||
func (r *GormContractRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除合同记录", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.ContractRecord{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取合同记录列表
|
||||
func (r *GormContractRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.ContractRecord, error) {
|
||||
var records []entities.ContractRecord
|
||||
query := r.db.WithContext(ctx).Model(&entities.ContractRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("contract_type LIKE ? OR contract_name LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
return records, query.Find(&records).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormContractRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.ContractRecord] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormContractRecordRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// GetByCertificationID 根据认证申请ID获取合同记录列表
|
||||
func (r *GormContractRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) ([]*entities.ContractRecord, error) {
|
||||
var records []entities.ContractRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").Find(&records).Error; err != nil {
|
||||
r.logger.Error("根据认证申请ID获取合同记录失败",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, fmt.Errorf("获取合同记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.ContractRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, nil
|
||||
}
|
||||
|
||||
// GetLatestByCertificationID 根据认证申请ID获取最新的合同记录
|
||||
func (r *GormContractRecordRepository) GetLatestByCertificationID(ctx context.Context, certificationID string) (*entities.ContractRecord, error) {
|
||||
var record entities.ContractRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").First(&record).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("合同记录不存在")
|
||||
}
|
||||
r.logger.Error("根据认证申请ID获取最新合同记录失败",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, fmt.Errorf("获取合同记录失败: %w", err)
|
||||
}
|
||||
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// ListRecords 获取合同记录列表(带分页和筛选)
|
||||
func (r *GormContractRecordRepository) ListRecords(ctx context.Context, query *queries.ListContractRecordsQuery) ([]*entities.ContractRecord, int64, error) {
|
||||
var records []entities.ContractRecord
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.ContractRecord{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.CertificationID != "" {
|
||||
dbQuery = dbQuery.Where("certification_id = ?", query.CertificationID)
|
||||
}
|
||||
if query.UserID != "" {
|
||||
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
|
||||
}
|
||||
if query.Status != "" {
|
||||
dbQuery = dbQuery.Where("status = ?", query.Status)
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&records).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.ContractRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, total, nil
|
||||
}
|
||||
|
||||
// UpdateContractStatus 更新合同状态
|
||||
func (r *GormContractRecordRepository) UpdateContractStatus(ctx context.Context, recordID string, status string, adminID *string, notes string) error {
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
}
|
||||
|
||||
if adminID != nil {
|
||||
updates["admin_id"] = *adminID
|
||||
}
|
||||
|
||||
if notes != "" {
|
||||
updates["admin_notes"] = notes
|
||||
}
|
||||
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.ContractRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error; err != nil {
|
||||
r.logger.Error("更新合同状态失败",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("status", status),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("更新合同状态失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("合同状态更新成功",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("status", status),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取合同记录列表
|
||||
func (r *GormContractRecordRepository) GetByUserID(ctx context.Context, userID string, page, pageSize int) ([]*entities.ContractRecord, int, error) {
|
||||
var records []entities.ContractRecord
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.ContractRecord{}).Where("user_id = ?", userID)
|
||||
|
||||
// 获取总数
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
r.logger.Error("获取用户合同记录总数失败", zap.Error(err))
|
||||
return nil, 0, fmt.Errorf("获取合同记录总数失败: %w", err)
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (page - 1) * pageSize
|
||||
if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&records).Error; err != nil {
|
||||
r.logger.Error("获取用户合同记录列表失败", zap.Error(err))
|
||||
return nil, 0, fmt.Errorf("获取合同记录列表失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.ContractRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, int(total), nil
|
||||
}
|
||||
|
||||
// GetByStatus 根据状态获取合同记录列表
|
||||
func (r *GormContractRecordRepository) GetByStatus(ctx context.Context, status string, page, pageSize int) ([]*entities.ContractRecord, int, error) {
|
||||
var records []entities.ContractRecord
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.ContractRecord{}).Where("status = ?", status)
|
||||
|
||||
// 获取总数
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
r.logger.Error("根据状态获取合同记录总数失败", zap.Error(err))
|
||||
return nil, 0, fmt.Errorf("获取合同记录总数失败: %w", err)
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (page - 1) * pageSize
|
||||
if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&records).Error; err != nil {
|
||||
r.logger.Error("根据状态获取合同记录列表失败", zap.Error(err))
|
||||
return nil, 0, fmt.Errorf("获取合同记录列表失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.ContractRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, int(total), nil
|
||||
}
|
||||
|
||||
// GetPendingContracts 获取待审核的合同记录
|
||||
func (r *GormContractRecordRepository) GetPendingContracts(ctx context.Context, page, pageSize int) ([]*entities.ContractRecord, int, error) {
|
||||
return r.GetByStatus(ctx, "PENDING", page, pageSize)
|
||||
}
|
||||
|
||||
// GetExpiredSigningContracts 获取签署链接已过期的合同记录
|
||||
func (r *GormContractRecordRepository) GetExpiredSigningContracts(ctx context.Context, limit int) ([]*entities.ContractRecord, error) {
|
||||
var records []entities.ContractRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("expires_at < NOW() AND status = ?", "APPROVED").
|
||||
Limit(limit).
|
||||
Order("expires_at ASC").
|
||||
Find(&records).Error; err != nil {
|
||||
r.logger.Error("获取过期签署合同记录失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("获取过期签署合同记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.ContractRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, nil
|
||||
}
|
||||
|
||||
// GetExpiredContracts 获取已过期的合同记录(通用方法)
|
||||
func (r *GormContractRecordRepository) GetExpiredContracts(ctx context.Context, limit int) ([]*entities.ContractRecord, error) {
|
||||
return r.GetExpiredSigningContracts(ctx, limit)
|
||||
}
|
||||
@@ -0,0 +1,596 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/domains/certification/repositories/queries"
|
||||
"tyapi-server/internal/shared/database"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// ================ 常量定义 ================
|
||||
|
||||
const (
|
||||
// 表名常量
|
||||
EnterpriseInfoSubmitRecordsTable = "enterprise_info_submit_records"
|
||||
|
||||
// 缓存时间常量
|
||||
CacheTTLPrimaryQuery = 30 * time.Minute // 主键查询缓存时间
|
||||
CacheTTLBusinessQuery = 15 * time.Minute // 业务查询缓存时间
|
||||
CacheTTLUserQuery = 10 * time.Minute // 用户相关查询缓存时间
|
||||
CacheTTLSearchQuery = 2 * time.Minute // 搜索查询缓存时间
|
||||
CacheTTLActiveRecords = 5 * time.Minute // 活跃记录查询缓存时间
|
||||
CacheTTLWarmupLong = 30 * time.Minute // 预热长期缓存
|
||||
CacheTTLWarmupMedium = 15 * time.Minute // 预热中期缓存
|
||||
|
||||
// 缓存键模式常量
|
||||
CachePatternTable = "gorm_cache:enterprise_info_submit_records:*"
|
||||
CachePatternCertification = "enterprise_info:certification_id:*"
|
||||
CachePatternUser = "enterprise_info:user_id:*"
|
||||
|
||||
// 业务常量
|
||||
StatusActive = "active"
|
||||
StatusPending = "pending"
|
||||
)
|
||||
|
||||
// ================ Repository 实现 ================
|
||||
|
||||
// GormEnterpriseInfoSubmitRecordRepository 企业信息提交记录GORM仓储实现
|
||||
//
|
||||
// 特性说明:
|
||||
// - 基于 CachedBaseRepositoryImpl 实现自动缓存管理
|
||||
// - 支持多级缓存策略(主键查询30分钟,业务查询15分钟,搜索2分钟)
|
||||
// - 自动缓存失效:写操作时自动清理相关缓存
|
||||
// - 智能缓存选择:根据查询复杂度自动选择缓存策略
|
||||
// - 内置监控支持:提供缓存统计和性能监控
|
||||
type GormEnterpriseInfoSubmitRecordRepository struct {
|
||||
*database.CachedBaseRepositoryImpl
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.EnterpriseInfoSubmitRecordRepository = (*GormEnterpriseInfoSubmitRecordRepository)(nil)
|
||||
|
||||
// NewGormEnterpriseInfoSubmitRecordRepository 创建企业信息提交记录GORM仓储
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库连接实例
|
||||
// - logger: 日志记录器
|
||||
//
|
||||
// 返回:
|
||||
// - repositories.EnterpriseInfoSubmitRecordRepository: 仓储接口实现
|
||||
func NewGormEnterpriseInfoSubmitRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.EnterpriseInfoSubmitRecordRepository {
|
||||
return &GormEnterpriseInfoSubmitRecordRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, EnterpriseInfoSubmitRecordsTable),
|
||||
}
|
||||
}
|
||||
|
||||
// ================ Repository[T] 接口实现 ================
|
||||
|
||||
// Create 创建企业信息提交记录
|
||||
//
|
||||
// 业务说明:
|
||||
// - 创建新的企业信息提交记录
|
||||
// - 自动触发相关缓存失效
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - record: 要创建的记录实体
|
||||
//
|
||||
// 返回:
|
||||
// - entities.EnterpriseInfoSubmitRecord: 创建后的记录(包含生成的ID)
|
||||
// - error: 创建失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Create(ctx context.Context, record entities.EnterpriseInfoSubmitRecord) (entities.EnterpriseInfoSubmitRecord, error) {
|
||||
r.GetLogger().Info("创建企业信息提交记录",
|
||||
zap.String("user_id", record.UserID),
|
||||
zap.String("company_name", record.CompanyName))
|
||||
|
||||
err := r.CreateEntity(ctx, &record)
|
||||
return record, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取企业信息提交记录
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 使用智能主键查询,自动缓存30分钟
|
||||
// - 主键查询命中率高,适合长期缓存
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - id: 记录ID
|
||||
//
|
||||
// 返回:
|
||||
// - entities.EnterpriseInfoSubmitRecord: 查询到的记录
|
||||
// - error: 查询失败或记录不存在时的错误
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetByID(ctx context.Context, id string) (entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var record entities.EnterpriseInfoSubmitRecord
|
||||
err := r.SmartGetByID(ctx, id, &record)
|
||||
return record, err
|
||||
}
|
||||
|
||||
// Update 更新企业信息提交记录
|
||||
//
|
||||
// 缓存影响:
|
||||
// - GORM缓存插件会自动失效相关缓存
|
||||
// - 无需手动管理缓存一致性
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - record: 要更新的记录实体
|
||||
//
|
||||
// 返回:
|
||||
// - error: 更新失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Update(ctx context.Context, record entities.EnterpriseInfoSubmitRecord) error {
|
||||
r.GetLogger().Info("更新企业信息提交记录",
|
||||
zap.String("id", record.ID),
|
||||
zap.String("company_name", record.CompanyName))
|
||||
|
||||
return r.UpdateEntity(ctx, &record)
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) CreateBatch(ctx context.Context, records []entities.EnterpriseInfoSubmitRecord) error {
|
||||
r.GetLogger().Info("批量创建企业信息提交记录", zap.Int("count", len(records)))
|
||||
return r.CreateBatchEntity(ctx, &records)
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []entities.EnterpriseInfoSubmitRecord
|
||||
err := r.GetEntitiesByIDs(ctx, ids, &records)
|
||||
return records, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) UpdateBatch(ctx context.Context, records []entities.EnterpriseInfoSubmitRecord) error {
|
||||
r.GetLogger().Info("批量更新企业信息提交记录", zap.Int("count", len(records)))
|
||||
return r.UpdateBatchEntity(ctx, &records)
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.GetLogger().Info("批量删除企业信息提交记录", zap.Strings("ids", ids))
|
||||
return r.DeleteBatchEntity(ctx, ids, &entities.EnterpriseInfoSubmitRecord{})
|
||||
}
|
||||
|
||||
// List 获取企业信息提交记录列表
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 搜索查询:短期缓存2分钟(避免频繁数据库查询但保证实时性)
|
||||
// - 常规列表:智能缓存(根据查询复杂度自动选择缓存策略)
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - options: 列表查询选项(分页、排序、筛选、搜索等)
|
||||
//
|
||||
// 返回:
|
||||
// - []entities.EnterpriseInfoSubmitRecord: 查询结果列表
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []entities.EnterpriseInfoSubmitRecord
|
||||
|
||||
// 搜索查询:使用短期缓存避免频繁数据库查询
|
||||
if options.Search != "" {
|
||||
return r.handleSearchQuery(ctx, options)
|
||||
}
|
||||
|
||||
// 常规列表:使用智能缓存策略
|
||||
err := r.SmartList(ctx, &records, options)
|
||||
return records, err
|
||||
}
|
||||
|
||||
// ================ BaseRepository 接口实现 ================
|
||||
|
||||
// Delete 删除企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
return r.DeleteEntity(ctx, id, &entities.EnterpriseInfoSubmitRecord{})
|
||||
}
|
||||
|
||||
// Exists 检查企业信息提交记录是否存在
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
return r.ExistsEntity(ctx, id, &entities.EnterpriseInfoSubmitRecord{})
|
||||
}
|
||||
|
||||
// Count 统计企业信息提交记录数量
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 搜索统计:使用自定义搜索逻辑,不缓存保证准确性
|
||||
// - 常规统计:使用基础实现的缓存策略
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
if options.Search != "" {
|
||||
return r.CountWhere(ctx, &entities.EnterpriseInfoSubmitRecord{},
|
||||
"company_name LIKE ? OR unified_social_code LIKE ? OR legal_person_name LIKE ?",
|
||||
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
return r.CountWithOptions(ctx, &entities.EnterpriseInfoSubmitRecord{}, options)
|
||||
}
|
||||
|
||||
// SoftDelete 软删除企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.SoftDeleteEntity(ctx, id, &entities.EnterpriseInfoSubmitRecord{})
|
||||
}
|
||||
|
||||
// Restore 恢复企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
return r.RestoreEntity(ctx, id, &entities.EnterpriseInfoSubmitRecord{})
|
||||
}
|
||||
|
||||
// ================ 业务专用查询方法 ================
|
||||
|
||||
// GetByCertificationID 根据认证ID获取企业信息提交记录
|
||||
//
|
||||
// 业务说明:
|
||||
// - 每个认证流程对应一个企业信息提交记录
|
||||
// - 适用于认证流程中查询企业信息
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 业务查询,缓存15分钟
|
||||
// - 认证ID查询频率较高,适合中期缓存
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - certificationID: 认证流程ID
|
||||
//
|
||||
// 返回:
|
||||
// - *entities.EnterpriseInfoSubmitRecord: 查询到的记录,未找到时返回nil
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) (*entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var record entities.EnterpriseInfoSubmitRecord
|
||||
err := r.SmartGetByField(ctx, &record, "certification_id", certificationID, CacheTTLBusinessQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取企业信息提交记录列表
|
||||
//
|
||||
// 业务说明:
|
||||
// - 获取某用户的所有企业信息提交记录
|
||||
// - 按创建时间倒序排列,最新的在前
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 用户相关查询,使用中期缓存10分钟
|
||||
// - 用户查询频率中等,适合中期缓存
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - userID: 用户ID
|
||||
//
|
||||
// 返回:
|
||||
// - []*entities.EnterpriseInfoSubmitRecord: 查询结果列表
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetByUserID(ctx context.Context, userID string) ([]*entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []*entities.EnterpriseInfoSubmitRecord
|
||||
|
||||
err := r.WithMediumCache().GetDB(ctx).
|
||||
Where("user_id = ?", userID).
|
||||
Order("created_at DESC").
|
||||
Find(&records).Error
|
||||
|
||||
return records, err
|
||||
}
|
||||
|
||||
// GetLatestByUserID 根据用户ID获取最新的企业信息提交记录
|
||||
//
|
||||
// 业务说明:
|
||||
// - 获取用户最新提交的企业信息记录
|
||||
// - 适用于用户中心显示最新提交状态
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 最新记录查询,缓存15分钟
|
||||
// - 用户中心访问频率较高
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetLatestByUserID(ctx context.Context, userID string) (*entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var record entities.EnterpriseInfoSubmitRecord
|
||||
err := r.GetDB(ctx).
|
||||
Where("user_id = ?", userID).
|
||||
Order("created_at DESC").
|
||||
First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// ================ 业务状态管理方法 ================
|
||||
|
||||
// UpdateStatus 更新企业信息提交记录状态
|
||||
//
|
||||
// 业务说明:
|
||||
// - 更新记录的审核状态和备注信息
|
||||
// - 适用于管理员审核流程
|
||||
//
|
||||
// 缓存影响:
|
||||
// - GORM缓存插件会自动失效表相关的缓存
|
||||
// - 状态更新会影响列表查询和统计结果
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - recordID: 记录ID
|
||||
// - status: 新状态
|
||||
// - reason: 状态变更原因或备注
|
||||
//
|
||||
// 返回:
|
||||
// - error: 更新失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) UpdateStatus(ctx context.Context, recordID string, status string, reason string) error {
|
||||
r.GetLogger().Info("更新企业信息提交记录状态",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("status", status),
|
||||
zap.String("reason", reason))
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
if reason != "" {
|
||||
updates["reason"] = reason
|
||||
}
|
||||
|
||||
return r.GetDB(ctx).Model(&entities.EnterpriseInfoSubmitRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// ================ 高级查询方法 ================
|
||||
|
||||
// ListRecords 获取企业信息提交记录列表(带分页和高级筛选)
|
||||
//
|
||||
// 业务说明:
|
||||
// - 管理员后台的高级查询接口
|
||||
// - 支持多维度筛选和分页
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - query: 高级查询条件
|
||||
//
|
||||
// 返回:
|
||||
// - []*entities.EnterpriseInfoSubmitRecord: 查询结果
|
||||
// - int64: 总记录数
|
||||
// - error: 查询失败时的错误
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) ListRecords(ctx context.Context, query *queries.ListEnterpriseInfoSubmitRecordsQuery) ([]*entities.EnterpriseInfoSubmitRecord, int64, error) {
|
||||
var records []*entities.EnterpriseInfoSubmitRecord
|
||||
var total int64
|
||||
|
||||
dbQuery := r.GetDB(ctx).Model(&entities.EnterpriseInfoSubmitRecord{})
|
||||
|
||||
// 构建查询条件
|
||||
dbQuery = r.buildQueryConditions(dbQuery, query)
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页和排序
|
||||
dbQuery = r.applyPaginationAndSorting(dbQuery, query)
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&records).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return records, total, nil
|
||||
}
|
||||
|
||||
// ================ 缓存管理方法 ================
|
||||
|
||||
// GetActiveRecords 获取活跃记录
|
||||
//
|
||||
// 业务说明:
|
||||
// - 获取状态为活跃的企业信息提交记录
|
||||
// - 适用于仪表板统计
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 活跃记录查询使用短期缓存5分钟
|
||||
// - 活跃状态变化较频繁,使用短期缓存
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetActiveRecords(ctx context.Context) ([]entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []entities.EnterpriseInfoSubmitRecord
|
||||
err := r.WithShortCache().FindWithCache(ctx, &records, CacheTTLActiveRecords, "status = ?", StatusActive)
|
||||
return records, err
|
||||
}
|
||||
|
||||
// GetPendingRecords 获取待审核记录
|
||||
//
|
||||
// 业务说明:
|
||||
// - 获取待审核的企业信息提交记录
|
||||
// - 适用于管理员工作台
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 禁用缓存,保证数据实时性
|
||||
// - 待审核状态需要实时准确的数据
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetPendingRecords(ctx context.Context) ([]entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []entities.EnterpriseInfoSubmitRecord
|
||||
|
||||
db := r.WithoutCache().GetDB(ctx)
|
||||
err := db.Where("status = ?", StatusPending).
|
||||
Order("created_at ASC").
|
||||
Find(&records).Error
|
||||
|
||||
return records, err
|
||||
}
|
||||
|
||||
// WarmupCache 预热企业信息提交记录缓存
|
||||
//
|
||||
// 业务说明:
|
||||
// - 系统启动时预热常用查询的缓存
|
||||
// - 提升首次访问的响应速度
|
||||
//
|
||||
// 预热策略:
|
||||
// - 活跃记录:30分钟长期缓存
|
||||
// - 最近提交:15分钟中期缓存
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) WarmupCache(ctx context.Context) error {
|
||||
r.GetLogger().Info("开始预热企业信息提交记录缓存")
|
||||
|
||||
queries := []database.WarmupQuery{
|
||||
{
|
||||
Name: "active_records",
|
||||
TTL: CacheTTLWarmupLong,
|
||||
Dest: &[]entities.EnterpriseInfoSubmitRecord{},
|
||||
},
|
||||
{
|
||||
Name: "recent_submissions",
|
||||
TTL: CacheTTLWarmupMedium,
|
||||
Dest: &[]entities.EnterpriseInfoSubmitRecord{},
|
||||
},
|
||||
}
|
||||
|
||||
return r.WarmupCommonQueries(ctx, queries)
|
||||
}
|
||||
|
||||
// RefreshRecordCache 刷新记录缓存
|
||||
//
|
||||
// 业务说明:
|
||||
// - 手动刷新企业信息提交记录相关的所有缓存
|
||||
// - 适用于数据迁移或批量更新后的缓存清理
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) RefreshRecordCache(ctx context.Context) error {
|
||||
r.GetLogger().Info("刷新企业信息提交记录缓存")
|
||||
return r.RefreshCache(ctx, CachePatternTable)
|
||||
}
|
||||
|
||||
// GetCacheStats 获取缓存统计信息
|
||||
//
|
||||
// 返回当前Repository的缓存使用统计,包括:
|
||||
// - 基础缓存信息(命中率、键数量等)
|
||||
// - 特定的缓存模式列表
|
||||
// - 性能指标
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetCacheStats() map[string]interface{} {
|
||||
stats := r.GetCacheInfo()
|
||||
stats["specific_patterns"] = []string{
|
||||
CachePatternTable,
|
||||
CachePatternCertification,
|
||||
CachePatternUser,
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
// ================ 私有辅助方法 ================
|
||||
|
||||
// handleSearchQuery 处理搜索查询
|
||||
//
|
||||
// 业务逻辑:
|
||||
// - 支持按企业名称、统一社会信用代码、法定代表人姓名搜索
|
||||
// - 使用短期缓存避免频繁数据库查询
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - options: 查询选项
|
||||
//
|
||||
// 返回:
|
||||
// - []entities.EnterpriseInfoSubmitRecord: 搜索结果
|
||||
// - error: 查询失败时的错误
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) handleSearchQuery(ctx context.Context, options interfaces.ListOptions) ([]entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []entities.EnterpriseInfoSubmitRecord
|
||||
|
||||
db := r.GetDB(ctx).
|
||||
Set("cache:enabled", true).
|
||||
Set("cache:ttl", CacheTTLSearchQuery).
|
||||
Model(&entities.EnterpriseInfoSubmitRecord{})
|
||||
|
||||
// 应用筛选条件
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
db = db.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
// 企业信息特定的搜索逻辑
|
||||
db = db.Where("company_name LIKE ? OR unified_social_code LIKE ? OR legal_person_name LIKE ?",
|
||||
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
|
||||
// 应用预加载
|
||||
for _, include := range options.Include {
|
||||
db = db.Preload(include)
|
||||
}
|
||||
|
||||
// 应用排序
|
||||
db = r.applySorting(db, options)
|
||||
|
||||
// 应用分页
|
||||
db = r.applyPagination(db, options)
|
||||
|
||||
return records, db.Find(&records).Error
|
||||
}
|
||||
|
||||
// buildQueryConditions 构建查询条件
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库查询对象
|
||||
// - query: 查询条件
|
||||
//
|
||||
// 返回:
|
||||
// - *gorm.DB: 应用查询条件后的数据库对象
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) buildQueryConditions(db *gorm.DB, query *queries.ListEnterpriseInfoSubmitRecordsQuery) *gorm.DB {
|
||||
if query.UserID != "" {
|
||||
db = db.Where("user_id = ?", query.UserID)
|
||||
}
|
||||
if query.Status != "" {
|
||||
db = db.Where("status = ?", query.Status)
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
db = db.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
db = db.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
// applyPaginationAndSorting 应用分页和排序
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库查询对象
|
||||
// - query: 查询条件
|
||||
//
|
||||
// 返回:
|
||||
// - *gorm.DB: 应用分页和排序后的数据库对象
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) applyPaginationAndSorting(db *gorm.DB, query *queries.ListEnterpriseInfoSubmitRecordsQuery) *gorm.DB {
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
db = db.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
db = db.Order("created_at DESC")
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
// applySorting 应用排序规则
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库查询对象
|
||||
// - options: 查询选项
|
||||
//
|
||||
// 返回:
|
||||
// - *gorm.DB: 应用排序后的数据库对象
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) applySorting(db *gorm.DB, options interfaces.ListOptions) *gorm.DB {
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order == "desc" || options.Order == "DESC" {
|
||||
order = "DESC"
|
||||
}
|
||||
return db.Order(options.Sort + " " + order)
|
||||
}
|
||||
return db.Order("created_at DESC")
|
||||
}
|
||||
|
||||
// applyPagination 应用分页规则
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库查询对象
|
||||
// - options: 查询选项
|
||||
//
|
||||
// 返回:
|
||||
// - *gorm.DB: 应用分页后的数据库对象
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) applyPagination(db *gorm.DB, options interfaces.ListOptions) *gorm.DB {
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
return db.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
return db
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/domains/certification/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// GormEsignContractGenerateRecordRepository e签宝生成合同记录GORM仓储实现
|
||||
type GormEsignContractGenerateRecordRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.EsignContractGenerateRecordRepository = (*GormEsignContractGenerateRecordRepository)(nil)
|
||||
|
||||
// NewGormEsignContractGenerateRecordRepository 创建e签宝生成合同记录GORM仓储
|
||||
func NewGormEsignContractGenerateRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.EsignContractGenerateRecordRepository {
|
||||
return &GormEsignContractGenerateRecordRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) Create(ctx context.Context, record entities.EsignContractGenerateRecord) (entities.EsignContractGenerateRecord, error) {
|
||||
r.logger.Info("创建e签宝生成合同记录", zap.String("certification_id", record.CertificationID))
|
||||
err := r.db.WithContext(ctx).Create(&record).Error
|
||||
return record, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) GetByID(ctx context.Context, id string) (entities.EsignContractGenerateRecord, error) {
|
||||
var record entities.EsignContractGenerateRecord
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&record).Error
|
||||
return record, err
|
||||
}
|
||||
|
||||
// Update 更新e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) Update(ctx context.Context, record entities.EsignContractGenerateRecord) error {
|
||||
r.logger.Info("更新e签宝生成合同记录", zap.String("id", record.ID))
|
||||
return r.db.WithContext(ctx).Save(&record).Error
|
||||
}
|
||||
|
||||
// Delete 删除e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
r.logger.Info("删除e签宝生成合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractGenerateRecord{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// SoftDelete 软删除e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
r.logger.Info("软删除e签宝生成合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractGenerateRecord{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// Restore 恢复e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
r.logger.Info("恢复e签宝生成合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Unscoped().Model(&entities.EsignContractGenerateRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
||||
}
|
||||
|
||||
// Count 统计e签宝生成合同记录数量
|
||||
func (r *GormEsignContractGenerateRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("contract_name LIKE ?", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
err := query.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// Exists 检查e签宝生成合同记录是否存在
|
||||
func (r *GormEsignContractGenerateRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) CreateBatch(ctx context.Context, records []entities.EsignContractGenerateRecord) error {
|
||||
r.logger.Info("批量创建e签宝生成合同记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Create(&records).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.EsignContractGenerateRecord, error) {
|
||||
var records []entities.EsignContractGenerateRecord
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) UpdateBatch(ctx context.Context, records []entities.EsignContractGenerateRecord) error {
|
||||
r.logger.Info("批量更新e签宝生成合同记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Save(&records).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除e签宝生成合同记录", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractGenerateRecord{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取e签宝生成合同记录列表
|
||||
func (r *GormEsignContractGenerateRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.EsignContractGenerateRecord, error) {
|
||||
var records []entities.EsignContractGenerateRecord
|
||||
query := r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("contract_name LIKE ?", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
return records, query.Find(&records).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormEsignContractGenerateRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.EsignContractGenerateRecord] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormEsignContractGenerateRecordRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// GetByCertificationID 根据认证ID获取e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) (*entities.EsignContractGenerateRecord, error) {
|
||||
var record entities.EsignContractGenerateRecord
|
||||
err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取e签宝生成合同记录列表
|
||||
func (r *GormEsignContractGenerateRecordRepository) GetByUserID(ctx context.Context, userID string) ([]*entities.EsignContractGenerateRecord, error) {
|
||||
var records []entities.EsignContractGenerateRecord
|
||||
err := r.db.WithContext(ctx).Where("user_id = ?", userID).Find(&records).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []*entities.EsignContractGenerateRecord
|
||||
for i := range records {
|
||||
result = append(result, &records[i])
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetLatestByCertificationID 根据认证ID获取最新的e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) GetLatestByCertificationID(ctx context.Context, certificationID string) (*entities.EsignContractGenerateRecord, error) {
|
||||
var record entities.EsignContractGenerateRecord
|
||||
err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// ListRecords 获取e签宝生成合同记录列表(带分页和筛选)
|
||||
func (r *GormEsignContractGenerateRecordRepository) ListRecords(ctx context.Context, query *queries.ListEsignContractGenerateRecordsQuery) ([]*entities.EsignContractGenerateRecord, int64, error) {
|
||||
var records []entities.EsignContractGenerateRecord
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.CertificationID != "" {
|
||||
dbQuery = dbQuery.Where("certification_id = ?", query.CertificationID)
|
||||
}
|
||||
if query.UserID != "" {
|
||||
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
|
||||
}
|
||||
if query.Status != "" {
|
||||
dbQuery = dbQuery.Where("status = ?", query.Status)
|
||||
}
|
||||
if query.ContractType != "" {
|
||||
dbQuery = dbQuery.Where("contract_type = ?", query.ContractType)
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
if query.Page > 0 && query.PageSize > 0 {
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
}
|
||||
|
||||
// 排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 执行查询
|
||||
if err := dbQuery.Find(&records).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
var result []*entities.EsignContractGenerateRecord
|
||||
for i := range records {
|
||||
result = append(result, &records[i])
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// UpdateStatus 更新状态
|
||||
func (r *GormEsignContractGenerateRecordRepository) UpdateStatus(ctx context.Context, recordID string, status string, reason string) error {
|
||||
r.logger.Info("更新e签宝生成合同记录状态",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("status", status),
|
||||
)
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
// 根据状态设置相应的时间戳
|
||||
switch status {
|
||||
case "generating":
|
||||
// 不需要额外时间戳
|
||||
case "success":
|
||||
updates["generated_at"] = time.Now()
|
||||
case "failed":
|
||||
updates["failed_at"] = time.Now()
|
||||
updates["failure_reason"] = reason
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// UpdateSuccessInfo 更新成功信息
|
||||
func (r *GormEsignContractGenerateRecordRepository) UpdateSuccessInfo(ctx context.Context, recordID, esignFlowID, contractFileID, contractURL string) error {
|
||||
r.logger.Info("更新e签宝生成合同记录成功信息",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("esign_flow_id", esignFlowID),
|
||||
)
|
||||
|
||||
now := time.Now()
|
||||
updates := map[string]interface{}{
|
||||
"status": "success",
|
||||
"esign_flow_id": esignFlowID,
|
||||
"contract_file_id": contractFileID,
|
||||
"contract_url": contractURL,
|
||||
"generated_at": &now,
|
||||
"updated_at": now,
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// IncrementRetry 增加重试次数
|
||||
func (r *GormEsignContractGenerateRecordRepository) IncrementRetry(ctx context.Context, recordID string) error {
|
||||
r.logger.Info("增加e签宝生成合同记录重试次数", zap.String("record_id", recordID))
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
UpdateColumn("retry_count", gorm.Expr("retry_count + 1")).Error
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/domains/certification/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// GormEsignContractSignRecordRepository e签宝签署合同记录GORM仓储实现
|
||||
type GormEsignContractSignRecordRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.EsignContractSignRecordRepository = (*GormEsignContractSignRecordRepository)(nil)
|
||||
|
||||
// NewGormEsignContractSignRecordRepository 创建e签宝签署合同记录GORM仓储
|
||||
func NewGormEsignContractSignRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.EsignContractSignRecordRepository {
|
||||
return &GormEsignContractSignRecordRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) Create(ctx context.Context, record entities.EsignContractSignRecord) (entities.EsignContractSignRecord, error) {
|
||||
r.logger.Info("创建e签宝签署合同记录", zap.String("certification_id", record.CertificationID))
|
||||
err := r.db.WithContext(ctx).Create(&record).Error
|
||||
return record, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) GetByID(ctx context.Context, id string) (entities.EsignContractSignRecord, error) {
|
||||
var record entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&record).Error
|
||||
return record, err
|
||||
}
|
||||
|
||||
// Update 更新e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) Update(ctx context.Context, record entities.EsignContractSignRecord) error {
|
||||
r.logger.Info("更新e签宝签署合同记录", zap.String("id", record.ID))
|
||||
return r.db.WithContext(ctx).Save(&record).Error
|
||||
}
|
||||
|
||||
// Delete 删除e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
r.logger.Info("删除e签宝签署合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractSignRecord{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// SoftDelete 软删除e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
r.logger.Info("软删除e签宝签署合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractSignRecord{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// Restore 恢复e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
r.logger.Info("恢复e签宝签署合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Unscoped().Model(&entities.EsignContractSignRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
||||
}
|
||||
|
||||
// Count 统计e签宝签署合同记录数量
|
||||
func (r *GormEsignContractSignRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("signer_name LIKE ?", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
err := query.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// Exists 检查e签宝签署合同记录是否存在
|
||||
func (r *GormEsignContractSignRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) CreateBatch(ctx context.Context, records []entities.EsignContractSignRecord) error {
|
||||
r.logger.Info("批量创建e签宝签署合同记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Create(&records).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.EsignContractSignRecord, error) {
|
||||
var records []entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) UpdateBatch(ctx context.Context, records []entities.EsignContractSignRecord) error {
|
||||
r.logger.Info("批量更新e签宝签署合同记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Save(&records).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除e签宝签署合同记录", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractSignRecord{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取e签宝签署合同记录列表
|
||||
func (r *GormEsignContractSignRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.EsignContractSignRecord, error) {
|
||||
var records []entities.EsignContractSignRecord
|
||||
query := r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("signer_name LIKE ?", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
return records, query.Find(&records).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormEsignContractSignRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.EsignContractSignRecord] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormEsignContractSignRecordRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// GetByCertificationID 根据认证ID获取e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) (*entities.EsignContractSignRecord, error) {
|
||||
var record entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取e签宝签署合同记录列表
|
||||
func (r *GormEsignContractSignRecordRepository) GetByUserID(ctx context.Context, userID string) ([]*entities.EsignContractSignRecord, error) {
|
||||
var records []entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("user_id = ?", userID).Find(&records).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []*entities.EsignContractSignRecord
|
||||
for i := range records {
|
||||
result = append(result, &records[i])
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetLatestByCertificationID 根据认证ID获取最新的e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) GetLatestByCertificationID(ctx context.Context, certificationID string) (*entities.EsignContractSignRecord, error) {
|
||||
var record entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// GetByGenerateRecordID 根据生成记录ID获取e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) GetByGenerateRecordID(ctx context.Context, generateRecordID string) (*entities.EsignContractSignRecord, error) {
|
||||
var record entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("generate_record_id = ?", generateRecordID).First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// ListRecords 获取e签宝签署合同记录列表(带分页和筛选)
|
||||
func (r *GormEsignContractSignRecordRepository) ListRecords(ctx context.Context, query *queries.ListEsignContractSignRecordsQuery) ([]*entities.EsignContractSignRecord, int64, error) {
|
||||
var records []entities.EsignContractSignRecord
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.CertificationID != "" {
|
||||
dbQuery = dbQuery.Where("certification_id = ?", query.CertificationID)
|
||||
}
|
||||
if query.UserID != "" {
|
||||
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
|
||||
}
|
||||
if query.Status != "" {
|
||||
dbQuery = dbQuery.Where("status = ?", query.Status)
|
||||
}
|
||||
if query.SignerName != "" {
|
||||
dbQuery = dbQuery.Where("signer_name LIKE ?", "%"+query.SignerName+"%")
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
if query.Page > 0 && query.PageSize > 0 {
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
}
|
||||
|
||||
// 排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 执行查询
|
||||
if err := dbQuery.Find(&records).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
var result []*entities.EsignContractSignRecord
|
||||
for i := range records {
|
||||
result = append(result, &records[i])
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// UpdateStatus 更新状态
|
||||
func (r *GormEsignContractSignRecordRepository) UpdateStatus(ctx context.Context, recordID string, status string, reason string) error {
|
||||
r.logger.Info("更新e签宝签署合同记录状态",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("status", status),
|
||||
)
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
// 根据状态设置相应的时间戳
|
||||
switch status {
|
||||
case "signing":
|
||||
// 不需要额外时间戳
|
||||
case "success":
|
||||
updates["signed_at"] = time.Now()
|
||||
case "failed":
|
||||
updates["failed_at"] = time.Now()
|
||||
updates["failure_reason"] = reason
|
||||
case "expired":
|
||||
updates["expired_at"] = time.Now()
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// UpdateSuccessInfo 更新成功信息
|
||||
func (r *GormEsignContractSignRecordRepository) UpdateSuccessInfo(ctx context.Context, recordID, signedFileURL string) error {
|
||||
r.logger.Info("更新e签宝签署合同记录成功信息",
|
||||
zap.String("record_id", recordID),
|
||||
)
|
||||
|
||||
now := time.Now()
|
||||
updates := map[string]interface{}{
|
||||
"status": "success",
|
||||
"signed_file_url": signedFileURL,
|
||||
"signed_at": &now,
|
||||
"updated_at": now,
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// SetSignURL 设置签署链接
|
||||
func (r *GormEsignContractSignRecordRepository) SetSignURL(ctx context.Context, recordID, signURL string) error {
|
||||
r.logger.Info("设置e签宝签署合同记录签署链接",
|
||||
zap.String("record_id", recordID),
|
||||
)
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"sign_url": signURL,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// IncrementRetry 增加重试次数
|
||||
func (r *GormEsignContractSignRecordRepository) IncrementRetry(ctx context.Context, recordID string) error {
|
||||
r.logger.Info("增加e签宝签署合同记录重试次数", zap.String("record_id", recordID))
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
UpdateColumn("retry_count", gorm.Expr("retry_count + 1")).Error
|
||||
}
|
||||
|
||||
// MarkExpiredRecords 标记过期的记录
|
||||
func (r *GormEsignContractSignRecordRepository) MarkExpiredRecords(ctx context.Context) error {
|
||||
r.logger.Info("标记过期的e签宝签署合同记录")
|
||||
|
||||
now := time.Now()
|
||||
updates := map[string]interface{}{
|
||||
"status": "expired",
|
||||
"expired_at": &now,
|
||||
"updated_at": now,
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).
|
||||
Where("status = ? AND expired_at < ?", "pending", now).
|
||||
Updates(updates).Error
|
||||
}
|
||||
@@ -1,394 +0,0 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/domains/certification/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// GormFaceVerifyRecordRepository GORM人脸识别记录仓储实现
|
||||
type GormFaceVerifyRecordRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.FaceVerifyRecordRepository = (*GormFaceVerifyRecordRepository)(nil)
|
||||
|
||||
// NewGormFaceVerifyRecordRepository 创建GORM人脸识别记录仓储
|
||||
func NewGormFaceVerifyRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.FaceVerifyRecordRepository {
|
||||
return &GormFaceVerifyRecordRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) Create(ctx context.Context, record entities.FaceVerifyRecord) (entities.FaceVerifyRecord, error) {
|
||||
if err := r.db.WithContext(ctx).Create(&record).Error; err != nil {
|
||||
r.logger.Error("创建人脸识别记录失败",
|
||||
zap.String("certification_id", record.CertificationID),
|
||||
zap.String("certify_id", record.CertifyID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return entities.FaceVerifyRecord{}, fmt.Errorf("创建人脸识别记录失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("人脸识别记录创建成功",
|
||||
zap.String("id", record.ID),
|
||||
zap.String("certify_id", record.CertifyID),
|
||||
)
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) GetByID(ctx context.Context, id string) (entities.FaceVerifyRecord, error) {
|
||||
var record entities.FaceVerifyRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).First(&record, "id = ?", id).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return entities.FaceVerifyRecord{}, fmt.Errorf("人脸识别记录不存在")
|
||||
}
|
||||
r.logger.Error("获取人脸识别记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return entities.FaceVerifyRecord{}, fmt.Errorf("获取人脸识别记录失败: %w", err)
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// Update 更新人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) Update(ctx context.Context, record entities.FaceVerifyRecord) error {
|
||||
if err := r.db.WithContext(ctx).Save(&record).Error; err != nil {
|
||||
r.logger.Error("更新人脸识别记录失败",
|
||||
zap.String("id", record.ID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("更新人脸识别记录失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete 删除人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Delete(&entities.FaceVerifyRecord{}, "id = ?", id).Error; err != nil {
|
||||
r.logger.Error("删除人脸识别记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("删除人脸识别记录失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SoftDelete 软删除人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// Restore 恢复人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Unscoped().Model(&entities.FaceVerifyRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error; err != nil {
|
||||
r.logger.Error("恢复人脸识别记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("恢复人脸识别记录失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("人脸识别记录恢复成功", zap.String("id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Count 统计人脸识别记录数量
|
||||
func (r *GormFaceVerifyRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("certify_id LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
return count, query.Count(&count).Error
|
||||
}
|
||||
|
||||
// Exists 检查人脸识别记录是否存在
|
||||
func (r *GormFaceVerifyRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) CreateBatch(ctx context.Context, records []entities.FaceVerifyRecord) error {
|
||||
r.logger.Info("批量创建人脸识别记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Create(&records).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.FaceVerifyRecord, error) {
|
||||
var records []entities.FaceVerifyRecord
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) UpdateBatch(ctx context.Context, records []entities.FaceVerifyRecord) error {
|
||||
r.logger.Info("批量更新人脸识别记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Save(&records).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除人脸识别记录", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.FaceVerifyRecord{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取人脸识别记录列表
|
||||
func (r *GormFaceVerifyRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.FaceVerifyRecord, error) {
|
||||
var records []entities.FaceVerifyRecord
|
||||
query := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("certify_id LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
return records, query.Find(&records).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormFaceVerifyRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.FaceVerifyRecord] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormFaceVerifyRecordRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// GetByCertificationID 根据认证申请ID获取人脸识别记录列表
|
||||
func (r *GormFaceVerifyRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) ([]*entities.FaceVerifyRecord, error) {
|
||||
var records []entities.FaceVerifyRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").Find(&records).Error; err != nil {
|
||||
r.logger.Error("根据认证申请ID获取人脸识别记录失败",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, fmt.Errorf("获取人脸识别记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.FaceVerifyRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, nil
|
||||
}
|
||||
|
||||
// GetLatestByCertificationID 根据认证申请ID获取最新的人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) GetLatestByCertificationID(ctx context.Context, certificationID string) (*entities.FaceVerifyRecord, error) {
|
||||
var record entities.FaceVerifyRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").First(&record).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("人脸识别记录不存在")
|
||||
}
|
||||
r.logger.Error("根据认证申请ID获取最新人脸识别记录失败",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, fmt.Errorf("获取人脸识别记录失败: %w", err)
|
||||
}
|
||||
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// ListRecords 获取人脸识别记录列表(带分页和筛选)
|
||||
func (r *GormFaceVerifyRecordRepository) ListRecords(ctx context.Context, query *queries.ListFaceVerifyRecordsQuery) ([]*entities.FaceVerifyRecord, int64, error) {
|
||||
var records []entities.FaceVerifyRecord
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.CertificationID != "" {
|
||||
dbQuery = dbQuery.Where("certification_id = ?", query.CertificationID)
|
||||
}
|
||||
if query.UserID != "" {
|
||||
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
|
||||
}
|
||||
if query.Status != "" {
|
||||
dbQuery = dbQuery.Where("status = ?", query.Status)
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&records).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.FaceVerifyRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, total, nil
|
||||
}
|
||||
|
||||
// GetSuccessRate 获取成功率
|
||||
func (r *GormFaceVerifyRecordRepository) GetSuccessRate(ctx context.Context, days int) (float64, error) {
|
||||
var totalCount int64
|
||||
var successCount int64
|
||||
|
||||
// 计算指定天数前的日期
|
||||
startDate := fmt.Sprintf("DATE_SUB(NOW(), INTERVAL %d DAY)", days)
|
||||
|
||||
// 获取总数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{}).
|
||||
Where("created_at >= " + startDate).Count(&totalCount).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 获取成功数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{}).
|
||||
Where("created_at >= "+startDate+" AND status = ?", "SUCCESS").Count(&successCount).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if totalCount == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return float64(successCount) / float64(totalCount) * 100, nil
|
||||
}
|
||||
|
||||
// GetByCertifyID 根据认证ID获取人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) GetByCertifyID(ctx context.Context, certifyID string) (*entities.FaceVerifyRecord, error) {
|
||||
var record entities.FaceVerifyRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).First(&record, "certify_id = ?", certifyID).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("人脸识别记录不存在")
|
||||
}
|
||||
r.logger.Error("根据认证ID获取人脸识别记录失败",
|
||||
zap.String("certify_id", certifyID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, fmt.Errorf("获取人脸识别记录失败: %w", err)
|
||||
}
|
||||
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取人脸识别记录列表
|
||||
func (r *GormFaceVerifyRecordRepository) GetByUserID(ctx context.Context, userID string, page, pageSize int) ([]*entities.FaceVerifyRecord, int, error) {
|
||||
var records []entities.FaceVerifyRecord
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{}).Where("user_id = ?", userID)
|
||||
|
||||
// 获取总数
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
r.logger.Error("获取用户人脸识别记录总数失败", zap.Error(err))
|
||||
return nil, 0, fmt.Errorf("获取人脸识别记录总数失败: %w", err)
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (page - 1) * pageSize
|
||||
if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&records).Error; err != nil {
|
||||
r.logger.Error("获取用户人脸识别记录列表失败", zap.Error(err))
|
||||
return nil, 0, fmt.Errorf("获取人脸识别记录列表失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.FaceVerifyRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, int(total), nil
|
||||
}
|
||||
|
||||
// GetExpiredRecords 获取已过期的人脸识别记录
|
||||
func (r *GormFaceVerifyRecordRepository) GetExpiredRecords(ctx context.Context, limit int) ([]*entities.FaceVerifyRecord, error) {
|
||||
var records []entities.FaceVerifyRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("expires_at < NOW() AND status = ?", "PROCESSING").
|
||||
Limit(limit).
|
||||
Order("expires_at ASC").
|
||||
Find(&records).Error; err != nil {
|
||||
r.logger.Error("获取过期人脸识别记录失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("获取过期人脸识别记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.FaceVerifyRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, nil
|
||||
}
|
||||
@@ -1,374 +0,0 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/domains/certification/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// GormLicenseUploadRecordRepository GORM营业执照上传记录仓储实现
|
||||
type GormLicenseUploadRecordRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.LicenseUploadRecordRepository = (*GormLicenseUploadRecordRepository)(nil)
|
||||
|
||||
// NewGormLicenseUploadRecordRepository 创建GORM营业执照上传记录仓储
|
||||
func NewGormLicenseUploadRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.LicenseUploadRecordRepository {
|
||||
return &GormLicenseUploadRecordRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) Create(ctx context.Context, record entities.LicenseUploadRecord) (entities.LicenseUploadRecord, error) {
|
||||
if err := r.db.WithContext(ctx).Create(&record).Error; err != nil {
|
||||
r.logger.Error("创建上传记录失败",
|
||||
zap.String("user_id", record.UserID),
|
||||
zap.String("file_name", record.OriginalFileName),
|
||||
zap.Error(err),
|
||||
)
|
||||
return entities.LicenseUploadRecord{}, fmt.Errorf("创建上传记录失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("上传记录创建成功",
|
||||
zap.String("id", record.ID),
|
||||
zap.String("file_name", record.OriginalFileName),
|
||||
)
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) GetByID(ctx context.Context, id string) (entities.LicenseUploadRecord, error) {
|
||||
var record entities.LicenseUploadRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).First(&record, "id = ?", id).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return entities.LicenseUploadRecord{}, fmt.Errorf("上传记录不存在")
|
||||
}
|
||||
r.logger.Error("获取上传记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return entities.LicenseUploadRecord{}, fmt.Errorf("获取上传记录失败: %w", err)
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// Update 更新上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) Update(ctx context.Context, record entities.LicenseUploadRecord) error {
|
||||
if err := r.db.WithContext(ctx).Save(&record).Error; err != nil {
|
||||
r.logger.Error("更新上传记录失败",
|
||||
zap.String("id", record.ID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("更新上传记录失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete 删除上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Delete(&entities.LicenseUploadRecord{}, "id = ?", id).Error; err != nil {
|
||||
r.logger.Error("删除上传记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("删除上传记录失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SoftDelete 软删除上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// Restore 恢复上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Unscoped().Model(&entities.LicenseUploadRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error; err != nil {
|
||||
r.logger.Error("恢复上传记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("恢复上传记录失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("上传记录恢复成功", zap.String("id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Count 统计上传记录数量
|
||||
func (r *GormLicenseUploadRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.LicenseUploadRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("original_file_name LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
return count, query.Count(&count).Error
|
||||
}
|
||||
|
||||
// Exists 检查上传记录是否存在
|
||||
func (r *GormLicenseUploadRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.LicenseUploadRecord{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) CreateBatch(ctx context.Context, records []entities.LicenseUploadRecord) error {
|
||||
r.logger.Info("批量创建上传记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Create(&records).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.LicenseUploadRecord, error) {
|
||||
var records []entities.LicenseUploadRecord
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) UpdateBatch(ctx context.Context, records []entities.LicenseUploadRecord) error {
|
||||
r.logger.Info("批量更新上传记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Save(&records).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除上传记录", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.LicenseUploadRecord{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取上传记录列表
|
||||
func (r *GormLicenseUploadRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.LicenseUploadRecord, error) {
|
||||
var records []entities.LicenseUploadRecord
|
||||
query := r.db.WithContext(ctx).Model(&entities.LicenseUploadRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("original_file_name LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
return records, query.Find(&records).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormLicenseUploadRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.LicenseUploadRecord] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormLicenseUploadRecordRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// GetByCertificationID 根据认证ID获取上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) (*entities.LicenseUploadRecord, error) {
|
||||
var record entities.LicenseUploadRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).First(&record, "certification_id = ?", certificationID).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("上传记录不存在")
|
||||
}
|
||||
r.logger.Error("根据认证ID获取上传记录失败",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, fmt.Errorf("获取上传记录失败: %w", err)
|
||||
}
|
||||
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// ListRecords 获取上传记录列表(带分页和筛选)
|
||||
func (r *GormLicenseUploadRecordRepository) ListRecords(ctx context.Context, query *queries.ListLicenseUploadRecordsQuery) ([]*entities.LicenseUploadRecord, int64, error) {
|
||||
var records []entities.LicenseUploadRecord
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.LicenseUploadRecord{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.CertificationID != "" {
|
||||
dbQuery = dbQuery.Where("certification_id = ?", query.CertificationID)
|
||||
}
|
||||
if query.UserID != "" {
|
||||
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
|
||||
}
|
||||
if query.Status != "" {
|
||||
dbQuery = dbQuery.Where("status = ?", query.Status)
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&records).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.LicenseUploadRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, total, nil
|
||||
}
|
||||
|
||||
// UpdateOCRResult 更新OCR结果
|
||||
func (r *GormLicenseUploadRecordRepository) UpdateOCRResult(ctx context.Context, recordID string, ocrResult string, confidence float64) error {
|
||||
updates := map[string]interface{}{
|
||||
"ocr_result": ocrResult,
|
||||
"ocr_confidence": confidence,
|
||||
"ocr_processed": true,
|
||||
"ocr_success": true,
|
||||
}
|
||||
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.LicenseUploadRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error; err != nil {
|
||||
r.logger.Error("更新OCR结果失败",
|
||||
zap.String("record_id", recordID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("更新OCR结果失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("OCR结果更新成功",
|
||||
zap.String("record_id", recordID),
|
||||
zap.Float64("confidence", confidence),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取上传记录列表
|
||||
func (r *GormLicenseUploadRecordRepository) GetByUserID(ctx context.Context, userID string, page, pageSize int) ([]*entities.LicenseUploadRecord, int, error) {
|
||||
var records []entities.LicenseUploadRecord
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.LicenseUploadRecord{}).Where("user_id = ?", userID)
|
||||
|
||||
// 获取总数
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
r.logger.Error("获取用户上传记录总数失败", zap.Error(err))
|
||||
return nil, 0, fmt.Errorf("获取上传记录总数失败: %w", err)
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (page - 1) * pageSize
|
||||
if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&records).Error; err != nil {
|
||||
r.logger.Error("获取用户上传记录列表失败", zap.Error(err))
|
||||
return nil, 0, fmt.Errorf("获取上传记录列表失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.LicenseUploadRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, int(total), nil
|
||||
}
|
||||
|
||||
// GetByQiNiuKey 根据七牛云Key获取上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) GetByQiNiuKey(ctx context.Context, key string) (*entities.LicenseUploadRecord, error) {
|
||||
var record entities.LicenseUploadRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).First(&record, "qiniu_key = ?", key).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("上传记录不存在")
|
||||
}
|
||||
r.logger.Error("根据七牛云Key获取上传记录失败",
|
||||
zap.String("qiniu_key", key),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, fmt.Errorf("获取上传记录失败: %w", err)
|
||||
}
|
||||
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// GetPendingOCR 获取待OCR处理的上传记录
|
||||
func (r *GormLicenseUploadRecordRepository) GetPendingOCR(ctx context.Context, limit int) ([]*entities.LicenseUploadRecord, error) {
|
||||
var records []entities.LicenseUploadRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("ocr_processed = ? OR (ocr_processed = ? AND ocr_success = ?)", false, true, false).
|
||||
Limit(limit).
|
||||
Order("created_at ASC").
|
||||
Find(&records).Error; err != nil {
|
||||
r.logger.Error("获取待OCR处理记录失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("获取待OCR处理记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.LicenseUploadRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, nil
|
||||
}
|
||||
@@ -1,344 +0,0 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/domains/certification/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// GormNotificationRecordRepository GORM通知记录仓储实现
|
||||
type GormNotificationRecordRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.NotificationRecordRepository = (*GormNotificationRecordRepository)(nil)
|
||||
|
||||
// NewGormNotificationRecordRepository 创建GORM通知记录仓储
|
||||
func NewGormNotificationRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.NotificationRecordRepository {
|
||||
return &GormNotificationRecordRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建通知记录
|
||||
func (r *GormNotificationRecordRepository) Create(ctx context.Context, record entities.NotificationRecord) (entities.NotificationRecord, error) {
|
||||
if err := r.db.WithContext(ctx).Create(&record).Error; err != nil {
|
||||
r.logger.Error("创建通知记录失败",
|
||||
zap.String("user_id", *record.UserID),
|
||||
zap.String("type", record.NotificationType),
|
||||
zap.Error(err),
|
||||
)
|
||||
return entities.NotificationRecord{}, fmt.Errorf("创建通知记录失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("通知记录创建成功",
|
||||
zap.String("id", record.ID),
|
||||
zap.String("type", record.NotificationType),
|
||||
)
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取通知记录
|
||||
func (r *GormNotificationRecordRepository) GetByID(ctx context.Context, id string) (entities.NotificationRecord, error) {
|
||||
var record entities.NotificationRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).First(&record, "id = ?", id).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return entities.NotificationRecord{}, fmt.Errorf("通知记录不存在")
|
||||
}
|
||||
r.logger.Error("获取通知记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return entities.NotificationRecord{}, fmt.Errorf("获取通知记录失败: %w", err)
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// Update 更新通知记录
|
||||
func (r *GormNotificationRecordRepository) Update(ctx context.Context, record entities.NotificationRecord) error {
|
||||
if err := r.db.WithContext(ctx).Save(&record).Error; err != nil {
|
||||
r.logger.Error("更新通知记录失败",
|
||||
zap.String("id", record.ID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("更新通知记录失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete 删除通知记录
|
||||
func (r *GormNotificationRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Delete(&entities.NotificationRecord{}, "id = ?", id).Error; err != nil {
|
||||
r.logger.Error("删除通知记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("删除通知记录失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SoftDelete 软删除通知记录
|
||||
func (r *GormNotificationRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// Restore 恢复通知记录
|
||||
func (r *GormNotificationRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Unscoped().Model(&entities.NotificationRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error; err != nil {
|
||||
r.logger.Error("恢复通知记录失败",
|
||||
zap.String("id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("恢复通知记录失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("通知记录恢复成功", zap.String("id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Count 统计通知记录数量
|
||||
func (r *GormNotificationRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.NotificationRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("title LIKE ? OR content LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
return count, query.Count(&count).Error
|
||||
}
|
||||
|
||||
// Exists 检查通知记录是否存在
|
||||
func (r *GormNotificationRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.NotificationRecord{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建通知记录
|
||||
func (r *GormNotificationRecordRepository) CreateBatch(ctx context.Context, records []entities.NotificationRecord) error {
|
||||
r.logger.Info("批量创建通知记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Create(&records).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取通知记录
|
||||
func (r *GormNotificationRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.NotificationRecord, error) {
|
||||
var records []entities.NotificationRecord
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新通知记录
|
||||
func (r *GormNotificationRecordRepository) UpdateBatch(ctx context.Context, records []entities.NotificationRecord) error {
|
||||
r.logger.Info("批量更新通知记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Save(&records).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除通知记录
|
||||
func (r *GormNotificationRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除通知记录", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.NotificationRecord{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取通知记录列表
|
||||
func (r *GormNotificationRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.NotificationRecord, error) {
|
||||
var records []entities.NotificationRecord
|
||||
query := r.db.WithContext(ctx).Model(&entities.NotificationRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("title LIKE ? OR content LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
return records, query.Find(&records).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormNotificationRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.NotificationRecord] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormNotificationRecordRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// GetByCertificationID 根据认证申请ID获取通知记录列表
|
||||
func (r *GormNotificationRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) ([]*entities.NotificationRecord, error) {
|
||||
var records []entities.NotificationRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").Find(&records).Error; err != nil {
|
||||
r.logger.Error("根据认证申请ID获取通知记录失败",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, fmt.Errorf("获取通知记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.NotificationRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, nil
|
||||
}
|
||||
|
||||
// GetUnreadByUserID 根据用户ID获取未读通知记录列表
|
||||
func (r *GormNotificationRecordRepository) GetUnreadByUserID(ctx context.Context, userID string) ([]*entities.NotificationRecord, error) {
|
||||
var records []entities.NotificationRecord
|
||||
|
||||
if err := r.db.WithContext(ctx).Where("user_id = ? AND is_read = ?", userID, false).Order("created_at DESC").Find(&records).Error; err != nil {
|
||||
r.logger.Error("根据用户ID获取未读通知记录失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, fmt.Errorf("获取未读通知记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.NotificationRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, nil
|
||||
}
|
||||
|
||||
// ListRecords 获取通知记录列表(带分页和筛选)
|
||||
func (r *GormNotificationRecordRepository) ListRecords(ctx context.Context, query *queries.ListNotificationRecordsQuery) ([]*entities.NotificationRecord, int64, error) {
|
||||
var records []entities.NotificationRecord
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.NotificationRecord{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.CertificationID != "" {
|
||||
dbQuery = dbQuery.Where("certification_id = ?", query.CertificationID)
|
||||
}
|
||||
if query.UserID != "" {
|
||||
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
|
||||
}
|
||||
if query.Type != "" {
|
||||
dbQuery = dbQuery.Where("type = ?", query.Type)
|
||||
}
|
||||
if query.IsRead != nil {
|
||||
dbQuery = dbQuery.Where("is_read = ?", *query.IsRead)
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&records).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
recordPtrs := make([]*entities.NotificationRecord, len(records))
|
||||
for i := range records {
|
||||
recordPtrs[i] = &records[i]
|
||||
}
|
||||
|
||||
return recordPtrs, total, nil
|
||||
}
|
||||
|
||||
// BatchCreate 批量创建通知记录
|
||||
func (r *GormNotificationRecordRepository) BatchCreate(ctx context.Context, records []entities.NotificationRecord) error {
|
||||
r.logger.Info("批量创建通知记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Create(&records).Error
|
||||
}
|
||||
|
||||
// MarkAsRead 标记通知记录为已读
|
||||
func (r *GormNotificationRecordRepository) MarkAsRead(ctx context.Context, recordIDs []string) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.NotificationRecord{}).
|
||||
Where("id IN ?", recordIDs).
|
||||
Update("is_read", true).Error; err != nil {
|
||||
r.logger.Error("标记通知记录为已读失败",
|
||||
zap.Strings("record_ids", recordIDs),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("标记通知记录为已读失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("通知记录标记为已读成功", zap.Strings("record_ids", recordIDs))
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarkAllAsReadByUser 标记用户所有通知记录为已读
|
||||
func (r *GormNotificationRecordRepository) MarkAllAsReadByUser(ctx context.Context, userID string) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.NotificationRecord{}).
|
||||
Where("user_id = ? AND is_read = ?", userID, false).
|
||||
Update("is_read", true).Error; err != nil {
|
||||
r.logger.Error("标记用户所有通知记录为已读失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fmt.Errorf("标记用户所有通知记录为已读失败: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("用户所有通知记录标记为已读成功", zap.String("user_id", userID))
|
||||
return nil
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
@@ -42,6 +43,12 @@ func (r *GormWalletRepository) Create(ctx context.Context, wallet entities.Walle
|
||||
func (r *GormWalletRepository) GetByID(ctx context.Context, id string) (entities.Wallet, error) {
|
||||
var wallet entities.Wallet
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&wallet).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.Wallet{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.Wallet{}, err
|
||||
}
|
||||
return wallet, err
|
||||
}
|
||||
|
||||
@@ -199,6 +206,9 @@ func (r *GormWalletRepository) GetByUserID(ctx context.Context, userID string) (
|
||||
var wallet entities.Wallet
|
||||
err := r.db.WithContext(ctx).Where("user_id = ?", userID).First(&wallet).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &wallet, nil
|
||||
@@ -209,6 +219,9 @@ func (r *GormWalletRepository) GetByWalletAddress(ctx context.Context, walletAdd
|
||||
var wallet entities.Wallet
|
||||
err := r.db.WithContext(ctx).Where("wallet_address = ?", walletAddress).First(&wallet).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &wallet, nil
|
||||
@@ -219,6 +232,9 @@ func (r *GormWalletRepository) GetByWalletType(ctx context.Context, userID strin
|
||||
var wallet entities.Wallet
|
||||
err := r.db.WithContext(ctx).Where("user_id = ? AND wallet_type = ?", userID, walletType).First(&wallet).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &wallet, nil
|
||||
@@ -384,6 +400,12 @@ func (r *GormUserSecretsRepository) Create(ctx context.Context, secrets entities
|
||||
func (r *GormUserSecretsRepository) GetByID(ctx context.Context, id string) (entities.UserSecrets, error) {
|
||||
var secrets entities.UserSecrets
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&secrets).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.UserSecrets{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.UserSecrets{}, err
|
||||
}
|
||||
return secrets, err
|
||||
}
|
||||
|
||||
@@ -503,21 +525,27 @@ func (r *GormUserSecretsRepository) WithTx(tx interface{}) interfaces.Repository
|
||||
return r
|
||||
}
|
||||
|
||||
// FindByUserID 根据用户ID查找密钥
|
||||
// FindByUserID 根据用户ID查找用户密钥
|
||||
func (r *GormUserSecretsRepository) FindByUserID(ctx context.Context, userID string) (*entities.UserSecrets, error) {
|
||||
var secrets entities.UserSecrets
|
||||
err := r.db.WithContext(ctx).Where("user_id = ?", userID).First(&secrets).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &secrets, nil
|
||||
}
|
||||
|
||||
// FindByAccessID 根据访问ID查找密钥
|
||||
// FindByAccessID 根据访问ID查找用户密钥
|
||||
func (r *GormUserSecretsRepository) FindByAccessID(ctx context.Context, accessID string) (*entities.UserSecrets, error) {
|
||||
var secrets entities.UserSecrets
|
||||
err := r.db.WithContext(ctx).Where("access_id = ?", accessID).First(&secrets).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &secrets, nil
|
||||
@@ -575,16 +603,22 @@ func (r *GormUserSecretsRepository) GetByUserID(ctx context.Context, userID stri
|
||||
var secrets entities.UserSecrets
|
||||
err := r.db.WithContext(ctx).Where("user_id = ?", userID).First(&secrets).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &secrets, nil
|
||||
}
|
||||
|
||||
// GetBySecretType 根据密钥类型获取用户密钥
|
||||
// GetBySecretType 根据用户ID和密钥类型获取用户密钥
|
||||
func (r *GormUserSecretsRepository) GetBySecretType(ctx context.Context, userID string, secretType string) (*entities.UserSecrets, error) {
|
||||
var secrets entities.UserSecrets
|
||||
err := r.db.WithContext(ctx).Where("user_id = ? AND secret_type = ?", userID, secretType).First(&secrets).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &secrets, nil
|
||||
|
||||
@@ -2,13 +2,15 @@ package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/product/entities"
|
||||
"tyapi-server/internal/domains/product/repositories"
|
||||
"tyapi-server/internal/domains/product/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// GormProductCategoryRepository GORM产品分类仓储实现
|
||||
@@ -39,7 +41,13 @@ func (r *GormProductCategoryRepository) Create(ctx context.Context, entity entit
|
||||
func (r *GormProductCategoryRepository) GetByID(ctx context.Context, id string) (entities.ProductCategory, error) {
|
||||
var entity entities.ProductCategory
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&entity).Error
|
||||
return entity, err
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.ProductCategory{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.ProductCategory{}, err
|
||||
}
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
// Update 更新产品分类
|
||||
@@ -59,40 +67,14 @@ func (r *GormProductCategoryRepository) FindByCode(ctx context.Context, code str
|
||||
var entity entities.ProductCategory
|
||||
err := r.db.WithContext(ctx).Where("code = ?", code).First(&entity).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &entity, nil
|
||||
}
|
||||
|
||||
// FindByParentID 根据父级ID查找产品分类
|
||||
func (r *GormProductCategoryRepository) FindByParentID(ctx context.Context, parentID *string) ([]*entities.ProductCategory, error) {
|
||||
var categories []entities.ProductCategory
|
||||
query := r.db.WithContext(ctx)
|
||||
|
||||
if parentID == nil {
|
||||
query = query.Where("parent_id IS NULL")
|
||||
} else {
|
||||
query = query.Where("parent_id = ?", *parentID)
|
||||
}
|
||||
|
||||
err := query.Find(&categories).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.ProductCategory, len(categories))
|
||||
for i := range categories {
|
||||
result[i] = &categories[i]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindRootCategories 查找根分类
|
||||
func (r *GormProductCategoryRepository) FindRootCategories(ctx context.Context) ([]*entities.ProductCategory, error) {
|
||||
return r.FindByParentID(ctx, nil)
|
||||
}
|
||||
|
||||
// FindVisible 查找可见分类
|
||||
func (r *GormProductCategoryRepository) FindVisible(ctx context.Context) ([]*entities.ProductCategory, error) {
|
||||
var categories []entities.ProductCategory
|
||||
@@ -133,9 +115,6 @@ func (r *GormProductCategoryRepository) ListCategories(ctx context.Context, quer
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.ProductCategory{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.ParentID != nil {
|
||||
dbQuery = dbQuery.Where("parent_id = ?", *query.ParentID)
|
||||
}
|
||||
if query.IsEnabled != nil {
|
||||
dbQuery = dbQuery.Where("is_enabled = ?", *query.IsEnabled)
|
||||
}
|
||||
@@ -158,7 +137,8 @@ func (r *GormProductCategoryRepository) ListCategories(ctx context.Context, quer
|
||||
}
|
||||
dbQuery = dbQuery.Order(order)
|
||||
} else {
|
||||
dbQuery = dbQuery.Order("sort_order ASC, created_at DESC")
|
||||
// 默认按排序字段和创建时间排序
|
||||
dbQuery = dbQuery.Order("sort ASC, created_at ASC")
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
@@ -181,66 +161,6 @@ func (r *GormProductCategoryRepository) ListCategories(ctx context.Context, quer
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// GetCategoryTree 获取分类树
|
||||
func (r *GormProductCategoryRepository) GetCategoryTree(ctx context.Context) ([]*entities.ProductCategory, error) {
|
||||
var categories []entities.ProductCategory
|
||||
err := r.db.WithContext(ctx).Where("is_enabled = ?", true).Order("sort_order ASC, created_at ASC").Find(&categories).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.ProductCategory, len(categories))
|
||||
for i := range categories {
|
||||
result[i] = &categories[i]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindCategoriesByLevel 根据层级查找分类
|
||||
func (r *GormProductCategoryRepository) FindCategoriesByLevel(ctx context.Context, level int) ([]*entities.ProductCategory, error) {
|
||||
var categories []entities.ProductCategory
|
||||
err := r.db.WithContext(ctx).Where("level = ? AND is_enabled = ?", level, true).Find(&categories).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.ProductCategory, len(categories))
|
||||
for i := range categories {
|
||||
result[i] = &categories[i]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindCategoryPath 查找分类路径
|
||||
func (r *GormProductCategoryRepository) FindCategoryPath(ctx context.Context, categoryID string) ([]*entities.ProductCategory, error) {
|
||||
// 这里需要递归查找父级分类,简化实现
|
||||
var entity entities.ProductCategory
|
||||
err := r.db.WithContext(ctx).Where("id = ?", categoryID).First(&entity).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []*entities.ProductCategory{&entity}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CountByParent 统计父级下的分类数量
|
||||
func (r *GormProductCategoryRepository) CountByParent(ctx context.Context, parentID *string) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.ProductCategory{})
|
||||
|
||||
if parentID == nil {
|
||||
query = query.Where("parent_id IS NULL")
|
||||
} else {
|
||||
query = query.Where("parent_id = ?", *parentID)
|
||||
}
|
||||
|
||||
err := query.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// CountEnabled 统计启用分类数量
|
||||
func (r *GormProductCategoryRepository) CountEnabled(ctx context.Context) (int64, error) {
|
||||
var count int64
|
||||
|
||||
@@ -2,6 +2,7 @@ package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"tyapi-server/internal/domains/product/entities"
|
||||
"tyapi-server/internal/domains/product/repositories"
|
||||
"tyapi-server/internal/domains/product/repositories/queries"
|
||||
@@ -38,8 +39,14 @@ func (r *GormProductRepository) Create(ctx context.Context, entity entities.Prod
|
||||
// GetByID 根据ID获取产品
|
||||
func (r *GormProductRepository) GetByID(ctx context.Context, id string) (entities.Product, error) {
|
||||
var entity entities.Product
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&entity).Error
|
||||
return entity, err
|
||||
err := r.db.WithContext(ctx).Preload("Category").Where("id = ?", id).First(&entity).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.Product{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.Product{}, err
|
||||
}
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
// Update 更新产品
|
||||
@@ -57,8 +64,11 @@ func (r *GormProductRepository) Delete(ctx context.Context, id string) error {
|
||||
// FindByCode 根据编号查找产品
|
||||
func (r *GormProductRepository) FindByCode(ctx context.Context, code string) (*entities.Product, error) {
|
||||
var entity entities.Product
|
||||
err := r.db.WithContext(ctx).Where("code = ?", code).First(&entity).Error
|
||||
err := r.db.WithContext(ctx).Preload("Category").Where("code = ?", code).First(&entity).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &entity, nil
|
||||
@@ -67,7 +77,7 @@ func (r *GormProductRepository) FindByCode(ctx context.Context, code string) (*e
|
||||
// FindByCategoryID 根据分类ID查找产品
|
||||
func (r *GormProductRepository) FindByCategoryID(ctx context.Context, categoryID string) ([]*entities.Product, error) {
|
||||
var productEntities []entities.Product
|
||||
err := r.db.WithContext(ctx).Where("category_id = ?", categoryID).Find(&productEntities).Error
|
||||
err := r.db.WithContext(ctx).Preload("Category").Where("category_id = ?", categoryID).Find(&productEntities).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -83,7 +93,7 @@ func (r *GormProductRepository) FindByCategoryID(ctx context.Context, categoryID
|
||||
// FindVisible 查找可见产品
|
||||
func (r *GormProductRepository) FindVisible(ctx context.Context) ([]*entities.Product, error) {
|
||||
var productEntities []entities.Product
|
||||
err := r.db.WithContext(ctx).Where("is_visible = ? AND is_enabled = ?", true, true).Find(&productEntities).Error
|
||||
err := r.db.WithContext(ctx).Preload("Category").Where("is_visible = ? AND is_enabled = ?", true, true).Find(&productEntities).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -99,7 +109,7 @@ func (r *GormProductRepository) FindVisible(ctx context.Context) ([]*entities.Pr
|
||||
// FindEnabled 查找启用产品
|
||||
func (r *GormProductRepository) FindEnabled(ctx context.Context) ([]*entities.Product, error) {
|
||||
var productEntities []entities.Product
|
||||
err := r.db.WithContext(ctx).Where("is_enabled = ?", true).Find(&productEntities).Error
|
||||
err := r.db.WithContext(ctx).Preload("Category").Where("is_enabled = ?", true).Find(&productEntities).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -167,8 +177,8 @@ func (r *GormProductRepository) ListProducts(ctx context.Context, query *queries
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
if err := dbQuery.Find(&productEntities).Error; err != nil {
|
||||
// 预加载分类信息并获取数据
|
||||
if err := dbQuery.Preload("Category").Find(&productEntities).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,15 @@ package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
"errors"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/product/entities"
|
||||
"tyapi-server/internal/domains/product/repositories"
|
||||
"tyapi-server/internal/domains/product/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// GormSubscriptionRepository GORM订阅仓储实现
|
||||
@@ -40,7 +41,13 @@ func (r *GormSubscriptionRepository) Create(ctx context.Context, entity entities
|
||||
func (r *GormSubscriptionRepository) GetByID(ctx context.Context, id string) (entities.Subscription, error) {
|
||||
var entity entities.Subscription
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&entity).Error
|
||||
return entity, err
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.Subscription{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.Subscription{}, err
|
||||
}
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
// Update 更新订阅
|
||||
@@ -62,7 +69,7 @@ func (r *GormSubscriptionRepository) FindByUserID(ctx context.Context, userID st
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.Subscription, len(subscriptions))
|
||||
for i := range subscriptions {
|
||||
@@ -78,7 +85,7 @@ func (r *GormSubscriptionRepository) FindByProductID(ctx context.Context, produc
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.Subscription, len(subscriptions))
|
||||
for i := range subscriptions {
|
||||
@@ -92,50 +99,36 @@ func (r *GormSubscriptionRepository) FindByUserAndProduct(ctx context.Context, u
|
||||
var entity entities.Subscription
|
||||
err := r.db.WithContext(ctx).Where("user_id = ? AND product_id = ?", userID, productID).First(&entity).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &entity, nil
|
||||
}
|
||||
|
||||
// FindActive 查找活跃订阅
|
||||
func (r *GormSubscriptionRepository) FindActive(ctx context.Context) ([]*entities.Subscription, error) {
|
||||
var subscriptions []entities.Subscription
|
||||
err := r.db.WithContext(ctx).Where("status = ?", entities.SubscriptionStatusActive).Find(&subscriptions).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.Subscription, len(subscriptions))
|
||||
for i := range subscriptions {
|
||||
result[i] = &subscriptions[i]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ListSubscriptions 获取订阅列表
|
||||
func (r *GormSubscriptionRepository) ListSubscriptions(ctx context.Context, query *queries.ListSubscriptionsQuery) ([]*entities.Subscription, int64, error) {
|
||||
var subscriptions []entities.Subscription
|
||||
var total int64
|
||||
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.Subscription{})
|
||||
|
||||
|
||||
// 应用筛选条件
|
||||
if query.UserID != "" {
|
||||
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
|
||||
}
|
||||
if query.ProductID != "" {
|
||||
dbQuery = dbQuery.Where("product_id = ?", query.ProductID)
|
||||
// 这里筛选的是关联的Product实体里的name或code字段,只有当keyword匹配关联Product的name或code时才返回
|
||||
if query.Keyword != "" {
|
||||
dbQuery = dbQuery.Joins("LEFT JOIN product ON product.id = subscription.product_id").
|
||||
Where("product.name LIKE ? OR product.code LIKE ?", "%"+query.Keyword+"%", "%"+query.Keyword+"%")
|
||||
}
|
||||
if query.Status != "" {
|
||||
dbQuery = dbQuery.Where("status = ?", query.Status)
|
||||
}
|
||||
|
||||
|
||||
// 获取总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
|
||||
// 应用排序
|
||||
if query.SortBy != "" {
|
||||
order := query.SortBy
|
||||
@@ -148,92 +141,34 @@ func (r *GormSubscriptionRepository) ListSubscriptions(ctx context.Context, quer
|
||||
} else {
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
}
|
||||
|
||||
|
||||
// 应用分页
|
||||
if query.Page > 0 && query.PageSize > 0 {
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
if err := dbQuery.Find(&subscriptions).Error; err != nil {
|
||||
|
||||
// 预加载Product的id、name、code字段,并同时预加载ProductCategory的id、name、code字段
|
||||
if err := dbQuery.
|
||||
Preload("Product", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Select("id", "name", "code", "category_id").
|
||||
Preload("Category", func(db2 *gorm.DB) *gorm.DB {
|
||||
return db2.Select("id", "name", "code")
|
||||
})
|
||||
}).
|
||||
Find(&subscriptions).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.Subscription, len(subscriptions))
|
||||
for i := range subscriptions {
|
||||
result[i] = &subscriptions[i]
|
||||
}
|
||||
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// FindUserActiveSubscriptions 查找用户活跃订阅
|
||||
func (r *GormSubscriptionRepository) FindUserActiveSubscriptions(ctx context.Context, userID string) ([]*entities.Subscription, error) {
|
||||
var subscriptions []entities.Subscription
|
||||
err := r.db.WithContext(ctx).Where("user_id = ? AND status = ?", userID, entities.SubscriptionStatusActive).Find(&subscriptions).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.Subscription, len(subscriptions))
|
||||
for i := range subscriptions {
|
||||
result[i] = &subscriptions[i]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindExpiredSubscriptions 查找过期订阅
|
||||
func (r *GormSubscriptionRepository) FindExpiredSubscriptions(ctx context.Context) ([]*entities.Subscription, error) {
|
||||
var subscriptions []entities.Subscription
|
||||
now := time.Now()
|
||||
err := r.db.WithContext(ctx).Where("end_date IS NOT NULL AND end_date < ? AND status = ?", now, entities.SubscriptionStatusActive).Find(&subscriptions).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.Subscription, len(subscriptions))
|
||||
for i := range subscriptions {
|
||||
result[i] = &subscriptions[i]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindSubscriptionsByStatus 根据状态查找订阅
|
||||
func (r *GormSubscriptionRepository) FindSubscriptionsByStatus(ctx context.Context, status entities.SubscriptionStatus) ([]*entities.Subscription, error) {
|
||||
var subscriptions []entities.Subscription
|
||||
err := r.db.WithContext(ctx).Where("status = ?", status).Find(&subscriptions).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.Subscription, len(subscriptions))
|
||||
for i := range subscriptions {
|
||||
result[i] = &subscriptions[i]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindSubscriptionsByDateRange 根据日期范围查找订阅
|
||||
func (r *GormSubscriptionRepository) FindSubscriptionsByDateRange(ctx context.Context, startDate, endDate string) ([]*entities.Subscription, error) {
|
||||
var subscriptions []entities.Subscription
|
||||
err := r.db.WithContext(ctx).Where("created_at BETWEEN ? AND ?", startDate, endDate).Find(&subscriptions).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.Subscription, len(subscriptions))
|
||||
for i := range subscriptions {
|
||||
result[i] = &subscriptions[i]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CountByUser 统计用户订阅数量
|
||||
func (r *GormSubscriptionRepository) CountByUser(ctx context.Context, userID string) (int64, error) {
|
||||
var count int64
|
||||
@@ -248,39 +183,25 @@ func (r *GormSubscriptionRepository) CountByProduct(ctx context.Context, product
|
||||
return count, err
|
||||
}
|
||||
|
||||
// CountByStatus 根据状态统计订阅数量
|
||||
func (r *GormSubscriptionRepository) CountByStatus(ctx context.Context, status entities.SubscriptionStatus) (int64, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.Subscription{}).Where("status = ?", status).Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// CountActive 统计活跃订阅数量
|
||||
func (r *GormSubscriptionRepository) CountActive(ctx context.Context) (int64, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.Subscription{}).Where("status = ?", entities.SubscriptionStatusActive).Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// 基础Repository接口方法
|
||||
|
||||
// Count 返回订阅总数
|
||||
func (r *GormSubscriptionRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.Subscription{})
|
||||
|
||||
|
||||
// 应用筛选条件
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 应用搜索条件
|
||||
if options.Search != "" {
|
||||
query = query.Where("user_id LIKE ? OR product_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
|
||||
err := query.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
@@ -311,19 +232,19 @@ func (r *GormSubscriptionRepository) DeleteBatch(ctx context.Context, ids []stri
|
||||
func (r *GormSubscriptionRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.Subscription, error) {
|
||||
var subscriptions []entities.Subscription
|
||||
query := r.db.WithContext(ctx).Model(&entities.Subscription{})
|
||||
|
||||
|
||||
// 应用筛选条件
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 应用搜索条件
|
||||
if options.Search != "" {
|
||||
query = query.Where("user_id LIKE ? OR product_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
|
||||
// 应用排序
|
||||
if options.Sort != "" {
|
||||
order := options.Sort
|
||||
@@ -334,13 +255,13 @@ func (r *GormSubscriptionRepository) List(ctx context.Context, options interface
|
||||
}
|
||||
query = query.Order(order)
|
||||
}
|
||||
|
||||
|
||||
// 应用分页
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
|
||||
err := query.Find(&subscriptions).Error
|
||||
return subscriptions, err
|
||||
}
|
||||
@@ -371,4 +292,4 @@ func (r *GormSubscriptionRepository) WithTx(tx interface{}) interfaces.Repositor
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -40,7 +41,7 @@ func (r *GormEnterpriseInfoRepository) Create(ctx context.Context, enterpriseInf
|
||||
func (r *GormEnterpriseInfoRepository) GetByID(ctx context.Context, id string) (entities.EnterpriseInfo, error) {
|
||||
var enterpriseInfo entities.EnterpriseInfo
|
||||
if err := r.db.WithContext(ctx).Where("id = ?", id).First(&enterpriseInfo).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.EnterpriseInfo{}, fmt.Errorf("企业信息不存在")
|
||||
}
|
||||
r.logger.Error("获取企业信息失败", zap.Error(err))
|
||||
@@ -51,11 +52,6 @@ func (r *GormEnterpriseInfoRepository) GetByID(ctx context.Context, id string) (
|
||||
|
||||
// Update 更新企业信息
|
||||
func (r *GormEnterpriseInfoRepository) Update(ctx context.Context, enterpriseInfo entities.EnterpriseInfo) error {
|
||||
// 检查企业信息是否已认证完成,认证完成后不可修改
|
||||
if enterpriseInfo.IsReadOnly() {
|
||||
return fmt.Errorf("企业信息已认证完成,不可修改")
|
||||
}
|
||||
|
||||
if err := r.db.WithContext(ctx).Save(&enterpriseInfo).Error; err != nil {
|
||||
r.logger.Error("更新企业信息失败", zap.Error(err))
|
||||
return fmt.Errorf("更新企业信息失败: %w", err)
|
||||
@@ -94,7 +90,7 @@ func (r *GormEnterpriseInfoRepository) Restore(ctx context.Context, id string) e
|
||||
func (r *GormEnterpriseInfoRepository) GetByUserID(ctx context.Context, userID string) (*entities.EnterpriseInfo, error) {
|
||||
var enterpriseInfo entities.EnterpriseInfo
|
||||
if err := r.db.WithContext(ctx).Where("user_id = ?", userID).First(&enterpriseInfo).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("企业信息不存在")
|
||||
}
|
||||
r.logger.Error("获取企业信息失败", zap.Error(err))
|
||||
@@ -107,7 +103,7 @@ func (r *GormEnterpriseInfoRepository) GetByUserID(ctx context.Context, userID s
|
||||
func (r *GormEnterpriseInfoRepository) GetByUnifiedSocialCode(ctx context.Context, unifiedSocialCode string) (*entities.EnterpriseInfo, error) {
|
||||
var enterpriseInfo entities.EnterpriseInfo
|
||||
if err := r.db.WithContext(ctx).Where("unified_social_code = ?", unifiedSocialCode).First(&enterpriseInfo).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("企业信息不存在")
|
||||
}
|
||||
r.logger.Error("获取企业信息失败", zap.Error(err))
|
||||
|
||||
@@ -5,6 +5,7 @@ package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -17,18 +18,16 @@ import (
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// SMSCodeRepository 短信验证码仓储
|
||||
// GormSMSCodeRepository 短信验证码GORM仓储实现(无缓存,确保安全性)
|
||||
type GormSMSCodeRepository struct {
|
||||
db *gorm.DB
|
||||
cache interfaces.CacheService
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewGormSMSCodeRepository 创建短信验证码仓储
|
||||
func NewGormSMSCodeRepository(db *gorm.DB, cache interfaces.CacheService, logger *zap.Logger) repositories.SMSCodeRepository {
|
||||
func NewGormSMSCodeRepository(db *gorm.DB, logger *zap.Logger) repositories.SMSCodeRepository {
|
||||
return &GormSMSCodeRepository{
|
||||
db: db,
|
||||
cache: cache,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
@@ -36,19 +35,15 @@ func NewGormSMSCodeRepository(db *gorm.DB, cache interfaces.CacheService, logger
|
||||
// 确保 GormSMSCodeRepository 实现了 SMSCodeRepository 接口
|
||||
var _ repositories.SMSCodeRepository = (*GormSMSCodeRepository)(nil)
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
// ================ Repository[T] 接口实现 ================
|
||||
|
||||
// Create 创建短信验证码记录
|
||||
// Create 创建短信验证码记录(不缓存,确保安全性)
|
||||
func (r *GormSMSCodeRepository) Create(ctx context.Context, smsCode entities.SMSCode) (entities.SMSCode, error) {
|
||||
if err := r.db.WithContext(ctx).Create(&smsCode).Error; err != nil {
|
||||
r.logger.Error("创建短信验证码失败", zap.Error(err))
|
||||
return entities.SMSCode{}, err
|
||||
}
|
||||
|
||||
// 缓存验证码
|
||||
cacheKey := r.buildCacheKey(smsCode.Phone, smsCode.Scene)
|
||||
r.cache.Set(ctx, cacheKey, &smsCode, 5*time.Minute)
|
||||
|
||||
return smsCode, nil
|
||||
}
|
||||
|
||||
@@ -56,7 +51,7 @@ func (r *GormSMSCodeRepository) Create(ctx context.Context, smsCode entities.SMS
|
||||
func (r *GormSMSCodeRepository) GetByID(ctx context.Context, id string) (entities.SMSCode, error) {
|
||||
var smsCode entities.SMSCode
|
||||
if err := r.db.WithContext(ctx).Where("id = ?", id).First(&smsCode).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.SMSCode{}, fmt.Errorf("短信验证码不存在")
|
||||
}
|
||||
r.logger.Error("获取短信验证码失败", zap.Error(err))
|
||||
@@ -69,74 +64,15 @@ func (r *GormSMSCodeRepository) GetByID(ctx context.Context, id string) (entitie
|
||||
// Update 更新验证码记录
|
||||
func (r *GormSMSCodeRepository) Update(ctx context.Context, smsCode entities.SMSCode) error {
|
||||
if err := r.db.WithContext(ctx).Save(&smsCode).Error; err != nil {
|
||||
r.logger.Error("更新验证码记录失败", zap.Error(err))
|
||||
r.logger.Error("更新短信验证码失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新缓存
|
||||
cacheKey := r.buildCacheKey(smsCode.Phone, smsCode.Scene)
|
||||
r.cache.Set(ctx, cacheKey, &smsCode, 5*time.Minute)
|
||||
|
||||
r.logger.Info("验证码记录更新成功", zap.String("code_id", smsCode.ID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete 删除短信验证码
|
||||
func (r *GormSMSCodeRepository) Delete(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Delete(&entities.SMSCode{}, "id = ?", id).Error; err != nil {
|
||||
r.logger.Error("删除短信验证码失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
r.logger.Info("短信验证码删除成功", zap.String("id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// SoftDelete 软删除短信验证码
|
||||
func (r *GormSMSCodeRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// Restore 恢复短信验证码
|
||||
func (r *GormSMSCodeRepository) Restore(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Unscoped().Model(&entities.SMSCode{}).Where("id = ?", id).Update("deleted_at", nil).Error; err != nil {
|
||||
r.logger.Error("恢复短信验证码失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
r.logger.Info("短信验证码恢复成功", zap.String("id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Count 统计短信验证码数量
|
||||
func (r *GormSMSCodeRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.SMSCode{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("phone LIKE ? OR code LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
err := query.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// Exists 检查短信验证码是否存在
|
||||
func (r *GormSMSCodeRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.SMSCode{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建短信验证码
|
||||
func (r *GormSMSCodeRepository) CreateBatch(ctx context.Context, smsCodes []entities.SMSCode) error {
|
||||
r.logger.Info("批量创建短信验证码", zap.Int("count", len(smsCodes)))
|
||||
return r.db.WithContext(ctx).Create(&smsCodes).Error
|
||||
}
|
||||
|
||||
@@ -149,13 +85,11 @@ func (r *GormSMSCodeRepository) GetByIDs(ctx context.Context, ids []string) ([]e
|
||||
|
||||
// UpdateBatch 批量更新短信验证码
|
||||
func (r *GormSMSCodeRepository) UpdateBatch(ctx context.Context, smsCodes []entities.SMSCode) error {
|
||||
r.logger.Info("批量更新短信验证码", zap.Int("count", len(smsCodes)))
|
||||
return r.db.WithContext(ctx).Save(&smsCodes).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除短信验证码
|
||||
func (r *GormSMSCodeRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除短信验证码", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.SMSCode{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
@@ -164,24 +98,35 @@ func (r *GormSMSCodeRepository) List(ctx context.Context, options interfaces.Lis
|
||||
var smsCodes []entities.SMSCode
|
||||
query := r.db.WithContext(ctx).Model(&entities.SMSCode{})
|
||||
|
||||
// 应用筛选条件
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
// 应用搜索条件
|
||||
if options.Search != "" {
|
||||
query = query.Where("phone LIKE ? OR code LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
query = query.Where("phone LIKE ?", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
// 应用预加载
|
||||
for _, include := range options.Include {
|
||||
query = query.Preload(include)
|
||||
}
|
||||
|
||||
// 应用排序
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
if options.Order == "desc" || options.Order == "DESC" {
|
||||
order = "DESC"
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
} else {
|
||||
query = query.Order("created_at DESC")
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
@@ -190,97 +135,148 @@ func (r *GormSMSCodeRepository) List(ctx context.Context, options interfaces.Lis
|
||||
return smsCodes, query.Find(&smsCodes).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormSMSCodeRepository) WithTx(tx interface{}) interfaces.Repository[entities.SMSCode] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormSMSCodeRepository{
|
||||
db: gormTx,
|
||||
cache: r.cache,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
// ================ BaseRepository 接口实现 ================
|
||||
|
||||
// Delete 删除短信验证码
|
||||
func (r *GormSMSCodeRepository) Delete(ctx context.Context, id string) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.SMSCode{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
// Exists 检查短信验证码是否存在
|
||||
func (r *GormSMSCodeRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.SMSCode{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// Count 统计短信验证码数量
|
||||
func (r *GormSMSCodeRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.SMSCode{})
|
||||
|
||||
// 应用筛选条件
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
// 应用搜索条件
|
||||
if options.Search != "" {
|
||||
query = query.Where("phone LIKE ?", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
err := query.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// SoftDelete 软删除短信验证码
|
||||
func (r *GormSMSCodeRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.SMSCode{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// Restore 恢复短信验证码
|
||||
func (r *GormSMSCodeRepository) Restore(ctx context.Context, id string) error {
|
||||
return r.db.WithContext(ctx).Unscoped().Model(&entities.SMSCode{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
||||
}
|
||||
|
||||
// ================ 业务专用方法 ================
|
||||
|
||||
// GetByPhone 根据手机号获取短信验证码
|
||||
func (r *GormSMSCodeRepository) GetByPhone(ctx context.Context, phone string) (*entities.SMSCode, error) {
|
||||
var smsCode entities.SMSCode
|
||||
if err := r.db.WithContext(ctx).Where("phone = ?", phone).Order("created_at DESC").First(&smsCode).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("短信验证码不存在")
|
||||
}
|
||||
r.logger.Error("根据手机号获取短信验证码失败", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &smsCode, nil
|
||||
}
|
||||
|
||||
// GetLatestByPhone 根据手机号获取最新的短信验证码
|
||||
// GetLatestByPhone 根据手机号获取最新短信验证码
|
||||
func (r *GormSMSCodeRepository) GetLatestByPhone(ctx context.Context, phone string) (*entities.SMSCode, error) {
|
||||
return r.GetByPhone(ctx, phone)
|
||||
var smsCode entities.SMSCode
|
||||
if err := r.db.WithContext(ctx).Where("phone = ?", phone).Order("created_at DESC").First(&smsCode).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("短信验证码不存在")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &smsCode, nil
|
||||
}
|
||||
|
||||
// GetValidByPhone 根据手机号获取有效的短信验证码
|
||||
func (r *GormSMSCodeRepository) GetValidByPhone(ctx context.Context, phone string) (*entities.SMSCode, error) {
|
||||
return r.GetValidCode(ctx, phone, "")
|
||||
var smsCode entities.SMSCode
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("phone = ? AND expires_at > ? AND used_at IS NULL", phone, time.Now()).
|
||||
Order("created_at DESC").
|
||||
First(&smsCode).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("有效的短信验证码不存在")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &smsCode, nil
|
||||
}
|
||||
|
||||
// GetValidByPhoneAndScene 根据手机号和场景获取有效的验证码
|
||||
// GetValidByPhoneAndScene 根据手机号和场景获取有效的短信验证码
|
||||
func (r *GormSMSCodeRepository) GetValidByPhoneAndScene(ctx context.Context, phone string, scene entities.SMSScene) (*entities.SMSCode, error) {
|
||||
return r.GetValidCode(ctx, phone, scene)
|
||||
var smsCode entities.SMSCode
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("phone = ? AND scene = ? AND expires_at > ? AND used_at IS NULL", phone, scene, time.Now()).
|
||||
Order("created_at DESC").
|
||||
First(&smsCode).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("有效的短信验证码不存在")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &smsCode, nil
|
||||
}
|
||||
|
||||
// ListSMSCodes 获取短信验证码列表(带分页和筛选)
|
||||
func (r *GormSMSCodeRepository) ListSMSCodes(ctx context.Context, query *queries.ListSMSCodesQuery) ([]*entities.SMSCode, int64, error) {
|
||||
var smsCodes []entities.SMSCode
|
||||
var smsCodes []*entities.SMSCode
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.SMSCode{})
|
||||
// 构建查询条件
|
||||
db := r.db.WithContext(ctx).Model(&entities.SMSCode{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.Phone != "" {
|
||||
dbQuery = dbQuery.Where("phone = ?", query.Phone)
|
||||
db = db.Where("phone = ?", query.Phone)
|
||||
}
|
||||
if query.Purpose != "" {
|
||||
dbQuery = dbQuery.Where("scene = ?", query.Purpose)
|
||||
db = db.Where("scene = ?", query.Purpose)
|
||||
}
|
||||
if query.Status != "" {
|
||||
dbQuery = dbQuery.Where("status = ?", query.Status)
|
||||
db = db.Where("used = ?", query.Status == "used")
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
db = db.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
db = db.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
if err := db.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&smsCodes).Error; err != nil {
|
||||
if err := db.Offset(offset).Limit(query.PageSize).Order("created_at DESC").Find(&smsCodes).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
smsCodePtrs := make([]*entities.SMSCode, len(smsCodes))
|
||||
for i := range smsCodes {
|
||||
smsCodePtrs[i] = &smsCodes[i]
|
||||
}
|
||||
|
||||
return smsCodePtrs, total, nil
|
||||
return smsCodes, total, nil
|
||||
}
|
||||
|
||||
// CreateCode 创建验证码
|
||||
@@ -288,87 +284,63 @@ func (r *GormSMSCodeRepository) CreateCode(ctx context.Context, phone string, co
|
||||
smsCode := entities.SMSCode{
|
||||
Phone: phone,
|
||||
Code: code,
|
||||
Scene: entities.SMSScene(purpose),
|
||||
ExpiresAt: time.Now().Add(5 * time.Minute), // 5分钟过期
|
||||
Used: false,
|
||||
Scene: entities.SMSScene(purpose), // 使用Scene字段
|
||||
ExpiresAt: time.Now().Add(5 * time.Minute), // 5分钟有效期
|
||||
}
|
||||
|
||||
return r.Create(ctx, smsCode)
|
||||
if err := r.db.WithContext(ctx).Create(&smsCode).Error; err != nil {
|
||||
r.logger.Error("创建短信验证码失败", zap.Error(err))
|
||||
return entities.SMSCode{}, err
|
||||
}
|
||||
|
||||
return smsCode, nil
|
||||
}
|
||||
|
||||
// ValidateCode 验证验证码
|
||||
func (r *GormSMSCodeRepository) ValidateCode(ctx context.Context, phone string, code string, purpose string) (bool, error) {
|
||||
var smsCode entities.SMSCode
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("phone = ? AND code = ? AND scene = ? AND expires_at > ? AND used_at IS NULL",
|
||||
phone, code, purpose, time.Now()).
|
||||
First(&smsCode).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return false, nil
|
||||
}
|
||||
r.logger.Error("验证验证码失败", zap.Error(err))
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 标记为已使用
|
||||
if err := r.MarkAsUsed(ctx, smsCode.ID); err != nil {
|
||||
r.logger.Error("标记验证码为已使用失败", zap.Error(err))
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.SMSCode{}).
|
||||
Where("phone = ? AND code = ? AND scene = ? AND expires_at > ? AND used_at IS NULL", phone, code, purpose, time.Now()).
|
||||
Count(&count).Error
|
||||
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// InvalidateCode 使验证码失效
|
||||
func (r *GormSMSCodeRepository) InvalidateCode(ctx context.Context, phone string) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.SMSCode{}).
|
||||
now := time.Now()
|
||||
return r.db.WithContext(ctx).Model(&entities.SMSCode{}).
|
||||
Where("phone = ? AND used_at IS NULL", phone).
|
||||
Update("used_at", time.Now()).Error; err != nil {
|
||||
r.logger.Error("使验证码失效失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 清除缓存
|
||||
cacheKey := r.buildCacheKey(phone, "")
|
||||
r.cache.Delete(ctx, cacheKey)
|
||||
|
||||
r.logger.Info("验证码已失效", zap.String("phone", phone))
|
||||
return nil
|
||||
Update("used_at", &now).Error
|
||||
}
|
||||
|
||||
// CheckSendFrequency 检查发送频率
|
||||
func (r *GormSMSCodeRepository) CheckSendFrequency(ctx context.Context, phone string, purpose string) (bool, error) {
|
||||
// 检查最近1分钟内是否已发送
|
||||
// 检查1分钟内是否已发送
|
||||
oneMinuteAgo := time.Now().Add(-1 * time.Minute)
|
||||
var count int64
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.SMSCode{}).
|
||||
|
||||
err := r.db.WithContext(ctx).Model(&entities.SMSCode{}).
|
||||
Where("phone = ? AND scene = ? AND created_at > ?", phone, purpose, oneMinuteAgo).
|
||||
Count(&count).Error; err != nil {
|
||||
r.logger.Error("检查发送频率失败", zap.Error(err))
|
||||
return false, err
|
||||
}
|
||||
|
||||
return count == 0, nil
|
||||
Count(&count).Error
|
||||
|
||||
// 如果1分钟内已发送,则返回false(不允许发送)
|
||||
return count == 0, err
|
||||
}
|
||||
|
||||
// GetTodaySendCount 获取今日发送次数
|
||||
// GetTodaySendCount 获取今日发送数量
|
||||
func (r *GormSMSCodeRepository) GetTodaySendCount(ctx context.Context, phone string) (int64, error) {
|
||||
today := time.Now().Truncate(24 * time.Hour)
|
||||
var count int64
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.SMSCode{}).
|
||||
|
||||
err := r.db.WithContext(ctx).Model(&entities.SMSCode{}).
|
||||
Where("phone = ? AND created_at >= ?", phone, today).
|
||||
Count(&count).Error; err != nil {
|
||||
r.logger.Error("获取今日发送次数失败", zap.Error(err))
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return count, nil
|
||||
Count(&count).Error
|
||||
|
||||
return count, err
|
||||
}
|
||||
|
||||
// GetCodeStats 获取验证码统计信息
|
||||
// GetCodeStats 获取验证码统计
|
||||
func (r *GormSMSCodeRepository) GetCodeStats(ctx context.Context, phone string, days int) (*repositories.SMSCodeStats, error) {
|
||||
var stats repositories.SMSCodeStats
|
||||
|
||||
@@ -406,94 +378,4 @@ func (r *GormSMSCodeRepository) GetCodeStats(ctx context.Context, phone string,
|
||||
}
|
||||
|
||||
return &stats, nil
|
||||
}
|
||||
|
||||
// GetValidCode 获取有效的验证码
|
||||
func (r *GormSMSCodeRepository) GetValidCode(ctx context.Context, phone string, scene entities.SMSScene) (*entities.SMSCode, error) {
|
||||
// 先从缓存查找
|
||||
cacheKey := r.buildCacheKey(phone, scene)
|
||||
var smsCode entities.SMSCode
|
||||
if err := r.cache.Get(ctx, cacheKey, &smsCode); err == nil {
|
||||
return &smsCode, nil
|
||||
}
|
||||
|
||||
// 从数据库查找最新的有效验证码
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("phone = ? AND scene = ? AND expires_at > ? AND used_at IS NULL",
|
||||
phone, scene, time.Now()).
|
||||
Order("created_at DESC").
|
||||
First(&smsCode).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 缓存结果
|
||||
r.cache.Set(ctx, cacheKey, &smsCode, 5*time.Minute)
|
||||
|
||||
return &smsCode, nil
|
||||
}
|
||||
|
||||
// MarkAsUsed 标记验证码为已使用
|
||||
func (r *GormSMSCodeRepository) MarkAsUsed(ctx context.Context, id string) error {
|
||||
now := time.Now()
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.SMSCode{}).
|
||||
Where("id = ?", id).
|
||||
Update("used_at", now).Error; err != nil {
|
||||
r.logger.Error("标记验证码为已使用失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
r.logger.Info("验证码已标记为使用", zap.String("code_id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRecentCode 获取最近的验证码记录(不限制有效性)
|
||||
func (r *GormSMSCodeRepository) GetRecentCode(ctx context.Context, phone string, scene entities.SMSScene) (*entities.SMSCode, error) {
|
||||
var smsCode entities.SMSCode
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("phone = ? AND scene = ?", phone, scene).
|
||||
Order("created_at DESC").
|
||||
First(&smsCode).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &smsCode, nil
|
||||
}
|
||||
|
||||
// CleanupExpired 清理过期的验证码
|
||||
func (r *GormSMSCodeRepository) CleanupExpired(ctx context.Context) error {
|
||||
result := r.db.WithContext(ctx).
|
||||
Where("expires_at < ?", time.Now()).
|
||||
Delete(&entities.SMSCode{})
|
||||
|
||||
if result.Error != nil {
|
||||
r.logger.Error("清理过期验证码失败", zap.Error(result.Error))
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected > 0 {
|
||||
r.logger.Info("清理过期验证码完成", zap.Int64("count", result.RowsAffected))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CountRecentCodes 统计最近发送的验证码数量
|
||||
func (r *GormSMSCodeRepository) CountRecentCodes(ctx context.Context, phone string, scene entities.SMSScene, duration time.Duration) (int64, error) {
|
||||
var count int64
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.SMSCode{}).
|
||||
Where("phone = ? AND scene = ? AND created_at > ?",
|
||||
phone, scene, time.Now().Add(-duration)).
|
||||
Count(&count).Error; err != nil {
|
||||
r.logger.Error("统计最近验证码数量失败", zap.Error(err))
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// buildCacheKey 构建缓存键
|
||||
func (r *GormSMSCodeRepository) buildCacheKey(phone string, scene entities.SMSScene) string {
|
||||
return fmt.Sprintf("sms_code:%s:%s", phone, string(scene))
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ package repositories
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
@@ -24,18 +23,16 @@ var (
|
||||
ErrUserNotFound = errors.New("用户不存在")
|
||||
)
|
||||
|
||||
// UserRepository 用户仓储实现
|
||||
// UserRepository 用户仓储实现(已移除手动缓存管理)
|
||||
type GormUserRepository struct {
|
||||
db *gorm.DB
|
||||
cache interfaces.CacheService
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewGormUserRepository 创建用户仓储
|
||||
func NewGormUserRepository(db *gorm.DB, cache interfaces.CacheService, logger *zap.Logger) repositories.UserRepository {
|
||||
func NewGormUserRepository(db *gorm.DB, logger *zap.Logger) repositories.UserRepository {
|
||||
return &GormUserRepository{
|
||||
db: db,
|
||||
cache: cache,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
@@ -43,34 +40,21 @@ func NewGormUserRepository(db *gorm.DB, cache interfaces.CacheService, logger *z
|
||||
// 确保 GormUserRepository 实现了 UserRepository 接口
|
||||
var _ repositories.UserRepository = (*GormUserRepository)(nil)
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
// ================ Repository[T] 接口实现 ================
|
||||
|
||||
// Create 创建用户
|
||||
// Create 创建用户(自动缓存失效)
|
||||
func (r *GormUserRepository) Create(ctx context.Context, user entities.User) (entities.User, error) {
|
||||
if err := r.db.WithContext(ctx).Create(&user).Error; err != nil {
|
||||
r.logger.Error("创建用户失败", zap.Error(err))
|
||||
return entities.User{}, err
|
||||
}
|
||||
|
||||
// 清除相关缓存
|
||||
r.deleteCacheByPhone(ctx, user.Phone)
|
||||
|
||||
r.logger.Info("用户创建成功", zap.String("user_id", user.ID))
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取用户
|
||||
// GetByID 根据ID获取用户(自动缓存)
|
||||
func (r *GormUserRepository) GetByID(ctx context.Context, id string) (entities.User, error) {
|
||||
// 尝试从缓存获取
|
||||
cacheKey := fmt.Sprintf("user:id:%s", id)
|
||||
var userCache entities.UserCache
|
||||
if err := r.cache.Get(ctx, cacheKey, &userCache); err == nil {
|
||||
var user entities.User
|
||||
user.FromCache(&userCache)
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// 从数据库查询
|
||||
var user entities.User
|
||||
if err := r.db.WithContext(ctx).Where("id = ?", id).First(&user).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
@@ -80,109 +64,20 @@ func (r *GormUserRepository) GetByID(ctx context.Context, id string) (entities.U
|
||||
return entities.User{}, err
|
||||
}
|
||||
|
||||
// 缓存结果
|
||||
r.cache.Set(ctx, cacheKey, user.ToCache(), 10*time.Minute)
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// Update 更新用户
|
||||
// Update 更新用户(自动缓存失效)
|
||||
func (r *GormUserRepository) Update(ctx context.Context, user entities.User) error {
|
||||
if err := r.db.WithContext(ctx).Save(&user).Error; err != nil {
|
||||
r.logger.Error("更新用户失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 清除相关缓存
|
||||
r.deleteCacheByID(ctx, user.ID)
|
||||
r.deleteCacheByPhone(ctx, user.Phone)
|
||||
|
||||
r.logger.Info("用户更新成功", zap.String("user_id", user.ID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete 删除用户
|
||||
func (r *GormUserRepository) Delete(ctx context.Context, id string) error {
|
||||
// 先获取用户信息用于清除缓存
|
||||
user, err := r.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.db.WithContext(ctx).Delete(&entities.User{}, "id = ?", id).Error; err != nil {
|
||||
r.logger.Error("删除用户失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 清除相关缓存
|
||||
r.deleteCacheByID(ctx, id)
|
||||
r.deleteCacheByPhone(ctx, user.Phone)
|
||||
|
||||
r.logger.Info("用户删除成功", zap.String("user_id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// SoftDelete 软删除用户
|
||||
func (r *GormUserRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
// 先获取用户信息用于清除缓存
|
||||
user, err := r.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.db.WithContext(ctx).Delete(&entities.User{}, "id = ?", id).Error; err != nil {
|
||||
r.logger.Error("软删除用户失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 清除相关缓存
|
||||
r.deleteCacheByID(ctx, id)
|
||||
r.deleteCacheByPhone(ctx, user.Phone)
|
||||
|
||||
r.logger.Info("用户软删除成功", zap.String("user_id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Restore 恢复软删除的用户
|
||||
func (r *GormUserRepository) Restore(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Unscoped().Model(&entities.User{}).Where("id = ?", id).Update("deleted_at", nil).Error; err != nil {
|
||||
r.logger.Error("恢复用户失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 清除相关缓存
|
||||
r.deleteCacheByID(ctx, id)
|
||||
|
||||
r.logger.Info("用户恢复成功", zap.String("user_id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Count 统计用户数量
|
||||
func (r *GormUserRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.User{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("phone LIKE ? OR nickname LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
err := query.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// Exists 检查用户是否存在
|
||||
func (r *GormUserRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.User{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建用户
|
||||
func (r *GormUserRepository) CreateBatch(ctx context.Context, users []entities.User) error {
|
||||
r.logger.Info("批量创建用户", zap.Int("count", len(users)))
|
||||
@@ -213,24 +108,35 @@ func (r *GormUserRepository) List(ctx context.Context, options interfaces.ListOp
|
||||
var users []entities.User
|
||||
query := r.db.WithContext(ctx).Model(&entities.User{})
|
||||
|
||||
// 应用筛选条件
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
// 应用搜索条件
|
||||
if options.Search != "" {
|
||||
query = query.Where("phone LIKE ? OR nickname LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
query = query.Where("username LIKE ? OR phone LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
// 应用预加载
|
||||
for _, include := range options.Include {
|
||||
query = query.Preload(include)
|
||||
}
|
||||
|
||||
// 应用排序
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order != "" {
|
||||
order = options.Order
|
||||
if options.Order == "desc" || options.Order == "DESC" {
|
||||
order = "DESC"
|
||||
}
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
} else {
|
||||
query = query.Order("created_at DESC")
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
@@ -239,32 +145,61 @@ func (r *GormUserRepository) List(ctx context.Context, options interfaces.ListOp
|
||||
return users, query.Find(&users).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormUserRepository) WithTx(tx interface{}) interfaces.Repository[entities.User] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormUserRepository{
|
||||
db: gormTx,
|
||||
cache: r.cache,
|
||||
logger: r.logger,
|
||||
}
|
||||
// ================ BaseRepository 接口实现 ================
|
||||
|
||||
// Delete 删除用户
|
||||
func (r *GormUserRepository) Delete(ctx context.Context, id string) error {
|
||||
if err := r.db.WithContext(ctx).Delete(&entities.User{}, "id = ?", id).Error; err != nil {
|
||||
r.logger.Error("删除用户失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
return r
|
||||
|
||||
r.logger.Info("用户删除成功", zap.String("user_id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
// Exists 检查用户是否存在
|
||||
func (r *GormUserRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.User{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// Count 统计用户数量
|
||||
func (r *GormUserRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.User{})
|
||||
|
||||
// 应用筛选条件
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
// 应用搜索条件
|
||||
if options.Search != "" {
|
||||
query = query.Where("username LIKE ? OR phone LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
err := query.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// SoftDelete 软删除用户
|
||||
func (r *GormUserRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.db.WithContext(ctx).Delete(&entities.User{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// Restore 恢复用户
|
||||
func (r *GormUserRepository) Restore(ctx context.Context, id string) error {
|
||||
return r.db.WithContext(ctx).Unscoped().Model(&entities.User{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
||||
}
|
||||
|
||||
// ================ 业务专用方法 ================
|
||||
|
||||
// GetByPhone 根据手机号获取用户
|
||||
func (r *GormUserRepository) GetByPhone(ctx context.Context, phone string) (*entities.User, error) {
|
||||
// 尝试从缓存获取
|
||||
cacheKey := fmt.Sprintf("user:phone:%s", phone)
|
||||
var userCache entities.UserCache
|
||||
if err := r.cache.Get(ctx, cacheKey, &userCache); err == nil {
|
||||
var user entities.User
|
||||
user.FromCache(&userCache)
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// 从数据库查询
|
||||
var user entities.User
|
||||
if err := r.db.WithContext(ctx).Where("phone = ?", phone).First(&user).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
@@ -274,64 +209,68 @@ func (r *GormUserRepository) GetByPhone(ctx context.Context, phone string) (*ent
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 缓存结果
|
||||
r.cache.Set(ctx, cacheKey, user.ToCache(), 10*time.Minute)
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// GetByUsername 根据用户名获取用户
|
||||
func (r *GormUserRepository) GetByUsername(ctx context.Context, username string) (*entities.User, error) {
|
||||
var user entities.User
|
||||
if err := r.db.WithContext(ctx).Where("username = ?", username).First(&user).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrUserNotFound
|
||||
}
|
||||
r.logger.Error("根据用户名查询用户失败", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// GetByUserType 根据用户类型获取用户列表
|
||||
func (r *GormUserRepository) GetByUserType(ctx context.Context, userType string) ([]*entities.User, error) {
|
||||
var users []*entities.User
|
||||
err := r.db.WithContext(ctx).Where("user_type = ?", userType).Find(&users).Error
|
||||
return users, err
|
||||
}
|
||||
|
||||
// ListUsers 获取用户列表(带分页和筛选)
|
||||
func (r *GormUserRepository) ListUsers(ctx context.Context, query *queries.ListUsersQuery) ([]*entities.User, int64, error) {
|
||||
var users []entities.User
|
||||
var users []*entities.User
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.User{})
|
||||
// 构建查询条件
|
||||
db := r.db.WithContext(ctx).Model(&entities.User{})
|
||||
|
||||
// 应用筛选条件
|
||||
if query.Phone != "" {
|
||||
dbQuery = dbQuery.Where("phone LIKE ?", "%"+query.Phone+"%")
|
||||
db = db.Where("phone LIKE ?", "%"+query.Phone+"%")
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
db = db.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
db = db.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
if err := db.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&users).Error; err != nil {
|
||||
if err := db.Offset(offset).Limit(query.PageSize).Find(&users).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
userPtrs := make([]*entities.User, len(users))
|
||||
for i := range users {
|
||||
userPtrs[i] = &users[i]
|
||||
}
|
||||
|
||||
return userPtrs, total, nil
|
||||
return users, total, nil
|
||||
}
|
||||
|
||||
// ValidateUser 验证用户
|
||||
// ValidateUser 验证用户登录
|
||||
func (r *GormUserRepository) ValidateUser(ctx context.Context, phone, password string) (*entities.User, error) {
|
||||
var user entities.User
|
||||
if err := r.db.WithContext(ctx).Where("phone = ? AND password = ?", phone, password).First(&user).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("手机号或密码错误")
|
||||
}
|
||||
r.logger.Error("验证用户失败", zap.Error(err))
|
||||
err := r.db.WithContext(ctx).Where("phone = ? AND password = ?", phone, password).First(&user).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -340,172 +279,105 @@ func (r *GormUserRepository) ValidateUser(ctx context.Context, phone, password s
|
||||
|
||||
// UpdateLastLogin 更新最后登录时间
|
||||
func (r *GormUserRepository) UpdateLastLogin(ctx context.Context, userID string) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.User{}).
|
||||
now := time.Now()
|
||||
return r.db.WithContext(ctx).Model(&entities.User{}).
|
||||
Where("id = ?", userID).
|
||||
Update("last_login_at", time.Now()).Error; err != nil {
|
||||
r.logger.Error("更新最后登录时间失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 清除相关缓存
|
||||
r.deleteCacheByID(ctx, userID)
|
||||
|
||||
r.logger.Info("最后登录时间更新成功", zap.String("user_id", userID))
|
||||
return nil
|
||||
Updates(map[string]interface{}{
|
||||
"last_login_at": &now,
|
||||
"updated_at": now,
|
||||
}).Error
|
||||
}
|
||||
|
||||
// UpdatePassword 更新密码
|
||||
func (r *GormUserRepository) UpdatePassword(ctx context.Context, userID string, newPassword string) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.User{}).
|
||||
return r.db.WithContext(ctx).Model(&entities.User{}).
|
||||
Where("id = ?", userID).
|
||||
Update("password", newPassword).Error; err != nil {
|
||||
r.logger.Error("更新密码失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 清除相关缓存
|
||||
r.deleteCacheByID(ctx, userID)
|
||||
|
||||
r.logger.Info("密码更新成功", zap.String("user_id", userID))
|
||||
return nil
|
||||
Update("password", newPassword).Error
|
||||
}
|
||||
|
||||
// CheckPassword 检查密码
|
||||
func (r *GormUserRepository) CheckPassword(ctx context.Context, userID string, password string) (bool, error) {
|
||||
var user entities.User
|
||||
if err := r.db.WithContext(ctx).Where("id = ? AND password = ?", userID, password).First(&user).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return false, nil
|
||||
}
|
||||
r.logger.Error("检查密码失败", zap.Error(err))
|
||||
return false, err
|
||||
}
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.User{}).
|
||||
Where("id = ? AND password = ?", userID, password).
|
||||
Count(&count).Error
|
||||
|
||||
return true, nil
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// ActivateUser 激活用户
|
||||
func (r *GormUserRepository) ActivateUser(ctx context.Context, userID string) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.User{}).
|
||||
return r.db.WithContext(ctx).Model(&entities.User{}).
|
||||
Where("id = ?", userID).
|
||||
Update("status", "ACTIVE").Error; err != nil {
|
||||
r.logger.Error("激活用户失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 清除相关缓存
|
||||
r.deleteCacheByID(ctx, userID)
|
||||
|
||||
r.logger.Info("用户激活成功", zap.String("user_id", userID))
|
||||
return nil
|
||||
Update("active", true).Error
|
||||
}
|
||||
|
||||
// DeactivateUser 停用用户
|
||||
func (r *GormUserRepository) DeactivateUser(ctx context.Context, userID string) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entities.User{}).
|
||||
return r.db.WithContext(ctx).Model(&entities.User{}).
|
||||
Where("id = ?", userID).
|
||||
Update("status", "INACTIVE").Error; err != nil {
|
||||
r.logger.Error("停用用户失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
Update("active", false).Error
|
||||
}
|
||||
|
||||
// 清除相关缓存
|
||||
r.deleteCacheByID(ctx, userID)
|
||||
|
||||
r.logger.Info("用户停用成功", zap.String("user_id", userID))
|
||||
return nil
|
||||
// UpdateLoginStats 更新登录统计
|
||||
func (r *GormUserRepository) UpdateLoginStats(ctx context.Context, userID string) error {
|
||||
return r.db.WithContext(ctx).Model(&entities.User{}).
|
||||
Where("id = ?", userID).
|
||||
Updates(map[string]interface{}{
|
||||
"login_count": gorm.Expr("login_count + 1"),
|
||||
"last_login_at": time.Now(),
|
||||
}).Error
|
||||
}
|
||||
|
||||
// GetStats 获取用户统计信息
|
||||
func (r *GormUserRepository) GetStats(ctx context.Context) (*repositories.UserStats, error) {
|
||||
var stats repositories.UserStats
|
||||
|
||||
db := r.db.WithContext(ctx)
|
||||
|
||||
// 总用户数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.User{}).Count(&stats.TotalUsers).Error; err != nil {
|
||||
if err := db.Model(&entities.User{}).Count(&stats.TotalUsers).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 活跃用户数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.User{}).Where("status = ?", "ACTIVE").Count(&stats.ActiveUsers).Error; err != nil {
|
||||
if err := db.Model(&entities.User{}).Where("active = ?", true).Count(&stats.ActiveUsers).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 今日注册数
|
||||
today := time.Now().Truncate(24 * time.Hour)
|
||||
if err := r.db.WithContext(ctx).Model(&entities.User{}).Where("created_at >= ?", today).Count(&stats.TodayRegistrations).Error; err != nil {
|
||||
if err := db.Model(&entities.User{}).Where("created_at >= ?", today).Count(&stats.TodayRegistrations).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 今日登录数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.User{}).Where("last_login_at >= ?", today).Count(&stats.TodayLogins).Error; err != nil {
|
||||
if err := db.Model(&entities.User{}).Where("last_login_at >= ?", today).Count(&stats.TodayLogins).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &stats, nil
|
||||
}
|
||||
|
||||
// GetStatsByDateRange 根据日期范围获取用户统计信息
|
||||
// GetStatsByDateRange 获取指定日期范围的用户统计
|
||||
func (r *GormUserRepository) GetStatsByDateRange(ctx context.Context, startDate, endDate string) (*repositories.UserStats, error) {
|
||||
var stats repositories.UserStats
|
||||
|
||||
// 总用户数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.User{}).Where("created_at BETWEEN ? AND ?", startDate, endDate).Count(&stats.TotalUsers).Error; err != nil {
|
||||
db := r.db.WithContext(ctx)
|
||||
|
||||
// 指定时间范围内的注册数
|
||||
if err := db.Model(&entities.User{}).
|
||||
Where("created_at >= ? AND created_at <= ?", startDate, endDate).
|
||||
Count(&stats.TodayRegistrations).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 活跃用户数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.User{}).Where("status = ? AND created_at BETWEEN ? AND ?", "ACTIVE", startDate, endDate).Count(&stats.ActiveUsers).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 今日注册数
|
||||
today := time.Now().Truncate(24 * time.Hour)
|
||||
if err := r.db.WithContext(ctx).Model(&entities.User{}).Where("created_at >= ?", today).Count(&stats.TodayRegistrations).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 今日登录数
|
||||
if err := r.db.WithContext(ctx).Model(&entities.User{}).Where("last_login_at >= ?", today).Count(&stats.TodayLogins).Error; err != nil {
|
||||
// 指定时间范围内的登录数
|
||||
if err := db.Model(&entities.User{}).
|
||||
Where("last_login_at >= ? AND last_login_at <= ?", startDate, endDate).
|
||||
Count(&stats.TodayLogins).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &stats, nil
|
||||
}
|
||||
|
||||
// FindByPhone 根据手机号查找用户(兼容旧方法)
|
||||
func (r *GormUserRepository) FindByPhone(ctx context.Context, phone string) (*entities.User, error) {
|
||||
return r.GetByPhone(ctx, phone)
|
||||
}
|
||||
|
||||
// ExistsByPhone 检查手机号是否存在
|
||||
func (r *GormUserRepository) ExistsByPhone(ctx context.Context, phone string) (bool, error) {
|
||||
var count int64
|
||||
if err := r.db.WithContext(ctx).Model(&entities.User{}).Where("phone = ?", phone).Count(&count).Error; err != nil {
|
||||
r.logger.Error("检查手机号是否存在失败", zap.Error(err))
|
||||
return false, err
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
// 私有辅助方法
|
||||
|
||||
// deleteCacheByID 根据ID删除缓存
|
||||
func (r *GormUserRepository) deleteCacheByID(ctx context.Context, id string) {
|
||||
cacheKey := fmt.Sprintf("user:id:%s", id)
|
||||
if err := r.cache.Delete(ctx, cacheKey); err != nil {
|
||||
r.logger.Warn("删除用户ID缓存失败", zap.String("cache_key", cacheKey), zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
// deleteCacheByPhone 根据手机号删除缓存
|
||||
func (r *GormUserRepository) deleteCacheByPhone(ctx context.Context, phone string) {
|
||||
cacheKey := fmt.Sprintf("user:phone:%s", phone)
|
||||
if err := r.cache.Delete(ctx, cacheKey); err != nil {
|
||||
r.logger.Warn("删除用户手机号缓存失败", zap.String("cache_key", cacheKey), zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"tyapi-server/internal/application/admin"
|
||||
"tyapi-server/internal/application/admin/dto/commands"
|
||||
"tyapi-server/internal/application/admin/dto/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// AdminHandler 管理员HTTP处理器
|
||||
type AdminHandler struct {
|
||||
appService admin.AdminApplicationService
|
||||
responseBuilder interfaces.ResponseBuilder
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewAdminHandler 创建管理员HTTP处理器
|
||||
func NewAdminHandler(
|
||||
appService admin.AdminApplicationService,
|
||||
responseBuilder interfaces.ResponseBuilder,
|
||||
logger *zap.Logger,
|
||||
) *AdminHandler {
|
||||
return &AdminHandler{
|
||||
appService: appService,
|
||||
responseBuilder: responseBuilder,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Login 管理员登录
|
||||
// @Summary 管理员登录
|
||||
// @Description 使用用户名和密码进行管理员登录,返回JWT令牌
|
||||
// @Tags 管理员管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body commands.AdminLoginCommand true "管理员登录请求"
|
||||
// @Success 200 {object} responses.AdminLoginResponse "登录成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "用户名或密码错误"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/auth/login [post]
|
||||
func (h *AdminHandler) Login(c *gin.Context) {
|
||||
var cmd commands.AdminLoginCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.appService.Login(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("管理员登录失败", zap.Error(err))
|
||||
h.responseBuilder.Unauthorized(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, response, "登录成功")
|
||||
}
|
||||
|
||||
// CreateAdmin 创建管理员
|
||||
// @Summary 创建管理员
|
||||
// @Description 创建新的管理员账户,需要超级管理员权限
|
||||
// @Tags 管理员管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.CreateAdminCommand true "创建管理员请求"
|
||||
// @Success 201 {object} map[string]interface{} "管理员创建成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 403 {object} map[string]interface{} "权限不足"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin [post]
|
||||
func (h *AdminHandler) CreateAdmin(c *gin.Context) {
|
||||
var cmd commands.CreateAdminCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
return
|
||||
}
|
||||
cmd.OperatorID = h.getCurrentAdminID(c)
|
||||
|
||||
if err := h.appService.CreateAdmin(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("创建管理员失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Created(c, nil, "管理员创建成功")
|
||||
}
|
||||
|
||||
// UpdateAdmin 更新管理员
|
||||
// @Summary 更新管理员信息
|
||||
// @Description 更新指定管理员的基本信息
|
||||
// @Tags 管理员管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "管理员ID"
|
||||
// @Param request body commands.UpdateAdminCommand true "更新管理员请求"
|
||||
// @Success 200 {object} map[string]interface{} "管理员更新成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 403 {object} map[string]interface{} "权限不足"
|
||||
// @Failure 404 {object} map[string]interface{} "管理员不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/{id} [put]
|
||||
func (h *AdminHandler) UpdateAdmin(c *gin.Context) {
|
||||
var cmd commands.UpdateAdminCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
return
|
||||
}
|
||||
cmd.AdminID = c.Param("id")
|
||||
cmd.OperatorID = h.getCurrentAdminID(c)
|
||||
|
||||
if err := h.appService.UpdateAdmin(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("更新管理员失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "管理员更新成功")
|
||||
}
|
||||
|
||||
// ChangePassword 修改密码
|
||||
// @Summary 修改管理员密码
|
||||
// @Description 修改当前登录管理员的密码
|
||||
// @Tags 管理员管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.ChangeAdminPasswordCommand true "修改密码请求"
|
||||
// @Success 200 {object} map[string]interface{} "密码修改成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/change-password [post]
|
||||
func (h *AdminHandler) ChangePassword(c *gin.Context) {
|
||||
var cmd commands.ChangeAdminPasswordCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
return
|
||||
}
|
||||
cmd.AdminID = h.getCurrentAdminID(c)
|
||||
|
||||
if err := h.appService.ChangePassword(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("修改密码失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "密码修改成功")
|
||||
}
|
||||
|
||||
// ListAdmins 获取管理员列表
|
||||
// @Summary 获取管理员列表
|
||||
// @Description 分页获取管理员列表,支持搜索和筛选
|
||||
// @Tags 管理员管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param size query int false "每页数量" default(10)
|
||||
// @Param keyword query string false "搜索关键词"
|
||||
// @Param status query string false "状态筛选"
|
||||
// @Success 200 {object} responses.AdminListResponse "获取管理员列表成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin [get]
|
||||
func (h *AdminHandler) ListAdmins(c *gin.Context) {
|
||||
var query queries.ListAdminsQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.appService.ListAdmins(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取管理员列表失败", zap.Error(err))
|
||||
h.responseBuilder.InternalError(c, "获取管理员列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, response, "获取管理员列表成功")
|
||||
}
|
||||
|
||||
// GetAdminByID 根据ID获取管理员
|
||||
// @Summary 获取管理员详情
|
||||
// @Description 根据管理员ID获取详细信息
|
||||
// @Tags 管理员管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "管理员ID"
|
||||
// @Success 200 {object} responses.AdminInfoResponse "获取管理员详情成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "管理员不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/{id} [get]
|
||||
func (h *AdminHandler) GetAdminByID(c *gin.Context) {
|
||||
var query queries.GetAdminInfoQuery
|
||||
if err := c.ShouldBindUri(&query); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
admin, err := h.appService.GetAdminByID(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取管理员详情失败", zap.Error(err))
|
||||
h.responseBuilder.NotFound(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, admin, "获取管理员详情成功")
|
||||
}
|
||||
|
||||
// DeleteAdmin 删除管理员
|
||||
// @Summary 删除管理员
|
||||
// @Description 删除指定的管理员账户
|
||||
// @Tags 管理员管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "管理员ID"
|
||||
// @Success 200 {object} map[string]interface{} "管理员删除成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 403 {object} map[string]interface{} "权限不足"
|
||||
// @Failure 404 {object} map[string]interface{} "管理员不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/{id} [delete]
|
||||
func (h *AdminHandler) DeleteAdmin(c *gin.Context) {
|
||||
var cmd commands.DeleteAdminCommand
|
||||
cmd.AdminID = c.Param("id")
|
||||
cmd.OperatorID = h.getCurrentAdminID(c)
|
||||
|
||||
if err := h.appService.DeleteAdmin(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("删除管理员失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "管理员删除成功")
|
||||
}
|
||||
|
||||
// GetAdminStats 获取管理员统计信息
|
||||
// @Summary 获取管理员统计信息
|
||||
// @Description 获取管理员相关的统计数据
|
||||
// @Tags 管理员管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.AdminStatsResponse "获取统计信息成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/stats [get]
|
||||
func (h *AdminHandler) GetAdminStats(c *gin.Context) {
|
||||
stats, err := h.appService.GetAdminStats(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("获取管理员统计失败", zap.Error(err))
|
||||
h.responseBuilder.InternalError(c, "获取统计信息失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, stats, "获取统计信息成功")
|
||||
}
|
||||
|
||||
// getCurrentAdminID 获取当前管理员ID
|
||||
func (h *AdminHandler) getCurrentAdminID(c *gin.Context) string {
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
if id, ok := userID.(string); ok {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
@@ -13,136 +15,57 @@ import (
|
||||
)
|
||||
|
||||
// CertificationHandler 认证处理器
|
||||
// 负责处理HTTP请求,参数验证,调用应用服务,返回HTTP响应
|
||||
type CertificationHandler struct {
|
||||
appService certification.CertificationApplicationService
|
||||
response interfaces.ResponseBuilder
|
||||
logger *zap.Logger
|
||||
certAppService certification.CertificationApplicationService
|
||||
esignCallbackService certification.EsignCallbackApplicationService
|
||||
response interfaces.ResponseBuilder
|
||||
validator interfaces.RequestValidator
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewCertificationHandler 创建认证处理器
|
||||
func NewCertificationHandler(
|
||||
appService certification.CertificationApplicationService,
|
||||
certAppService certification.CertificationApplicationService,
|
||||
esignCallbackService certification.EsignCallbackApplicationService,
|
||||
response interfaces.ResponseBuilder,
|
||||
validator interfaces.RequestValidator,
|
||||
logger *zap.Logger,
|
||||
) *CertificationHandler {
|
||||
return &CertificationHandler{
|
||||
appService: appService,
|
||||
response: response,
|
||||
logger: logger,
|
||||
certAppService: certAppService,
|
||||
esignCallbackService: esignCallbackService,
|
||||
response: response,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateCertification 创建认证申请
|
||||
// @Summary 创建认证申请
|
||||
// @Description 为用户创建新的企业认证申请
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.CertificationResponse "认证申请创建成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification [post]
|
||||
func (h *CertificationHandler) CreateCertification(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
return
|
||||
}
|
||||
|
||||
cmd := &commands.CreateCertificationCommand{UserID: userID}
|
||||
result, err := h.appService.CreateCertification(c.Request.Context(), cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("创建认证申请失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.response.InternalError(c, "创建认证申请失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "认证申请创建成功")
|
||||
}
|
||||
|
||||
// UploadBusinessLicense 上传营业执照并同步OCR识别
|
||||
// @Summary 上传营业执照并同步OCR识别
|
||||
// @Description 上传营业执照文件,立即进行OCR识别并返回结果
|
||||
// @Tags 企业认证
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param file formData file true "营业执照文件"
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.UploadLicenseResponse "上传成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未授权"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/upload-license [post]
|
||||
func (h *CertificationHandler) UploadBusinessLicense(c *gin.Context) {
|
||||
// 获取当前用户ID
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取上传的文件
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "文件上传失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
openedFile, err := file.Open()
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无法读取文件")
|
||||
return
|
||||
}
|
||||
defer openedFile.Close()
|
||||
|
||||
fileBytes, err := io.ReadAll(openedFile)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "文件读取失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 调用应用服务
|
||||
response, err := h.appService.UploadBusinessLicense(c.Request.Context(), userID.(string), fileBytes, file.Filename)
|
||||
if err != nil {
|
||||
h.logger.Error("营业执照上传失败", zap.Error(err))
|
||||
h.response.InternalError(c, "营业执照上传失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, response, "营业执照上传成功")
|
||||
}
|
||||
|
||||
// GetCertificationStatus 获取认证状态
|
||||
// @Summary 获取认证状态
|
||||
// @Description 获取当前用户的认证申请状态
|
||||
// @Description 获取当前用户的认证状态信息,包括认证进度、当前状态等
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.CertificationResponse "获取认证状态成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Success 200 {object} map[string]interface{} "获取认证状态成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/status [get]
|
||||
func (h *CertificationHandler) GetCertificationStatus(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
query := &queries.GetCertificationStatusQuery{UserID: userID}
|
||||
result, err := h.appService.GetCertificationStatus(c.Request.Context(), query)
|
||||
query := &queries.GetCertificationStatusQuery{
|
||||
UserID: userID,
|
||||
}
|
||||
|
||||
result, err := h.certAppService.GetCertificationStatus(c.Request.Context(), query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证状态失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.logger.Error("获取认证状态失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -150,55 +73,59 @@ func (h *CertificationHandler) GetCertificationStatus(c *gin.Context) {
|
||||
h.response.Success(c, result, "获取认证状态成功")
|
||||
}
|
||||
|
||||
// GetProgressStats 获取进度统计
|
||||
// @Summary 获取进度统计
|
||||
// @Description 获取认证申请的进度统计数据
|
||||
// GetCertificationDetails 获取认证详情
|
||||
// @Summary 获取认证详情
|
||||
// @Description 获取当前用户的详细认证信息,包括企业信息、认证记录等
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} map[string]interface{} "获取进度统计成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Success 200 {object} map[string]interface{} "获取认证详情成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/stats [get]
|
||||
func (h *CertificationHandler) GetProgressStats(c *gin.Context) {
|
||||
// 这里应该实现获取进度统计的逻辑
|
||||
// 暂时返回空数据
|
||||
h.response.Success(c, map[string]interface{}{
|
||||
"total_applications": 0,
|
||||
"pending": 0,
|
||||
"in_progress": 0,
|
||||
"completed": 0,
|
||||
"rejected": 0,
|
||||
}, "获取进度统计成功")
|
||||
// @Router /api/v1/certification/details [get]
|
||||
func (h *CertificationHandler) GetCertificationDetails(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
query := &queries.GetCertificationDetailsQuery{
|
||||
UserID: userID,
|
||||
}
|
||||
|
||||
result, err := h.certAppService.GetCertificationDetails(c.Request.Context(), query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证详情失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取认证详情成功")
|
||||
}
|
||||
|
||||
// GetCertificationProgress 获取认证进度
|
||||
// @Summary 获取认证进度
|
||||
// @Description 获取当前用户的认证申请详细进度信息
|
||||
// @Description 获取当前用户的认证进度百分比和下一步操作提示
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} map[string]interface{} "获取认证进度成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证申请不存在"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/progress [get]
|
||||
func (h *CertificationHandler) GetCertificationProgress(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.GetCertificationProgress(c.Request.Context(), userID)
|
||||
result, err := h.certAppService.GetCertificationProgress(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证进度失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.logger.Error("获取认证进度失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -208,39 +135,34 @@ func (h *CertificationHandler) GetCertificationProgress(c *gin.Context) {
|
||||
|
||||
// SubmitEnterpriseInfo 提交企业信息
|
||||
// @Summary 提交企业信息
|
||||
// @Description 提交企业基本信息,包括企业名称、统一社会信用代码、法定代表人信息等
|
||||
// @Description 提交企业四要素信息(企业名称、统一社会信用代码、法定代表人姓名、法定代表人身份证),完成企业信息验证。如果用户没有认证申请,系统会自动创建
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.SubmitEnterpriseInfoCommand true "企业信息"
|
||||
// @Success 200 {object} responses.CertificationResponse "企业信息提交成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Param request body commands.SubmitEnterpriseInfoCommand true "企业信息提交请求"
|
||||
// @Success 200 {object} map[string]interface{} "企业信息提交成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误或验证码无效"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/enterprise-info [post]
|
||||
// @Router /api/v1/certification/submit-enterprise-info [post]
|
||||
func (h *CertificationHandler) SubmitEnterpriseInfo(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.SubmitEnterpriseInfoCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.logger.Error("参数绑定失败", zap.Error(err))
|
||||
h.response.BadRequest(c, "请求参数格式错误")
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.appService.SubmitEnterpriseInfo(c.Request.Context(), &cmd)
|
||||
result, err := h.certAppService.SubmitEnterpriseInfo(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("提交企业信息失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.logger.Error("提交企业信息失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -248,92 +170,57 @@ func (h *CertificationHandler) SubmitEnterpriseInfo(c *gin.Context) {
|
||||
h.response.Success(c, result, "企业信息提交成功")
|
||||
}
|
||||
|
||||
// InitiateFaceVerify 发起人脸验证
|
||||
// @Summary 发起人脸验证
|
||||
// @Description 发起企业法人人脸验证流程
|
||||
// GetEnterpriseAuthURL 获取企业认证链接
|
||||
// @Summary 获取企业认证链接
|
||||
// @Description 获取e签宝企业认证链接,用户可通过该链接完成企业认证
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.InitiateFaceVerifyCommand true "人脸验证请求"
|
||||
// @Success 200 {object} responses.FaceVerifyResponse "人脸验证发起成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Success 200 {object} map[string]interface{} "获取企业认证链接成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 400 {object} map[string]interface{} "企业信息未提交或认证状态异常"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/face-verify [post]
|
||||
func (h *CertificationHandler) InitiateFaceVerify(c *gin.Context) {
|
||||
// @Router /api/v1/certification/enterprise-auth-url [get]
|
||||
func (h *CertificationHandler) GetEnterpriseAuthURL(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.InitiateFaceVerifyCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.logger.Error("参数绑定失败", zap.Error(err))
|
||||
h.response.BadRequest(c, "请求参数格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 根据用户ID获取认证申请
|
||||
query := &queries.GetCertificationStatusQuery{UserID: userID}
|
||||
certification, err := h.appService.GetCertificationStatus(c.Request.Context(), query)
|
||||
result, err := h.certAppService.GetEnterpriseAuthURL(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证申请失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.logger.Error("获取企业认证链接失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 如果用户没有认证申请,返回错误
|
||||
if certification.ID == "" {
|
||||
h.response.BadRequest(c, "用户尚未创建认证申请")
|
||||
return
|
||||
}
|
||||
|
||||
cmd.CertificationID = certification.ID
|
||||
|
||||
result, err := h.appService.InitiateFaceVerify(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("发起人脸验证失败",
|
||||
zap.String("certification_id", certification.ID),
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "人脸验证发起成功")
|
||||
h.response.Success(c, result, "获取企业认证链接成功")
|
||||
}
|
||||
|
||||
// ApplyContract 申请合同
|
||||
// @Summary 申请合同
|
||||
// @Description 申请企业认证合同
|
||||
// @Description 为企业认证用户申请合同,生成合同文档
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.CertificationResponse "合同申请成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Success 200 {object} map[string]interface{} "合同申请成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 400 {object} map[string]interface{} "企业认证未完成或合同申请失败"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/contract [post]
|
||||
// @Router /api/v1/certification/apply-contract [post]
|
||||
func (h *CertificationHandler) ApplyContract(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.ApplyContract(c.Request.Context(), userID)
|
||||
result, err := h.certAppService.ApplyContract(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("申请合同失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.logger.Error("申请合同失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -341,132 +228,161 @@ func (h *CertificationHandler) ApplyContract(c *gin.Context) {
|
||||
h.response.Success(c, result, "合同申请成功")
|
||||
}
|
||||
|
||||
// GetCertificationDetails 获取认证详情
|
||||
// @Summary 获取认证详情
|
||||
// @Description 获取当前用户的认证申请详细信息
|
||||
// GetContractSignURL 获取合同签署链接
|
||||
// @Summary 获取合同签署链接
|
||||
// @Description 获取e签宝合同签署链接,用户可通过该链接完成合同签署
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.CertificationResponse "获取认证详情成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证申请不存在"
|
||||
// @Success 200 {object} map[string]interface{} "获取合同签署链接成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 400 {object} map[string]interface{} "合同未申请或签署状态异常"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/details [get]
|
||||
func (h *CertificationHandler) GetCertificationDetails(c *gin.Context) {
|
||||
// @Router /api/v1/certification/contract-sign-url [get]
|
||||
func (h *CertificationHandler) GetContractSignURL(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
query := &queries.GetCertificationDetailsQuery{
|
||||
cmd := &commands.GetContractSignURLCommand{
|
||||
UserID: userID,
|
||||
}
|
||||
|
||||
result, err := h.appService.GetCertificationDetails(c.Request.Context(), query)
|
||||
result, err := h.certAppService.GetContractSignURL(c.Request.Context(), cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证详情失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.logger.Error("获取合同签署链接失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取认证详情成功")
|
||||
h.response.Success(c, result, "获取合同签署链接成功")
|
||||
}
|
||||
|
||||
// RetryStep 重试步骤
|
||||
// @Summary 重试认证步骤
|
||||
// @Description 重新执行指定的认证步骤
|
||||
// EsignCallback e签宝回调
|
||||
// @Summary e签宝回调接口
|
||||
// @Description 接收e签宝认证和签署的回调通知
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param step path string true "步骤名称"
|
||||
// @Success 200 {object} map[string]interface{} "步骤重试成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Success 200 {object} map[string]interface{} "回调处理成功"
|
||||
// @Failure 400 {object} map[string]interface{} "回调参数错误"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/retry/{step} [post]
|
||||
func (h *CertificationHandler) RetryStep(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
return
|
||||
// @Router /api/v1/certification/esign-callback [post]
|
||||
func (h *CertificationHandler) EsignCallback(c *gin.Context) {
|
||||
// 记录请求基本信息
|
||||
h.logger.Info("收到e签宝回调请求",
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
zap.String("remote_addr", c.ClientIP()),
|
||||
zap.String("user_agent", c.GetHeader("User-Agent")),
|
||||
)
|
||||
|
||||
// 记录所有请求头
|
||||
headers := make(map[string]string)
|
||||
for key, values := range c.Request.Header {
|
||||
if len(values) > 0 {
|
||||
headers[key] = values[0]
|
||||
}
|
||||
}
|
||||
h.logger.Info("回调请求头信息", zap.Any("headers", headers))
|
||||
|
||||
// 记录URL查询参数
|
||||
queryParams := make(map[string]string)
|
||||
for key, values := range c.Request.URL.Query() {
|
||||
if len(values) > 0 {
|
||||
queryParams[key] = values[0]
|
||||
}
|
||||
}
|
||||
if len(queryParams) > 0 {
|
||||
h.logger.Info("回调URL查询参数", zap.Any("query_params", queryParams))
|
||||
}
|
||||
|
||||
step := c.Param("step")
|
||||
if step == "" {
|
||||
h.response.BadRequest(c, "步骤名称不能为空")
|
||||
return
|
||||
// 读取并记录请求体
|
||||
var requestBody interface{}
|
||||
var callbackData map[string]interface{}
|
||||
if c.Request.Body != nil {
|
||||
// 读取请求体
|
||||
bodyBytes, err := c.GetRawData()
|
||||
if err != nil {
|
||||
h.logger.Error("读取回调请求体失败", zap.Error(err))
|
||||
h.response.BadRequest(c, "读取请求体失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 尝试解析为JSON
|
||||
if err := c.ShouldBindJSON(&callbackData); err == nil {
|
||||
requestBody = callbackData
|
||||
} else {
|
||||
// 如果不是JSON,记录原始字符串
|
||||
requestBody = string(bodyBytes)
|
||||
h.logger.Error("回调请求体不是有效的JSON格式", zap.Error(err))
|
||||
h.response.BadRequest(c, "请求体格式错误")
|
||||
return
|
||||
}
|
||||
h.logger.Info("回调请求体内容", zap.Any("body", requestBody))
|
||||
|
||||
// 重新设置请求体,以便后续处理
|
||||
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
}
|
||||
|
||||
var result interface{}
|
||||
var err error
|
||||
// 记录Content-Type
|
||||
contentType := c.GetHeader("Content-Type")
|
||||
h.logger.Info("回调请求Content-Type", zap.String("content_type", contentType))
|
||||
|
||||
switch step {
|
||||
case "face_verify":
|
||||
result, err = h.appService.RetryFaceVerify(c.Request.Context(), userID)
|
||||
case "contract_sign":
|
||||
result, err = h.appService.RetryContractSign(c.Request.Context(), userID)
|
||||
default:
|
||||
h.response.BadRequest(c, "不支持的步骤类型")
|
||||
return
|
||||
// 记录Content-Length
|
||||
contentLength := c.GetHeader("Content-Length")
|
||||
if contentLength != "" {
|
||||
h.logger.Info("回调请求Content-Length", zap.String("content_length", contentLength))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("重试认证步骤失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.String("step", step),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
// 记录时间戳
|
||||
h.logger.Info("回调请求时间",
|
||||
zap.Time("request_time", time.Now()),
|
||||
zap.String("request_id", c.GetHeader("X-Request-ID")),
|
||||
)
|
||||
|
||||
// 记录完整的请求信息摘要
|
||||
h.logger.Info("e签宝回调完整信息摘要",
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
zap.String("client_ip", c.ClientIP()),
|
||||
zap.String("content_type", contentType),
|
||||
zap.Any("headers", headers),
|
||||
zap.Any("query_params", queryParams),
|
||||
zap.Any("body", requestBody),
|
||||
)
|
||||
|
||||
// 处理回调数据
|
||||
if callbackData != nil {
|
||||
// 构建请求头映射
|
||||
headers := make(map[string]string)
|
||||
for key, values := range c.Request.Header {
|
||||
if len(values) > 0 {
|
||||
headers[key] = values[0]
|
||||
}
|
||||
}
|
||||
|
||||
// 构建查询参数映射
|
||||
queryParams := make(map[string]string)
|
||||
for key, values := range c.Request.URL.Query() {
|
||||
if len(values) > 0 {
|
||||
queryParams[key] = values[0]
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.esignCallbackService.HandleCallback(c.Request.Context(), callbackData, headers, queryParams); err != nil {
|
||||
h.logger.Error("处理e签宝回调失败", zap.Error(err))
|
||||
h.response.BadRequest(c, "回调处理失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "认证步骤重试成功")
|
||||
}
|
||||
|
||||
// GetLicenseOCRResult 获取营业执照OCR识别结果
|
||||
// @Summary 获取营业执照OCR识别结果
|
||||
// @Description 根据上传记录ID获取OCR识别结果
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param record_id path string true "上传记录ID"
|
||||
// @Success 200 {object} responses.UploadLicenseResponse "获取OCR结果成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "记录不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/license/{record_id}/ocr-result [get]
|
||||
func (h *CertificationHandler) GetLicenseOCRResult(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
return
|
||||
}
|
||||
|
||||
recordID := c.Param("record_id")
|
||||
if recordID == "" {
|
||||
h.response.BadRequest(c, "上传记录ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.GetLicenseOCRResult(c.Request.Context(), recordID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取OCR结果失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.String("record_id", recordID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取OCR结果成功")
|
||||
// 返回成功响应
|
||||
c.JSON(200, map[string]interface{}{
|
||||
"code": "200",
|
||||
"msg": "success",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
type FinanceHandler struct {
|
||||
appService finance.FinanceApplicationService
|
||||
responseBuilder interfaces.ResponseBuilder
|
||||
validator interfaces.RequestValidator
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
@@ -21,11 +22,13 @@ type FinanceHandler struct {
|
||||
func NewFinanceHandler(
|
||||
appService finance.FinanceApplicationService,
|
||||
responseBuilder interfaces.ResponseBuilder,
|
||||
validator interfaces.RequestValidator,
|
||||
logger *zap.Logger,
|
||||
) *FinanceHandler {
|
||||
return &FinanceHandler{
|
||||
appService: appService,
|
||||
responseBuilder: responseBuilder,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
@@ -44,8 +47,7 @@ func NewFinanceHandler(
|
||||
// @Router /api/v1/finance/wallet [post]
|
||||
func (h *FinanceHandler) CreateWallet(c *gin.Context) {
|
||||
var cmd commands.CreateWalletCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -74,7 +76,7 @@ func (h *FinanceHandler) CreateWallet(c *gin.Context) {
|
||||
func (h *FinanceHandler) GetWallet(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -108,13 +110,12 @@ func (h *FinanceHandler) GetWallet(c *gin.Context) {
|
||||
func (h *FinanceHandler) UpdateWallet(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.UpdateWalletCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -149,13 +150,12 @@ func (h *FinanceHandler) UpdateWallet(c *gin.Context) {
|
||||
func (h *FinanceHandler) Recharge(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.RechargeWalletCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -190,13 +190,12 @@ func (h *FinanceHandler) Recharge(c *gin.Context) {
|
||||
func (h *FinanceHandler) Withdraw(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.WithdrawWalletCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -231,13 +230,12 @@ func (h *FinanceHandler) Withdraw(c *gin.Context) {
|
||||
func (h *FinanceHandler) WalletTransaction(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.WalletTransactionCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -270,7 +268,7 @@ func (h *FinanceHandler) WalletTransaction(c *gin.Context) {
|
||||
func (h *FinanceHandler) GetWalletStats(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -304,13 +302,12 @@ func (h *FinanceHandler) GetWalletStats(c *gin.Context) {
|
||||
func (h *FinanceHandler) CreateUserSecrets(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.CreateUserSecretsCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -344,7 +341,7 @@ func (h *FinanceHandler) CreateUserSecrets(c *gin.Context) {
|
||||
func (h *FinanceHandler) GetUserSecrets(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -377,7 +374,7 @@ func (h *FinanceHandler) GetUserSecrets(c *gin.Context) {
|
||||
func (h *FinanceHandler) RegenerateAccessKey(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -410,7 +407,7 @@ func (h *FinanceHandler) RegenerateAccessKey(c *gin.Context) {
|
||||
func (h *FinanceHandler) DeactivateUserSecrets(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
469
internal/infrastructure/http/handlers/product_admin_handler.go
Normal file
469
internal/infrastructure/http/handlers/product_admin_handler.go
Normal file
@@ -0,0 +1,469 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"tyapi-server/internal/application/product"
|
||||
"tyapi-server/internal/application/product/dto/commands"
|
||||
"tyapi-server/internal/application/product/dto/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// ProductAdminHandler 产品管理员HTTP处理器
|
||||
type ProductAdminHandler struct {
|
||||
productAppService product.ProductApplicationService
|
||||
categoryAppService product.CategoryApplicationService
|
||||
subscriptionAppService product.SubscriptionApplicationService
|
||||
responseBuilder interfaces.ResponseBuilder
|
||||
validator interfaces.RequestValidator
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewProductAdminHandler 创建产品管理员HTTP处理器
|
||||
func NewProductAdminHandler(
|
||||
productAppService product.ProductApplicationService,
|
||||
categoryAppService product.CategoryApplicationService,
|
||||
subscriptionAppService product.SubscriptionApplicationService,
|
||||
responseBuilder interfaces.ResponseBuilder,
|
||||
validator interfaces.RequestValidator,
|
||||
logger *zap.Logger,
|
||||
) *ProductAdminHandler {
|
||||
return &ProductAdminHandler{
|
||||
productAppService: productAppService,
|
||||
categoryAppService: categoryAppService,
|
||||
subscriptionAppService: subscriptionAppService,
|
||||
responseBuilder: responseBuilder,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateProduct 创建产品
|
||||
// @Summary 创建产品
|
||||
// @Description 管理员创建新产品
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.CreateProductCommand true "创建产品请求"
|
||||
// @Success 201 {object} map[string]interface{} "产品创建成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products [post]
|
||||
func (h *ProductAdminHandler) CreateProduct(c *gin.Context) {
|
||||
var cmd commands.CreateProductCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.productAppService.CreateProduct(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("创建产品失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Created(c, nil, "产品创建成功")
|
||||
}
|
||||
|
||||
// UpdateProduct 更新产品
|
||||
// @Summary 更新产品
|
||||
// @Description 管理员更新产品信息
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "产品ID"
|
||||
// @Param request body commands.UpdateProductCommand true "更新产品请求"
|
||||
// @Success 200 {object} map[string]interface{} "产品更新成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id} [put]
|
||||
func (h *ProductAdminHandler) UpdateProduct(c *gin.Context) {
|
||||
var cmd commands.UpdateProductCommand
|
||||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.productAppService.UpdateProduct(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("更新产品失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "产品更新成功")
|
||||
}
|
||||
|
||||
// DeleteProduct 删除产品
|
||||
// @Summary 删除产品
|
||||
// @Description 管理员删除产品
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "产品ID"
|
||||
// @Success 200 {object} map[string]interface{} "产品删除成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id} [delete]
|
||||
func (h *ProductAdminHandler) DeleteProduct(c *gin.Context) {
|
||||
var cmd commands.DeleteProductCommand
|
||||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.productAppService.DeleteProduct(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("删除产品失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "产品删除成功")
|
||||
}
|
||||
|
||||
// CreateCategory 创建分类
|
||||
// @Summary 创建分类
|
||||
// @Description 管理员创建新产品分类
|
||||
// @Tags 分类管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.CreateCategoryCommand true "创建分类请求"
|
||||
// @Success 201 {object} map[string]interface{} "分类创建成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/product-categories [post]
|
||||
func (h *ProductAdminHandler) CreateCategory(c *gin.Context) {
|
||||
var cmd commands.CreateCategoryCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.categoryAppService.CreateCategory(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("创建分类失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Created(c, nil, "分类创建成功")
|
||||
}
|
||||
|
||||
// UpdateCategory 更新分类
|
||||
// @Summary 更新分类
|
||||
// @Description 管理员更新产品分类信息
|
||||
// @Tags 分类管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "分类ID"
|
||||
// @Param request body commands.UpdateCategoryCommand true "更新分类请求"
|
||||
// @Success 200 {object} map[string]interface{} "分类更新成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "分类不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/product-categories/{id} [put]
|
||||
func (h *ProductAdminHandler) UpdateCategory(c *gin.Context) {
|
||||
var cmd commands.UpdateCategoryCommand
|
||||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.categoryAppService.UpdateCategory(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("更新分类失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "分类更新成功")
|
||||
}
|
||||
|
||||
// DeleteCategory 删除分类
|
||||
// @Summary 删除分类
|
||||
// @Description 管理员删除产品分类
|
||||
// @Tags 分类管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "分类ID"
|
||||
// @Success 200 {object} map[string]interface{} "分类删除成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "分类不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/product-categories/{id} [delete]
|
||||
func (h *ProductAdminHandler) DeleteCategory(c *gin.Context) {
|
||||
var cmd commands.DeleteCategoryCommand
|
||||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.categoryAppService.DeleteCategory(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("删除分类失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "分类删除成功")
|
||||
}
|
||||
|
||||
// UpdateSubscriptionPrice 更新订阅价格
|
||||
// @Summary 更新订阅价格
|
||||
// @Description 管理员修改用户订阅价格
|
||||
// @Tags 订阅管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "订阅ID"
|
||||
// @Param request body commands.UpdateSubscriptionPriceCommand true "更新订阅价格请求"
|
||||
// @Success 200 {object} map[string]interface{} "订阅价格更新成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "订阅不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/subscriptions/{id}/price [put]
|
||||
func (h *ProductAdminHandler) UpdateSubscriptionPrice(c *gin.Context) {
|
||||
var cmd commands.UpdateSubscriptionPriceCommand
|
||||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.subscriptionAppService.UpdateSubscriptionPrice(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("更新订阅价格失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "订阅价格更新成功")
|
||||
}
|
||||
|
||||
// ListProducts 获取产品列表(管理员)
|
||||
// @Summary 获取产品列表
|
||||
// @Description 管理员获取产品列表,支持筛选
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Param keyword query string false "搜索关键词"
|
||||
// @Param category_id query string false "分类ID"
|
||||
// @Param status query string false "产品状态"
|
||||
// @Success 200 {object} responses.ProductListResponse "获取产品列表成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products [get]
|
||||
func (h *ProductAdminHandler) ListProducts(c *gin.Context) {
|
||||
var query queries.ListProductsQuery
|
||||
if err := h.validator.ValidateQuery(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.PageSize <= 0 {
|
||||
query.PageSize = 10
|
||||
}
|
||||
if query.PageSize > 100 {
|
||||
query.PageSize = 100
|
||||
}
|
||||
|
||||
result, err := h.productAppService.ListProducts(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取产品列表失败", zap.Error(err))
|
||||
h.responseBuilder.InternalError(c, "获取产品列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取产品列表成功")
|
||||
}
|
||||
|
||||
// GetProductDetail 获取产品详情(管理员)
|
||||
// @Summary 获取产品详情
|
||||
// @Description 管理员获取产品详细信息
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "产品ID"
|
||||
// @Success 200 {object} responses.ProductInfoResponse "获取产品详情成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id} [get]
|
||||
func (h *ProductAdminHandler) GetProductDetail(c *gin.Context) {
|
||||
var query queries.GetProductQuery
|
||||
query.ID = c.Param("id")
|
||||
|
||||
if query.ID == "" {
|
||||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.productAppService.GetProductByID(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取产品详情失败", zap.Error(err), zap.String("product_id", query.ID))
|
||||
h.responseBuilder.NotFound(c, "产品不存在")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取产品详情成功")
|
||||
}
|
||||
|
||||
// ListCategories 获取分类列表(管理员)
|
||||
// @Summary 获取分类列表
|
||||
// @Description 管理员获取产品分类列表
|
||||
// @Tags 分类管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Success 200 {object} responses.CategoryListResponse "获取分类列表成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/product-categories [get]
|
||||
func (h *ProductAdminHandler) ListCategories(c *gin.Context) {
|
||||
var query queries.ListCategoriesQuery
|
||||
if err := h.validator.ValidateQuery(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.PageSize <= 0 {
|
||||
query.PageSize = 10
|
||||
}
|
||||
if query.PageSize > 100 {
|
||||
query.PageSize = 100
|
||||
}
|
||||
|
||||
result, err := h.categoryAppService.ListCategories(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取分类列表失败", zap.Error(err))
|
||||
h.responseBuilder.InternalError(c, "获取分类列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取分类列表成功")
|
||||
}
|
||||
|
||||
// GetCategoryDetail 获取分类详情(管理员)
|
||||
// @Summary 获取分类详情
|
||||
// @Description 管理员获取分类详细信息
|
||||
// @Tags 分类管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "分类ID"
|
||||
// @Success 200 {object} responses.CategoryInfoResponse "获取分类详情成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "分类不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/product-categories/{id} [get]
|
||||
func (h *ProductAdminHandler) GetCategoryDetail(c *gin.Context) {
|
||||
var query queries.GetCategoryQuery
|
||||
query.ID = c.Param("id")
|
||||
|
||||
if query.ID == "" {
|
||||
h.responseBuilder.BadRequest(c, "分类ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.categoryAppService.GetCategoryByID(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取分类详情失败", zap.Error(err), zap.String("category_id", query.ID))
|
||||
h.responseBuilder.NotFound(c, "分类不存在")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取分类详情成功")
|
||||
}
|
||||
|
||||
// ListSubscriptions 获取订阅列表(管理员)
|
||||
// @Summary 获取订阅列表
|
||||
// @Description 管理员获取订阅列表
|
||||
// @Tags 订阅管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Param status query string false "订阅状态"
|
||||
// @Success 200 {object} responses.SubscriptionListResponse "获取订阅列表成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/subscriptions [get]
|
||||
func (h *ProductAdminHandler) ListSubscriptions(c *gin.Context) {
|
||||
var query queries.ListSubscriptionsQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.PageSize <= 0 {
|
||||
query.PageSize = 10
|
||||
}
|
||||
if query.PageSize > 100 {
|
||||
query.PageSize = 100
|
||||
}
|
||||
|
||||
result, err := h.subscriptionAppService.ListSubscriptions(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取订阅列表失败", zap.Error(err))
|
||||
h.responseBuilder.InternalError(c, "获取订阅列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取订阅列表成功")
|
||||
}
|
||||
|
||||
// GetSubscriptionStats 获取订阅统计(管理员)
|
||||
// @Summary 获取订阅统计
|
||||
// @Description 管理员获取订阅统计信息
|
||||
// @Tags 订阅管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.SubscriptionStatsResponse "获取订阅统计成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/subscriptions/stats [get]
|
||||
func (h *ProductAdminHandler) GetSubscriptionStats(c *gin.Context) {
|
||||
result, err := h.subscriptionAppService.GetSubscriptionStats(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("获取订阅统计失败", zap.Error(err))
|
||||
h.responseBuilder.InternalError(c, "获取订阅统计失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取订阅统计成功")
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"tyapi-server/internal/application/product"
|
||||
"tyapi-server/internal/application/product/dto/commands"
|
||||
"tyapi-server/internal/application/product/dto/queries"
|
||||
@@ -17,6 +16,7 @@ type ProductHandler struct {
|
||||
categoryService product.CategoryApplicationService
|
||||
subAppService product.SubscriptionApplicationService
|
||||
responseBuilder interfaces.ResponseBuilder
|
||||
validator interfaces.RequestValidator
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ func NewProductHandler(
|
||||
categoryService product.CategoryApplicationService,
|
||||
subAppService product.SubscriptionApplicationService,
|
||||
responseBuilder interfaces.ResponseBuilder,
|
||||
validator interfaces.RequestValidator,
|
||||
logger *zap.Logger,
|
||||
) *ProductHandler {
|
||||
return &ProductHandler{
|
||||
@@ -33,6 +34,7 @@ func NewProductHandler(
|
||||
categoryService: categoryService,
|
||||
subAppService: subAppService,
|
||||
responseBuilder: responseBuilder,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
@@ -60,8 +62,7 @@ func NewProductHandler(
|
||||
// @Router /api/v1/products [get]
|
||||
func (h *ProductHandler) ListProducts(c *gin.Context) {
|
||||
var query queries.ListProductsQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
if err := h.validator.ValidateQuery(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -117,7 +118,6 @@ func (h *ProductHandler) GetProductDetail(c *gin.Context) {
|
||||
h.responseBuilder.Success(c, result, "获取产品详情成功")
|
||||
}
|
||||
|
||||
|
||||
// SubscribeProduct 订阅产品
|
||||
// @Summary 订阅产品
|
||||
// @Description 用户订阅指定产品
|
||||
@@ -126,7 +126,6 @@ func (h *ProductHandler) GetProductDetail(c *gin.Context) {
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "产品ID"
|
||||
// @Param request body commands.CreateSubscriptionCommand true "订阅请求"
|
||||
// @Success 200 {object} map[string]interface{} "订阅成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
@@ -136,36 +135,20 @@ func (h *ProductHandler) GetProductDetail(c *gin.Context) {
|
||||
func (h *ProductHandler) SubscribeProduct(c *gin.Context) {
|
||||
userID := c.GetString("user_id") // 从JWT中间件获取
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
return
|
||||
}
|
||||
|
||||
productID := c.Param("id")
|
||||
if productID == "" {
|
||||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.CreateSubscriptionCommand
|
||||
if err := c.ShouldBindJSON(&cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置用户ID和产品ID
|
||||
// 设置用户ID
|
||||
cmd.UserID = userID
|
||||
cmd.ProductID = productID
|
||||
|
||||
// 设置默认值
|
||||
if cmd.APILimit <= 0 {
|
||||
cmd.APILimit = 1000 // 默认API调用限制
|
||||
}
|
||||
if cmd.Duration == "" {
|
||||
cmd.Duration = "30d" // 默认订阅30天
|
||||
}
|
||||
|
||||
if err := h.subAppService.CreateSubscription(c.Request.Context(), &cmd); err != nil {
|
||||
h.logger.Error("订阅产品失败", zap.Error(err), zap.String("user_id", userID), zap.String("product_id", productID))
|
||||
h.logger.Error("订阅产品失败", zap.Error(err), zap.String("user_id", userID), zap.String("product_id", cmd.ProductID))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -197,48 +180,42 @@ func (h *ProductHandler) GetProductStats(c *gin.Context) {
|
||||
|
||||
// ListCategories 获取分类列表
|
||||
// @Summary 获取分类列表
|
||||
// @Description 获取产品分类列表,支持层级筛选
|
||||
// @Description 获取产品分类列表,支持筛选
|
||||
// @Tags 数据大厅
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param parent_id query string false "父级分类ID"
|
||||
// @Param level query int false "分类层级"
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Param is_enabled query bool false "是否启用"
|
||||
// @Param is_visible query bool false "是否可见"
|
||||
// @Success 200 {object} responses.CategoryListResponse "获取分类列表成功"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/categories [get]
|
||||
func (h *ProductHandler) ListCategories(c *gin.Context) {
|
||||
// 解析查询参数
|
||||
parentID := c.Query("parent_id")
|
||||
levelStr := c.Query("level")
|
||||
|
||||
// 构建查询命令
|
||||
query := &queries.ListCategoriesQuery{
|
||||
Page: 1,
|
||||
PageSize: 100,
|
||||
SortBy: "sort_order",
|
||||
SortOrder: "asc",
|
||||
var query queries.ListCategoriesQuery
|
||||
if err := h.validator.ValidateQuery(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置父级分类ID
|
||||
if parentID != "" {
|
||||
query.ParentID = &parentID
|
||||
|
||||
// 设置默认值
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
|
||||
// 设置分类层级
|
||||
if levelStr != "" {
|
||||
if level, err := strconv.Atoi(levelStr); err == nil {
|
||||
query.Level = &level
|
||||
}
|
||||
if query.PageSize <= 0 {
|
||||
query.PageSize = 10
|
||||
}
|
||||
|
||||
if query.PageSize > 100 {
|
||||
query.PageSize = 100
|
||||
}
|
||||
|
||||
// 调用应用服务
|
||||
categories, err := h.categoryService.ListCategories(c.Request.Context(), query)
|
||||
categories, err := h.categoryService.ListCategories(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取分类列表失败", zap.Error(err))
|
||||
h.responseBuilder.InternalError(c, "获取分类列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 返回结果
|
||||
h.responseBuilder.Success(c, categories, "获取分类列表成功")
|
||||
}
|
||||
@@ -261,12 +238,12 @@ func (h *ProductHandler) GetCategoryDetail(c *gin.Context) {
|
||||
h.responseBuilder.BadRequest(c, "分类ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 构建查询命令
|
||||
query := &queries.GetCategoryQuery{
|
||||
ID: categoryID,
|
||||
}
|
||||
|
||||
|
||||
// 调用应用服务
|
||||
category, err := h.categoryService.GetCategoryByID(c.Request.Context(), query)
|
||||
if err != nil {
|
||||
@@ -274,7 +251,7 @@ func (h *ProductHandler) GetCategoryDetail(c *gin.Context) {
|
||||
h.responseBuilder.NotFound(c, "分类不存在")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 返回结果
|
||||
h.responseBuilder.Success(c, category, "获取分类详情成功")
|
||||
}
|
||||
@@ -301,13 +278,12 @@ func (h *ProductHandler) GetCategoryDetail(c *gin.Context) {
|
||||
func (h *ProductHandler) ListMySubscriptions(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var query queries.ListSubscriptionsQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
if err := h.validator.ValidateQuery(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -349,7 +325,7 @@ func (h *ProductHandler) ListMySubscriptions(c *gin.Context) {
|
||||
func (h *ProductHandler) GetMySubscriptionStats(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -380,7 +356,7 @@ func (h *ProductHandler) GetMySubscriptionStats(c *gin.Context) {
|
||||
func (h *ProductHandler) GetMySubscriptionDetail(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -420,7 +396,7 @@ func (h *ProductHandler) GetMySubscriptionDetail(c *gin.Context) {
|
||||
func (h *ProductHandler) GetMySubscriptionUsage(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未认证")
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -439,6 +415,3 @@ func (h *ProductHandler) GetMySubscriptionUsage(c *gin.Context) {
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取我的订阅使用情况成功")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ func (h *UserHandler) LoginWithSMS(c *gin.Context) {
|
||||
func (h *UserHandler) GetProfile(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ func (h *UserHandler) GetProfile(c *gin.Context) {
|
||||
func (h *UserHandler) ChangePassword(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未认证")
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"tyapi-server/internal/infrastructure/http/handlers"
|
||||
sharedhttp "tyapi-server/internal/shared/http"
|
||||
"tyapi-server/internal/shared/middleware"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// AdminRoutes 管理员路由注册器
|
||||
type AdminRoutes struct {
|
||||
handler *handlers.AdminHandler
|
||||
authMiddleware *middleware.JWTAuthMiddleware
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewAdminRoutes 创建管理员路由注册器
|
||||
func NewAdminRoutes(
|
||||
handler *handlers.AdminHandler,
|
||||
authMiddleware *middleware.JWTAuthMiddleware,
|
||||
logger *zap.Logger,
|
||||
) *AdminRoutes {
|
||||
return &AdminRoutes{
|
||||
handler: handler,
|
||||
authMiddleware: authMiddleware,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Register 注册管理员相关路由
|
||||
func (r *AdminRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
// 管理员路由组
|
||||
engine := router.GetEngine()
|
||||
adminGroup := engine.Group("/api/v1/admin")
|
||||
{
|
||||
// 认证相关路由(无需认证)
|
||||
authGroup := adminGroup.Group("/auth")
|
||||
{
|
||||
authGroup.POST("/login", r.handler.Login)
|
||||
}
|
||||
|
||||
// 管理员管理路由(需要认证)
|
||||
authenticated := adminGroup.Group("")
|
||||
authenticated.Use(r.authMiddleware.Handle())
|
||||
{
|
||||
authenticated.POST("", r.handler.CreateAdmin) // 创建管理员
|
||||
authenticated.GET("", r.handler.ListAdmins) // 获取管理员列表
|
||||
authenticated.GET("/stats", r.handler.GetAdminStats) // 获取统计信息
|
||||
authenticated.GET("/:id", r.handler.GetAdminByID) // 获取管理员详情
|
||||
authenticated.PUT("/:id", r.handler.UpdateAdmin) // 更新管理员
|
||||
authenticated.DELETE("/:id", r.handler.DeleteAdmin) // 删除管理员
|
||||
authenticated.POST("/change-password", r.handler.ChangePassword) // 修改密码
|
||||
}
|
||||
}
|
||||
|
||||
r.logger.Info("管理员路由注册完成")
|
||||
}
|
||||
@@ -10,64 +10,49 @@ import (
|
||||
|
||||
// CertificationRoutes 认证路由注册器
|
||||
type CertificationRoutes struct {
|
||||
certificationHandler *handlers.CertificationHandler
|
||||
authMiddleware *middleware.JWTAuthMiddleware
|
||||
logger *zap.Logger
|
||||
handler *handlers.CertificationHandler
|
||||
authMiddleware *middleware.JWTAuthMiddleware
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewCertificationRoutes 创建认证路由注册器
|
||||
func NewCertificationRoutes(
|
||||
certificationHandler *handlers.CertificationHandler,
|
||||
handler *handlers.CertificationHandler,
|
||||
authMiddleware *middleware.JWTAuthMiddleware,
|
||||
logger *zap.Logger,
|
||||
) *CertificationRoutes {
|
||||
return &CertificationRoutes{
|
||||
certificationHandler: certificationHandler,
|
||||
authMiddleware: authMiddleware,
|
||||
logger: logger,
|
||||
handler: handler,
|
||||
authMiddleware: authMiddleware,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Register 注册认证相关路由
|
||||
func (r *CertificationRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
// 认证相关路由组,需要用户认证
|
||||
// 认证相关路由组
|
||||
engine := router.GetEngine()
|
||||
certificationGroup := engine.Group("/api/v1/certification")
|
||||
certificationGroup.Use(r.authMiddleware.Handle())
|
||||
{
|
||||
// 创建认证申请
|
||||
certificationGroup.POST("", r.certificationHandler.CreateCertification)
|
||||
// 认证状态查询
|
||||
certificationGroup.GET("/status", r.handler.GetCertificationStatus) // 获取认证状态
|
||||
certificationGroup.GET("/details", r.handler.GetCertificationDetails) // 获取认证详情
|
||||
certificationGroup.GET("/progress", r.handler.GetCertificationProgress) // 获取认证进度
|
||||
|
||||
// 营业执照上传
|
||||
certificationGroup.POST("/upload-license", r.certificationHandler.UploadBusinessLicense)
|
||||
// 企业信息管理
|
||||
certificationGroup.POST("/submit-enterprise-info", r.handler.SubmitEnterpriseInfo) // 提交企业信息(自动创建认证申请)
|
||||
|
||||
// 获取OCR识别结果
|
||||
certificationGroup.GET("/license/:record_id/ocr-result", r.certificationHandler.GetLicenseOCRResult)
|
||||
// 企业认证
|
||||
certificationGroup.GET("/enterprise-auth-url", r.handler.GetEnterpriseAuthURL) // 获取企业认证链接
|
||||
|
||||
// 获取认证状态
|
||||
certificationGroup.GET("/status", r.certificationHandler.GetCertificationStatus)
|
||||
|
||||
// 获取进度统计
|
||||
certificationGroup.GET("/stats", r.certificationHandler.GetProgressStats)
|
||||
|
||||
// 获取认证进度
|
||||
certificationGroup.GET("/progress", r.certificationHandler.GetCertificationProgress)
|
||||
|
||||
// 提交企业信息
|
||||
certificationGroup.POST("/enterprise-info", r.certificationHandler.SubmitEnterpriseInfo)
|
||||
|
||||
// 发起人脸识别验证
|
||||
certificationGroup.POST("/face-verify", r.certificationHandler.InitiateFaceVerify)
|
||||
|
||||
// 申请合同签署
|
||||
certificationGroup.POST("/contract", r.certificationHandler.ApplyContract)
|
||||
|
||||
// 获取认证详情
|
||||
certificationGroup.GET("/details", r.certificationHandler.GetCertificationDetails)
|
||||
|
||||
// 重试认证步骤
|
||||
certificationGroup.POST("/retry/:step", r.certificationHandler.RetryStep)
|
||||
// 合同管理
|
||||
certificationGroup.POST("/apply-contract", r.handler.ApplyContract) // 申请合同
|
||||
certificationGroup.GET("/contract-sign-url", r.handler.GetContractSignURL) // 获取合同签署链接
|
||||
}
|
||||
callbackGroup := engine.Group("/api/v1/certification")
|
||||
// e签宝回调
|
||||
callbackGroup.POST("/esign-callback", r.handler.EsignCallback) // e签宝回调
|
||||
|
||||
r.logger.Info("认证路由注册完成")
|
||||
}
|
||||
|
||||
65
internal/infrastructure/http/routes/product_admin_routes.go
Normal file
65
internal/infrastructure/http/routes/product_admin_routes.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"tyapi-server/internal/infrastructure/http/handlers"
|
||||
sharedhttp "tyapi-server/internal/shared/http"
|
||||
"tyapi-server/internal/shared/middleware"
|
||||
)
|
||||
|
||||
// ProductAdminRoutes 产品管理员路由
|
||||
type ProductAdminRoutes struct {
|
||||
handler *handlers.ProductAdminHandler
|
||||
auth *middleware.JWTAuthMiddleware
|
||||
admin *middleware.AdminAuthMiddleware
|
||||
}
|
||||
|
||||
// NewProductAdminRoutes 创建产品管理员路由
|
||||
func NewProductAdminRoutes(
|
||||
handler *handlers.ProductAdminHandler,
|
||||
auth *middleware.JWTAuthMiddleware,
|
||||
admin *middleware.AdminAuthMiddleware,
|
||||
) *ProductAdminRoutes {
|
||||
return &ProductAdminRoutes{
|
||||
handler: handler,
|
||||
auth: auth,
|
||||
admin: admin,
|
||||
}
|
||||
}
|
||||
|
||||
// Register 注册路由
|
||||
func (r *ProductAdminRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
// 管理员路由组
|
||||
engine := router.GetEngine()
|
||||
adminGroup := engine.Group("/api/v1/admin")
|
||||
adminGroup.Use(r.auth.Handle()) // JWT认证
|
||||
adminGroup.Use(r.admin.Handle()) // 管理员权限验证
|
||||
{
|
||||
// 产品管理
|
||||
products := adminGroup.Group("/products")
|
||||
{
|
||||
products.GET("", r.handler.ListProducts)
|
||||
products.GET("/:id", r.handler.GetProductDetail)
|
||||
products.POST("", r.handler.CreateProduct)
|
||||
products.PUT("/:id", r.handler.UpdateProduct)
|
||||
products.DELETE("/:id", r.handler.DeleteProduct)
|
||||
}
|
||||
|
||||
// 分类管理
|
||||
categories := adminGroup.Group("/product-categories")
|
||||
{
|
||||
categories.GET("", r.handler.ListCategories)
|
||||
categories.GET("/:id", r.handler.GetCategoryDetail)
|
||||
categories.POST("", r.handler.CreateCategory)
|
||||
categories.PUT("/:id", r.handler.UpdateCategory)
|
||||
categories.DELETE("/:id", r.handler.DeleteCategory)
|
||||
}
|
||||
|
||||
// 订阅管理
|
||||
subscriptions := adminGroup.Group("/subscriptions")
|
||||
{
|
||||
subscriptions.GET("", r.handler.ListSubscriptions)
|
||||
subscriptions.GET("/stats", r.handler.GetSubscriptionStats)
|
||||
subscriptions.PUT("/:id/price", r.handler.UpdateSubscriptionPrice)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user