You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
6.9 KiB
215 lines
6.9 KiB
1 week ago
|
package repository
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"gofaster/internal/auth/model"
|
||
|
"gofaster/internal/shared/repository"
|
||
|
|
||
|
"gorm.io/gorm"
|
||
|
)
|
||
|
|
||
|
type ResourceRepository interface {
|
||
|
Create(ctx context.Context, resource *model.Resource) error
|
||
|
Update(ctx context.Context, resource *model.Resource) error
|
||
|
Delete(ctx context.Context, id uint) error
|
||
|
GetByID(ctx context.Context, id uint) (*model.Resource, error)
|
||
|
GetByCode(ctx context.Context, code string) (*model.Resource, error)
|
||
|
List(ctx context.Context, offset, limit int) ([]*model.Resource, int64, error)
|
||
|
ListByModule(ctx context.Context, module string) ([]*model.Resource, error)
|
||
|
ListByType(ctx context.Context, resourceType string) ([]*model.Resource, error)
|
||
|
ListPublic(ctx context.Context) ([]*model.Resource, error)
|
||
|
GetTree(ctx context.Context) ([]*model.Resource, error)
|
||
|
BatchCreate(ctx context.Context, resources []*model.Resource) error
|
||
|
BatchUpdate(ctx context.Context, resources []*model.Resource) error
|
||
|
SyncFromRoutes(ctx context.Context, routes []RouteInfo) error
|
||
|
}
|
||
|
|
||
|
type resourceRepository struct {
|
||
|
*repository.BaseRepo
|
||
|
}
|
||
|
|
||
|
func NewResourceRepository(db *gorm.DB) ResourceRepository {
|
||
|
return &resourceRepository{
|
||
|
BaseRepo: repository.NewBaseRepo(db),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) Create(ctx context.Context, resource *model.Resource) error {
|
||
|
return r.DB().WithContext(ctx).Create(resource).Error
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) Update(ctx context.Context, resource *model.Resource) error {
|
||
|
return r.DB().WithContext(ctx).Save(resource).Error
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) Delete(ctx context.Context, id uint) error {
|
||
|
return r.DB().WithContext(ctx).Delete(&model.Resource{}, id).Error
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) GetByID(ctx context.Context, id uint) (*model.Resource, error) {
|
||
|
var resource model.Resource
|
||
|
err := r.DB().WithContext(ctx).First(&resource, id).Error
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &resource, nil
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) GetByCode(ctx context.Context, code string) (*model.Resource, error) {
|
||
|
var resource model.Resource
|
||
|
err := r.DB().WithContext(ctx).Where("code = ?", code).First(&resource).Error
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &resource, nil
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) List(ctx context.Context, offset, limit int) ([]*model.Resource, int64, error) {
|
||
|
var resources []*model.Resource
|
||
|
var total int64
|
||
|
|
||
|
// 添加调试日志
|
||
|
fmt.Printf("🔍 [资源查询] 开始查询资源列表,offset=%d, limit=%d\n", offset, limit)
|
||
|
|
||
|
err := r.DB().WithContext(ctx).Model(&model.Resource{}).Count(&total).Error
|
||
|
if err != nil {
|
||
|
fmt.Printf("🔍 [资源查询] 统计总数失败: %v\n", err)
|
||
|
return nil, 0, err
|
||
|
}
|
||
|
fmt.Printf("🔍 [资源查询] 数据库中共有 %d 条资源记录\n", total)
|
||
|
|
||
|
err = r.DB().WithContext(ctx).Offset(offset).Limit(limit).Order("sort ASC, id ASC").Find(&resources).Error
|
||
|
if err != nil {
|
||
|
fmt.Printf("🔍 [资源查询] 查询资源列表失败: %v\n", err)
|
||
|
return nil, 0, err
|
||
|
}
|
||
|
fmt.Printf("🔍 [资源查询] 查询到 %d 条资源记录\n", len(resources))
|
||
|
|
||
|
return resources, total, nil
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) ListByModule(ctx context.Context, module string) ([]*model.Resource, error) {
|
||
|
var resources []*model.Resource
|
||
|
err := r.DB().WithContext(ctx).Where("module = ? AND status = 1", module).Order("sort ASC, id ASC").Find(&resources).Error
|
||
|
return resources, err
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) ListByType(ctx context.Context, resourceType string) ([]*model.Resource, error) {
|
||
|
var resources []*model.Resource
|
||
|
err := r.DB().WithContext(ctx).Where("type = ? AND status = 1", resourceType).Order("sort ASC, id ASC").Find(&resources).Error
|
||
|
return resources, err
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) ListPublic(ctx context.Context) ([]*model.Resource, error) {
|
||
|
var resources []*model.Resource
|
||
|
err := r.DB().WithContext(ctx).Where("is_public = true AND status = 1").Order("sort ASC, id ASC").Find(&resources).Error
|
||
|
return resources, err
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) GetTree(ctx context.Context) ([]*model.Resource, error) {
|
||
|
var resources []*model.Resource
|
||
|
err := r.DB().WithContext(ctx).Where("status = 1").Order("sort ASC, id ASC").Find(&resources).Error
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
// 构建树形结构
|
||
|
return r.buildTree(resources), nil
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) buildTree(resources []*model.Resource) []*model.Resource {
|
||
|
resourceMap := make(map[uint]*model.Resource)
|
||
|
var roots []*model.Resource
|
||
|
|
||
|
// 创建映射
|
||
|
for _, resource := range resources {
|
||
|
resourceMap[resource.ID] = resource
|
||
|
}
|
||
|
|
||
|
// 构建树形结构
|
||
|
for _, resource := range resources {
|
||
|
if resource.ParentID == nil {
|
||
|
roots = append(roots, resource)
|
||
|
} else {
|
||
|
if _, exists := resourceMap[*resource.ParentID]; exists {
|
||
|
// 这里需要添加Children字段到Resource模型中
|
||
|
// 暂时跳过,后续可以扩展
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return roots
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) BatchCreate(ctx context.Context, resources []*model.Resource) error {
|
||
|
return r.DB().WithContext(ctx).CreateInBatches(resources, 100).Error
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) BatchUpdate(ctx context.Context, resources []*model.Resource) error {
|
||
|
return r.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||
|
for _, resource := range resources {
|
||
|
if err := tx.Save(resource).Error; err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// RouteInfo 路由信息
|
||
|
type RouteInfo struct {
|
||
|
Path string
|
||
|
Method string
|
||
|
Name string
|
||
|
Description string
|
||
|
Module string
|
||
|
IsPublic bool
|
||
|
}
|
||
|
|
||
|
func (r *resourceRepository) SyncFromRoutes(ctx context.Context, routes []RouteInfo) error {
|
||
|
return r.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||
|
for _, route := range routes {
|
||
|
// 生成资源代码
|
||
|
code := fmt.Sprintf("%s:%s:%s", route.Module, route.Method, route.Path)
|
||
|
|
||
|
// 检查资源是否已存在
|
||
|
var existingResource model.Resource
|
||
|
err := tx.Where("code = ?", code).First(&existingResource).Error
|
||
|
|
||
|
if err == gorm.ErrRecordNotFound {
|
||
|
// 创建新资源
|
||
|
resource := &model.Resource{
|
||
|
Name: route.Name,
|
||
|
Code: code,
|
||
|
Type: "api",
|
||
|
Path: route.Path,
|
||
|
Method: route.Method,
|
||
|
Description: route.Description,
|
||
|
Module: route.Module,
|
||
|
Status: 1,
|
||
|
IsPublic: route.IsPublic,
|
||
|
}
|
||
|
|
||
|
if err := tx.Create(resource).Error; err != nil {
|
||
|
return fmt.Errorf("创建资源失败: %v", err)
|
||
|
}
|
||
|
fmt.Printf("✅ 创建资源: %s (%s %s)\n", route.Name, route.Method, route.Path)
|
||
|
} else if err != nil {
|
||
|
return fmt.Errorf("查询资源失败: %v", err)
|
||
|
} else {
|
||
|
// 更新现有资源
|
||
|
existingResource.Name = route.Name
|
||
|
existingResource.Description = route.Description
|
||
|
existingResource.IsPublic = route.IsPublic
|
||
|
|
||
|
if err := tx.Save(&existingResource).Error; err != nil {
|
||
|
return fmt.Errorf("更新资源失败: %v", err)
|
||
|
}
|
||
|
fmt.Printf("🔄 更新资源: %s (%s %s)\n", route.Name, route.Method, route.Path)
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
}
|