Files
junhong_cmp_fiber/internal/store/postgres/account_store.go
huang fba8e9e76b
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m18s
refactor(account): 移除卡类型字段、优化账号列表查询和权限检查
- 移除 IoT 卡和号卡的 card_type 字段(数据库迁移)
- 优化账号列表查询,支持按店铺和企业筛选
- 账号响应增加店铺名称和企业名称字段
- 实现批量加载店铺和企业名称,避免 N+1 查询
- 更新权限检查中间件,完善权限验证逻辑
- 更新相关测试用例,确保功能正确性
2026-02-03 10:59:44 +08:00

288 lines
8.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package postgres
import (
"context"
"github.com/break/junhong_cmp_fiber/internal/store"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
)
// AccountStore 账号数据访问层
type AccountStore struct {
db *gorm.DB
redis *redis.Client
}
// NewAccountStore 创建账号 Store
func NewAccountStore(db *gorm.DB, redis *redis.Client) *AccountStore {
return &AccountStore{
db: db,
redis: redis,
}
}
// Create 创建账号
func (s *AccountStore) Create(ctx context.Context, account *model.Account) error {
return s.db.WithContext(ctx).Create(account).Error
}
// GetByID 根据 ID 获取账号
func (s *AccountStore) GetByID(ctx context.Context, id uint) (*model.Account, error) {
var account model.Account
if err := s.db.WithContext(ctx).First(&account, id).Error; err != nil {
return nil, err
}
return &account, nil
}
// GetByUsername 根据用户名获取账号
func (s *AccountStore) GetByUsername(ctx context.Context, username string) (*model.Account, error) {
var account model.Account
if err := s.db.WithContext(ctx).Where("username = ?", username).First(&account).Error; err != nil {
return nil, err
}
return &account, nil
}
// GetByPhone 根据手机号获取账号
func (s *AccountStore) GetByPhone(ctx context.Context, phone string) (*model.Account, error) {
var account model.Account
if err := s.db.WithContext(ctx).Where("phone = ?", phone).First(&account).Error; err != nil {
return nil, err
}
return &account, nil
}
// GetByUsernameOrPhone 根据用户名或手机号获取账号
func (s *AccountStore) GetByUsernameOrPhone(ctx context.Context, identifier string) (*model.Account, error) {
var account model.Account
if err := s.db.WithContext(ctx).Where("username = ? OR phone = ?", identifier, identifier).First(&account).Error; err != nil {
return nil, err
}
return &account, nil
}
// GetByShopID 根据店铺 ID 查询账号列表
func (s *AccountStore) GetByShopID(ctx context.Context, shopID uint) ([]*model.Account, error) {
var accounts []*model.Account
if err := s.db.WithContext(ctx).Where("shop_id = ?", shopID).Find(&accounts).Error; err != nil {
return nil, err
}
return accounts, nil
}
// GetByEnterpriseID 根据企业 ID 查询账号列表
func (s *AccountStore) GetByEnterpriseID(ctx context.Context, enterpriseID uint) ([]*model.Account, error) {
var accounts []*model.Account
if err := s.db.WithContext(ctx).Where("enterprise_id = ?", enterpriseID).Find(&accounts).Error; err != nil {
return nil, err
}
return accounts, nil
}
// Update 更新账号
func (s *AccountStore) Update(ctx context.Context, account *model.Account) error {
return s.db.WithContext(ctx).Save(account).Error
}
// Delete 软删除账号
func (s *AccountStore) Delete(ctx context.Context, id uint) error {
return s.db.WithContext(ctx).Delete(&model.Account{}, id).Error
}
// List 查询账号列表
func (s *AccountStore) List(ctx context.Context, opts *store.QueryOptions, filters map[string]interface{}) ([]*model.Account, int64, error) {
var accounts []*model.Account
var total int64
query := s.db.WithContext(ctx).Model(&model.Account{})
// 应用过滤条件
if username, ok := filters["username"].(string); ok && username != "" {
query = query.Where("username LIKE ?", "%"+username+"%")
}
if phone, ok := filters["phone"].(string); ok && phone != "" {
query = query.Where("phone LIKE ?", "%"+phone+"%")
}
if userType, ok := filters["user_type"].(int); ok {
query = query.Where("user_type = ?", userType)
}
if status, ok := filters["status"].(int); ok {
query = query.Where("status = ?", status)
}
if shopID, ok := filters["shop_id"].(uint); ok && shopID > 0 {
query = query.Where("shop_id = ?", shopID)
}
if enterpriseID, ok := filters["enterprise_id"].(uint); ok && enterpriseID > 0 {
query = query.Where("enterprise_id = ?", enterpriseID)
}
// 计算总数
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// 分页
if opts == nil {
opts = store.DefaultQueryOptions()
}
offset := (opts.Page - 1) * opts.PageSize
query = query.Offset(offset).Limit(opts.PageSize)
// 排序
if opts.OrderBy != "" {
query = query.Order(opts.OrderBy)
}
// 执行查询
if err := query.Find(&accounts).Error; err != nil {
return nil, 0, err
}
return accounts, total, nil
}
// ListPlatformAccounts 查询平台账号列表(自动筛选 user_type IN (1, 2)
func (s *AccountStore) ListPlatformAccounts(ctx context.Context, opts *store.QueryOptions, filters map[string]interface{}) ([]*model.Account, int64, error) {
var accounts []*model.Account
var total int64
query := s.db.WithContext(ctx).Model(&model.Account{})
// 固定筛选平台账号:超级管理员(1) 和 平台用户(2)
query = query.Where("user_type IN ?", []int{1, 2})
// 应用过滤条件
if username, ok := filters["username"].(string); ok && username != "" {
query = query.Where("username LIKE ?", "%"+username+"%")
}
if phone, ok := filters["phone"].(string); ok && phone != "" {
query = query.Where("phone LIKE ?", "%"+phone+"%")
}
if status, ok := filters["status"].(int); ok {
query = query.Where("status = ?", status)
}
// 计算总数
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// 分页
if opts == nil {
opts = store.DefaultQueryOptions()
}
offset := (opts.Page - 1) * opts.PageSize
query = query.Offset(offset).Limit(opts.PageSize)
// 排序
if opts.OrderBy != "" {
query = query.Order(opts.OrderBy)
}
// 执行查询
if err := query.Find(&accounts).Error; err != nil {
return nil, 0, err
}
return accounts, total, nil
}
// UpdatePassword 更新账号密码
func (s *AccountStore) UpdatePassword(ctx context.Context, id uint, hashedPassword string, updater uint) error {
return s.db.WithContext(ctx).
Model(&model.Account{}).
Where("id = ?", id).
Updates(map[string]interface{}{
"password": hashedPassword,
"updater": updater,
}).Error
}
// UpdateStatus 更新账号状态
func (s *AccountStore) UpdateStatus(ctx context.Context, id uint, status int, updater uint) error {
return s.db.WithContext(ctx).
Model(&model.Account{}).
Where("id = ?", id).
Updates(map[string]interface{}{
"status": status,
"updater": updater,
}).Error
}
// BulkUpdateStatus 批量更新账号状态
func (s *AccountStore) BulkUpdateStatus(ctx context.Context, ids []uint, status int, updater uint) error {
return s.db.WithContext(ctx).
Model(&model.Account{}).
Where("id IN ?", ids).
Updates(map[string]interface{}{
"status": status,
"updater": updater,
}).Error
}
func (s *AccountStore) GetByIDs(ctx context.Context, ids []uint) ([]*model.Account, error) {
if len(ids) == 0 {
return []*model.Account{}, nil
}
var accounts []*model.Account
if err := s.db.WithContext(ctx).Where("id IN ?", ids).Find(&accounts).Error; err != nil {
return nil, err
}
return accounts, nil
}
func (s *AccountStore) GetPrimaryAccountsByShopIDs(ctx context.Context, shopIDs []uint) ([]*model.Account, error) {
if len(shopIDs) == 0 {
return []*model.Account{}, nil
}
var accounts []*model.Account
if err := s.db.WithContext(ctx).
Where("shop_id IN ? AND is_primary = ?", shopIDs, true).
Find(&accounts).Error; err != nil {
return nil, err
}
return accounts, nil
}
// ListByShopID 按店铺ID分页查询账号列表
func (s *AccountStore) ListByShopID(ctx context.Context, shopID uint, opts *store.QueryOptions, filters map[string]interface{}) ([]*model.Account, int64, error) {
var accounts []*model.Account
var total int64
query := s.db.WithContext(ctx).Model(&model.Account{}).Where("shop_id = ?", shopID)
if username, ok := filters["username"].(string); ok && username != "" {
query = query.Where("username LIKE ?", "%"+username+"%")
}
if phone, ok := filters["phone"].(string); ok && phone != "" {
query = query.Where("phone LIKE ?", "%"+phone+"%")
}
if status, ok := filters["status"].(int); ok {
query = query.Where("status = ?", status)
}
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
if opts == nil {
opts = store.DefaultQueryOptions()
}
offset := (opts.Page - 1) * opts.PageSize
query = query.Offset(offset).Limit(opts.PageSize)
if opts.OrderBy != "" {
query = query.Order(opts.OrderBy)
}
if err := query.Find(&accounts).Error; err != nil {
return nil, 0, err
}
return accounts, total, nil
}