后端重构
This commit is contained in:
parent
8800c069d9
commit
9cb6b965e0
1
go.sum
1
go.sum
|
|
@ -231,6 +231,7 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO
|
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package biz
|
||||
|
||||
import (
|
||||
"kra/internal/biz/example"
|
||||
"kra/internal/biz/system"
|
||||
|
||||
"github.com/google/wire"
|
||||
|
|
@ -8,6 +9,7 @@ import (
|
|||
|
||||
// ProviderSet is biz providers.
|
||||
var ProviderSet = wire.NewSet(
|
||||
// System
|
||||
system.NewUserUsecase,
|
||||
system.NewApiUsecase,
|
||||
system.NewAuthorityUsecase,
|
||||
|
|
@ -18,4 +20,14 @@ var ProviderSet = wire.NewSet(
|
|||
system.NewJwtBlacklistUsecase,
|
||||
system.NewOperationRecordUsecase,
|
||||
system.NewParamsUsecase,
|
||||
system.NewErrorUsecase,
|
||||
system.NewVersionUsecase,
|
||||
system.NewSystemUsecase,
|
||||
system.NewExportTemplateUsecase,
|
||||
system.NewAutoCodeUsecase,
|
||||
system.NewAutoCodeHistoryUsecase,
|
||||
// Example
|
||||
example.NewFileUploadUsecase,
|
||||
example.NewCustomerUsecase,
|
||||
example.NewAttachmentCategoryUsecase,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AttachmentCategory 附件分类实体
|
||||
type AttachmentCategory struct {
|
||||
ID uint
|
||||
Name string
|
||||
Pid uint
|
||||
Children []*AttachmentCategory
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// AttachmentCategoryRepo 附件分类仓储接口
|
||||
type AttachmentCategoryRepo interface {
|
||||
Create(ctx context.Context, category *AttachmentCategory) error
|
||||
Update(ctx context.Context, category *AttachmentCategory) error
|
||||
Delete(ctx context.Context, id uint) error
|
||||
FindByID(ctx context.Context, id uint) (*AttachmentCategory, error)
|
||||
FindByNameAndPid(ctx context.Context, name string, pid uint) (*AttachmentCategory, error)
|
||||
FindAll(ctx context.Context) ([]*AttachmentCategory, error)
|
||||
HasChildren(ctx context.Context, id uint) (bool, error)
|
||||
}
|
||||
|
||||
// AttachmentCategoryUsecase 附件分类用例
|
||||
type AttachmentCategoryUsecase struct {
|
||||
repo AttachmentCategoryRepo
|
||||
}
|
||||
|
||||
// NewAttachmentCategoryUsecase 创建附件分类用例
|
||||
func NewAttachmentCategoryUsecase(repo AttachmentCategoryRepo) *AttachmentCategoryUsecase {
|
||||
return &AttachmentCategoryUsecase{repo: repo}
|
||||
}
|
||||
|
||||
// AddCategory 创建/更新分类
|
||||
func (uc *AttachmentCategoryUsecase) AddCategory(ctx context.Context, category *AttachmentCategory) error {
|
||||
// 检查是否已存在相同名称的分类
|
||||
existing, _ := uc.repo.FindByNameAndPid(ctx, category.Name, category.Pid)
|
||||
if existing != nil && existing.ID != category.ID {
|
||||
return errors.New("分类名称已存在")
|
||||
}
|
||||
|
||||
if category.ID > 0 {
|
||||
return uc.repo.Update(ctx, category)
|
||||
}
|
||||
return uc.repo.Create(ctx, category)
|
||||
}
|
||||
|
||||
// DeleteCategory 删除分类
|
||||
func (uc *AttachmentCategoryUsecase) DeleteCategory(ctx context.Context, id uint) error {
|
||||
hasChildren, err := uc.repo.HasChildren(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if hasChildren {
|
||||
return errors.New("请先删除子级")
|
||||
}
|
||||
return uc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// GetCategoryList 获取分类列表(树形)
|
||||
func (uc *AttachmentCategoryUsecase) GetCategoryList(ctx context.Context) ([]*AttachmentCategory, error) {
|
||||
categories, err := uc.repo.FindAll(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uc.buildTree(categories, 0), nil
|
||||
}
|
||||
|
||||
// buildTree 构建树形结构
|
||||
func (uc *AttachmentCategoryUsecase) buildTree(categories []*AttachmentCategory, parentID uint) []*AttachmentCategory {
|
||||
var tree []*AttachmentCategory
|
||||
for _, category := range categories {
|
||||
if category.Pid == parentID {
|
||||
category.Children = uc.buildTree(categories, category.ID)
|
||||
tree = append(tree, category)
|
||||
}
|
||||
}
|
||||
return tree
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Customer 客户实体
|
||||
type Customer struct {
|
||||
ID uint
|
||||
CustomerName string
|
||||
CustomerPhoneData string
|
||||
SysUserID uint
|
||||
SysUserAuthorityID uint
|
||||
SysUserName string // 关联用户名
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// CustomerSearchReq 客户搜索请求
|
||||
type CustomerSearchReq struct {
|
||||
Page int
|
||||
PageSize int
|
||||
}
|
||||
|
||||
// CustomerRepo 客户仓储接口
|
||||
type CustomerRepo interface {
|
||||
Create(ctx context.Context, customer *Customer) error
|
||||
Update(ctx context.Context, customer *Customer) error
|
||||
Delete(ctx context.Context, id uint) error
|
||||
FindByID(ctx context.Context, id uint) (*Customer, error)
|
||||
List(ctx context.Context, authorityIds []uint, page, pageSize int) ([]*Customer, int64, error)
|
||||
}
|
||||
|
||||
// DataAuthorityProvider 数据权限提供者接口
|
||||
type DataAuthorityProvider interface {
|
||||
GetDataAuthorityIds(ctx context.Context, authorityId uint) ([]uint, error)
|
||||
}
|
||||
|
||||
// SimpleDataAuthorityProvider 简单数据权限提供者(返回自身ID)
|
||||
type SimpleDataAuthorityProvider struct{}
|
||||
|
||||
func (s *SimpleDataAuthorityProvider) GetDataAuthorityIds(ctx context.Context, authorityId uint) ([]uint, error) {
|
||||
return []uint{authorityId}, nil
|
||||
}
|
||||
|
||||
// CustomerUsecase 客户用例
|
||||
type CustomerUsecase struct {
|
||||
repo CustomerRepo
|
||||
authProvider DataAuthorityProvider
|
||||
}
|
||||
|
||||
// NewCustomerUsecase 创建客户用例
|
||||
func NewCustomerUsecase(repo CustomerRepo, authProvider DataAuthorityProvider) *CustomerUsecase {
|
||||
return &CustomerUsecase{repo: repo, authProvider: authProvider}
|
||||
}
|
||||
|
||||
// CreateExaCustomer 创建客户
|
||||
func (uc *CustomerUsecase) CreateExaCustomer(ctx context.Context, customer *Customer) error {
|
||||
return uc.repo.Create(ctx, customer)
|
||||
}
|
||||
|
||||
// DeleteExaCustomer 删除客户
|
||||
func (uc *CustomerUsecase) DeleteExaCustomer(ctx context.Context, id uint) error {
|
||||
return uc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// UpdateExaCustomer 更新客户
|
||||
func (uc *CustomerUsecase) UpdateExaCustomer(ctx context.Context, customer *Customer) error {
|
||||
return uc.repo.Update(ctx, customer)
|
||||
}
|
||||
|
||||
// GetExaCustomer 获取客户信息
|
||||
func (uc *CustomerUsecase) GetExaCustomer(ctx context.Context, id uint) (*Customer, error) {
|
||||
return uc.repo.FindByID(ctx, id)
|
||||
}
|
||||
|
||||
// GetCustomerInfoList 分页获取客户列表
|
||||
func (uc *CustomerUsecase) GetCustomerInfoList(ctx context.Context, authorityId uint, page, pageSize int) ([]*Customer, int64, error) {
|
||||
// 获取数据权限ID列表
|
||||
dataIds, err := uc.authProvider.GetDataAuthorityIds(ctx, authorityId)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return uc.repo.List(ctx, dataIds, page, pageSize)
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"mime/multipart"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// FileUpload 文件上传实体
|
||||
type FileUpload struct {
|
||||
ID uint
|
||||
Name string
|
||||
ClassId int
|
||||
Url string
|
||||
Tag string
|
||||
Key string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// FileUploadSearchReq 文件搜索请求
|
||||
type FileUploadSearchReq struct {
|
||||
Page int
|
||||
PageSize int
|
||||
Keyword string
|
||||
ClassId int
|
||||
}
|
||||
|
||||
// OssUploader OSS上传接口(与 pkg/upload.OSS 兼容)
|
||||
type OssUploader interface {
|
||||
UploadFile(file *multipart.FileHeader) (string, string, error)
|
||||
DeleteFile(key string) error
|
||||
}
|
||||
|
||||
// NilOssUploader 空OSS上传器(用于未配置OSS时)
|
||||
type NilOssUploader struct{}
|
||||
|
||||
func (n *NilOssUploader) UploadFile(file *multipart.FileHeader) (string, string, error) {
|
||||
return "", "", errors.New("OSS未配置")
|
||||
}
|
||||
|
||||
func (n *NilOssUploader) DeleteFile(key string) error {
|
||||
return errors.New("OSS未配置")
|
||||
}
|
||||
|
||||
// FileUploadRepo 文件上传仓储接口
|
||||
type FileUploadRepo interface {
|
||||
Create(ctx context.Context, file *FileUpload) error
|
||||
Update(ctx context.Context, file *FileUpload) error
|
||||
Delete(ctx context.Context, id uint) error
|
||||
FindByID(ctx context.Context, id uint) (*FileUpload, error)
|
||||
FindByKey(ctx context.Context, key string) (*FileUpload, error)
|
||||
List(ctx context.Context, req *FileUploadSearchReq) ([]*FileUpload, int64, error)
|
||||
BatchCreate(ctx context.Context, files []*FileUpload) error
|
||||
}
|
||||
|
||||
// FileUploadUsecase 文件上传用例
|
||||
type FileUploadUsecase struct {
|
||||
repo FileUploadRepo
|
||||
oss OssUploader
|
||||
}
|
||||
|
||||
// NewFileUploadUsecase 创建文件上传用例
|
||||
func NewFileUploadUsecase(repo FileUploadRepo, oss OssUploader) *FileUploadUsecase {
|
||||
return &FileUploadUsecase{repo: repo, oss: oss}
|
||||
}
|
||||
|
||||
// Upload 创建文件上传记录
|
||||
func (uc *FileUploadUsecase) Upload(ctx context.Context, file *FileUpload) error {
|
||||
return uc.repo.Create(ctx, file)
|
||||
}
|
||||
|
||||
// FindFile 查询文件记录
|
||||
func (uc *FileUploadUsecase) FindFile(ctx context.Context, id uint) (*FileUpload, error) {
|
||||
return uc.repo.FindByID(ctx, id)
|
||||
}
|
||||
|
||||
// DeleteFile 删除文件记录
|
||||
func (uc *FileUploadUsecase) DeleteFile(ctx context.Context, id uint) error {
|
||||
file, err := uc.repo.FindByID(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除OSS文件
|
||||
if uc.oss != nil && file.Key != "" {
|
||||
if err := uc.oss.DeleteFile(file.Key); err != nil {
|
||||
return errors.New("文件删除失败")
|
||||
}
|
||||
}
|
||||
|
||||
return uc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// EditFileName 编辑文件名
|
||||
func (uc *FileUploadUsecase) EditFileName(ctx context.Context, id uint, name string) error {
|
||||
file, err := uc.repo.FindByID(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file.Name = name
|
||||
return uc.repo.Update(ctx, file)
|
||||
}
|
||||
|
||||
// GetFileRecordInfoList 分页获取文件列表
|
||||
func (uc *FileUploadUsecase) GetFileRecordInfoList(ctx context.Context, req *FileUploadSearchReq) ([]*FileUpload, int64, error) {
|
||||
return uc.repo.List(ctx, req)
|
||||
}
|
||||
|
||||
// UploadFile 上传文件
|
||||
func (uc *FileUploadUsecase) UploadFile(ctx context.Context, header *multipart.FileHeader, noSave string, classId int) (*FileUpload, error) {
|
||||
if uc.oss == nil {
|
||||
return nil, errors.New("OSS未配置")
|
||||
}
|
||||
|
||||
filePath, key, err := uc.oss.UploadFile(header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := strings.Split(header.Filename, ".")
|
||||
file := &FileUpload{
|
||||
Url: filePath,
|
||||
Name: header.Filename,
|
||||
ClassId: classId,
|
||||
Tag: s[len(s)-1],
|
||||
Key: key,
|
||||
}
|
||||
|
||||
if noSave == "0" {
|
||||
// 检查是否已存在相同key的记录
|
||||
existing, _ := uc.repo.FindByKey(ctx, key)
|
||||
if existing == nil {
|
||||
if err := uc.repo.Create(ctx, file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// ImportURL 导入URL
|
||||
func (uc *FileUploadUsecase) ImportURL(ctx context.Context, files []*FileUpload) error {
|
||||
return uc.repo.BatchCreate(ctx, files)
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Db 数据库信息
|
||||
type Db struct {
|
||||
Database string `json:"database" gorm:"column:database"`
|
||||
}
|
||||
|
||||
// Table 表信息
|
||||
type Table struct {
|
||||
TableName string `json:"tableName" gorm:"column:table_name"`
|
||||
}
|
||||
|
||||
// Column 列信息
|
||||
type Column struct {
|
||||
ColumnName string `json:"columnName" gorm:"column:column_name"`
|
||||
DataType string `json:"dataType" gorm:"column:data_type"`
|
||||
DataTypeLong string `json:"dataTypeLong" gorm:"column:data_type_long"`
|
||||
ColumnComment string `json:"columnComment" gorm:"column:column_comment"`
|
||||
PrimaryKey int `json:"primaryKey" gorm:"column:primary_key"`
|
||||
}
|
||||
|
||||
// AutoCodeRepo 自动代码仓储接口
|
||||
type AutoCodeRepo interface {
|
||||
GetDB(ctx context.Context) ([]Db, error)
|
||||
GetTables(ctx context.Context, dbName string) ([]Table, error)
|
||||
GetColumn(ctx context.Context, tableName, dbName string) ([]Column, error)
|
||||
}
|
||||
|
||||
// AutoCodeUsecase 自动代码用例
|
||||
type AutoCodeUsecase struct {
|
||||
repo AutoCodeRepo
|
||||
}
|
||||
|
||||
// NewAutoCodeUsecase 创建自动代码用例
|
||||
func NewAutoCodeUsecase(repo AutoCodeRepo) *AutoCodeUsecase {
|
||||
return &AutoCodeUsecase{repo: repo}
|
||||
}
|
||||
|
||||
// GetDB 获取所有数据库
|
||||
func (uc *AutoCodeUsecase) GetDB(ctx context.Context) ([]Db, error) {
|
||||
return uc.repo.GetDB(ctx)
|
||||
}
|
||||
|
||||
// GetTables 获取指定数据库的所有表
|
||||
func (uc *AutoCodeUsecase) GetTables(ctx context.Context, dbName string) ([]Table, error) {
|
||||
return uc.repo.GetTables(ctx, dbName)
|
||||
}
|
||||
|
||||
// GetColumn 获取指定表的所有列
|
||||
func (uc *AutoCodeUsecase) GetColumn(ctx context.Context, tableName, dbName string) ([]Column, error) {
|
||||
return uc.repo.GetColumn(ctx, tableName, dbName)
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SysAutoCodeHistory 自动代码生成历史
|
||||
type SysAutoCodeHistory struct {
|
||||
ID uint `json:"ID" gorm:"primarykey"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Table string `json:"tableName" gorm:"column:table_name;comment:表名"`
|
||||
Package string `json:"package" gorm:"column:package;comment:模块名/插件名"`
|
||||
Request string `json:"request" gorm:"type:text;column:request;comment:前端传入的结构化信息"`
|
||||
StructName string `json:"structName" gorm:"column:struct_name;comment:结构体名称"`
|
||||
Abbreviation string `json:"abbreviation" gorm:"column:abbreviation;comment:结构体名称缩写"`
|
||||
BusinessDB string `json:"businessDb" gorm:"column:business_db;comment:业务库"`
|
||||
Description string `json:"description" gorm:"column:description;comment:Struct中文名称"`
|
||||
Templates map[string]string `json:"template" gorm:"serializer:json;type:text;column:templates;comment:模板信息"`
|
||||
Injections map[string]string `json:"injections" gorm:"serializer:json;type:text;column:Injections;comment:注入路径"`
|
||||
Flag int `json:"flag" gorm:"column:flag;comment:[0:创建,1:回滚]"`
|
||||
ApiIDs []uint `json:"apiIDs" gorm:"serializer:json;column:api_ids;comment:api表注册内容"`
|
||||
MenuID uint `json:"menuId" gorm:"column:menu_id;comment:菜单ID"`
|
||||
ExportTemplateID uint `json:"exportTemplateID" gorm:"column:export_template_id;comment:导出模板ID"`
|
||||
PackageID uint `json:"packageID" gorm:"column:package_id;comment:包ID"`
|
||||
}
|
||||
|
||||
func (SysAutoCodeHistory) TableName() string {
|
||||
return "sys_auto_code_histories"
|
||||
}
|
||||
|
||||
// AutoCodeHistorySearchReq 历史搜索请求
|
||||
type AutoCodeHistorySearchReq struct {
|
||||
Page int `json:"page" form:"page"`
|
||||
PageSize int `json:"pageSize" form:"pageSize"`
|
||||
}
|
||||
|
||||
// SysAutoHistoryRollBack 回滚请求
|
||||
type SysAutoHistoryRollBack struct {
|
||||
ID uint `json:"id"`
|
||||
DeleteApi bool `json:"deleteApi"`
|
||||
DeleteMenu bool `json:"deleteMenu"`
|
||||
DeleteTable bool `json:"deleteTable"`
|
||||
}
|
||||
|
||||
// AutoCodeHistoryRepo 自动代码历史仓储接口
|
||||
type AutoCodeHistoryRepo interface {
|
||||
First(ctx context.Context, id uint) (string, error)
|
||||
Delete(ctx context.Context, id uint) error
|
||||
GetList(ctx context.Context, page, pageSize int) ([]SysAutoCodeHistory, int64, error)
|
||||
GetByID(ctx context.Context, id uint) (*SysAutoCodeHistory, error)
|
||||
UpdateFlag(ctx context.Context, id uint, flag int) error
|
||||
DropTable(ctx context.Context, businessDB, tableName string) error
|
||||
}
|
||||
|
||||
// AutoCodeHistoryUsecase 自动代码历史用例
|
||||
type AutoCodeHistoryUsecase struct {
|
||||
repo AutoCodeHistoryRepo
|
||||
}
|
||||
|
||||
// NewAutoCodeHistoryUsecase 创建自动代码历史用例
|
||||
func NewAutoCodeHistoryUsecase(repo AutoCodeHistoryRepo) *AutoCodeHistoryUsecase {
|
||||
return &AutoCodeHistoryUsecase{repo: repo}
|
||||
}
|
||||
|
||||
// First 根据id获取meta信息
|
||||
func (uc *AutoCodeHistoryUsecase) First(ctx context.Context, id uint) (string, error) {
|
||||
return uc.repo.First(ctx, id)
|
||||
}
|
||||
|
||||
// Delete 删除历史记录
|
||||
func (uc *AutoCodeHistoryUsecase) Delete(ctx context.Context, id uint) error {
|
||||
return uc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// GetList 获取历史记录列表
|
||||
func (uc *AutoCodeHistoryUsecase) GetList(ctx context.Context, page, pageSize int) ([]SysAutoCodeHistory, int64, error) {
|
||||
return uc.repo.GetList(ctx, page, pageSize)
|
||||
}
|
||||
|
||||
// RollBack 回滚自动生成代码
|
||||
// 注意:完整的回滚功能需要AST工具支持,这里只实现基础功能
|
||||
func (uc *AutoCodeHistoryUsecase) RollBack(ctx context.Context, info SysAutoHistoryRollBack) error {
|
||||
// 获取历史记录
|
||||
history, err := uc.repo.GetByID(ctx, info.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除表(如果需要)
|
||||
if info.DeleteTable && history.Table != "" {
|
||||
err = uc.repo.DropTable(ctx, history.BusinessDB, history.Table)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 更新标记为已回滚
|
||||
return uc.repo.UpdateFlag(ctx, info.ID, 1)
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrErrorNotFound = errors.New("错误日志不存在")
|
||||
)
|
||||
|
||||
// SysError 错误日志实体
|
||||
type SysError struct {
|
||||
ID int64
|
||||
Form string
|
||||
Info string
|
||||
Level string
|
||||
Solution string
|
||||
Status string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// ErrorSearchReq 错误日志搜索请求
|
||||
type ErrorSearchReq struct {
|
||||
Page int
|
||||
PageSize int
|
||||
Form *string
|
||||
Info *string
|
||||
CreatedAtRange []time.Time
|
||||
}
|
||||
|
||||
// ErrorRepo 错误日志仓储接口
|
||||
type ErrorRepo interface {
|
||||
Create(ctx context.Context, sysError *SysError) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
DeleteByIds(ctx context.Context, ids []string) error
|
||||
Update(ctx context.Context, sysError *SysError) error
|
||||
GetById(ctx context.Context, id string) (*SysError, error)
|
||||
GetList(ctx context.Context, req *ErrorSearchReq) ([]*SysError, int64, error)
|
||||
UpdateStatus(ctx context.Context, id string, status string) error
|
||||
UpdateSolution(ctx context.Context, id string, status string, solution string) error
|
||||
}
|
||||
|
||||
// ErrorUsecase 错误日志用例
|
||||
type ErrorUsecase struct {
|
||||
repo ErrorRepo
|
||||
}
|
||||
|
||||
// NewErrorUsecase 创建错误日志用例
|
||||
func NewErrorUsecase(repo ErrorRepo) *ErrorUsecase {
|
||||
return &ErrorUsecase{repo: repo}
|
||||
}
|
||||
|
||||
// CreateSysError 创建错误日志
|
||||
func (uc *ErrorUsecase) CreateSysError(ctx context.Context, sysError *SysError) error {
|
||||
return uc.repo.Create(ctx, sysError)
|
||||
}
|
||||
|
||||
// DeleteSysError 删除错误日志
|
||||
func (uc *ErrorUsecase) DeleteSysError(ctx context.Context, id string) error {
|
||||
return uc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// DeleteSysErrorByIds 批量删除错误日志
|
||||
func (uc *ErrorUsecase) DeleteSysErrorByIds(ctx context.Context, ids []string) error {
|
||||
return uc.repo.DeleteByIds(ctx, ids)
|
||||
}
|
||||
|
||||
// UpdateSysError 更新错误日志
|
||||
func (uc *ErrorUsecase) UpdateSysError(ctx context.Context, sysError *SysError) error {
|
||||
return uc.repo.Update(ctx, sysError)
|
||||
}
|
||||
|
||||
// GetSysError 根据ID获取错误日志
|
||||
func (uc *ErrorUsecase) GetSysError(ctx context.Context, id string) (*SysError, error) {
|
||||
return uc.repo.GetById(ctx, id)
|
||||
}
|
||||
|
||||
// GetSysErrorInfoList 分页获取错误日志列表
|
||||
func (uc *ErrorUsecase) GetSysErrorInfoList(ctx context.Context, req *ErrorSearchReq) ([]*SysError, int64, error) {
|
||||
return uc.repo.GetList(ctx, req)
|
||||
}
|
||||
|
||||
// GetSysErrorSolution 异步处理错误(触发AI生成解决方案)
|
||||
func (uc *ErrorUsecase) GetSysErrorSolution(ctx context.Context, id string) error {
|
||||
// 立即更新为处理中
|
||||
if err := uc.repo.UpdateStatus(ctx, id, "处理中"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 异步处理(简化版本,不调用LLM)
|
||||
go func(errorId string) {
|
||||
// 这里可以集成AI服务生成解决方案
|
||||
// 目前简化为直接标记处理完成
|
||||
_ = uc.repo.UpdateStatus(context.Background(), errorId, "处理完成")
|
||||
}(id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,598 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ExportTemplate 导出模板实体
|
||||
type ExportTemplate struct {
|
||||
ID uint
|
||||
DBName string
|
||||
Name string
|
||||
TableName string
|
||||
TemplateID string
|
||||
TemplateInfo string
|
||||
Limit *int
|
||||
Order string
|
||||
Conditions []*Condition
|
||||
JoinTemplate []*JoinTemplate
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// Condition 条件实体
|
||||
type Condition struct {
|
||||
ID uint
|
||||
TemplateID string
|
||||
From string
|
||||
Column string
|
||||
Operator string
|
||||
}
|
||||
|
||||
// JoinTemplate 关联模板实体
|
||||
type JoinTemplate struct {
|
||||
ID uint
|
||||
TemplateID string
|
||||
Joins string
|
||||
Table string
|
||||
On string
|
||||
}
|
||||
|
||||
// ExportTemplateSearchReq 导出模板搜索请求
|
||||
type ExportTemplateSearchReq struct {
|
||||
Page int
|
||||
PageSize int
|
||||
Name string
|
||||
TableName string
|
||||
TemplateID string
|
||||
StartCreatedAt *time.Time
|
||||
EndCreatedAt *time.Time
|
||||
}
|
||||
|
||||
// ExportTemplateRepo 导出模板仓储接口
|
||||
type ExportTemplateRepo interface {
|
||||
Create(ctx context.Context, template *ExportTemplate) error
|
||||
Update(ctx context.Context, template *ExportTemplate) error
|
||||
Delete(ctx context.Context, id uint) error
|
||||
FindByID(ctx context.Context, id uint) (*ExportTemplate, error)
|
||||
FindByTemplateID(ctx context.Context, templateID string) (*ExportTemplate, error)
|
||||
GetList(ctx context.Context, req *ExportTemplateSearchReq) ([]*ExportTemplate, int64, error)
|
||||
DeleteConditionsByTemplateID(ctx context.Context, templateID string) error
|
||||
DeleteJoinsByTemplateID(ctx context.Context, templateID string) error
|
||||
CreateConditions(ctx context.Context, conditions []*Condition) error
|
||||
CreateJoins(ctx context.Context, joins []*JoinTemplate) error
|
||||
// Excel 相关
|
||||
GetDB(dbName string) interface{}
|
||||
ExecuteQuery(ctx context.Context, dbName, sql string, args ...interface{}) ([]map[string]interface{}, error)
|
||||
GetColumnTypes(ctx context.Context, dbName, tableName string) ([]string, error)
|
||||
HasDeletedAtColumn(ctx context.Context, tableName string) bool
|
||||
ImportData(ctx context.Context, dbName, tableName string, items []map[string]interface{}) error
|
||||
}
|
||||
|
||||
// ExportTemplateUsecase 导出模板用例
|
||||
type ExportTemplateUsecase struct {
|
||||
repo ExportTemplateRepo
|
||||
}
|
||||
|
||||
// NewExportTemplateUsecase 创建导出模板用例
|
||||
func NewExportTemplateUsecase(repo ExportTemplateRepo) *ExportTemplateUsecase {
|
||||
return &ExportTemplateUsecase{repo: repo}
|
||||
}
|
||||
|
||||
// CreateExportTemplate 创建导出模板
|
||||
func (uc *ExportTemplateUsecase) CreateExportTemplate(ctx context.Context, template *ExportTemplate) error {
|
||||
return uc.repo.Create(ctx, template)
|
||||
}
|
||||
|
||||
// DeleteExportTemplate 删除导出模板
|
||||
func (uc *ExportTemplateUsecase) DeleteExportTemplate(ctx context.Context, id uint) error {
|
||||
return uc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// DeleteExportTemplateByIds 批量删除导出模板
|
||||
func (uc *ExportTemplateUsecase) DeleteExportTemplateByIds(ctx context.Context, ids []uint) error {
|
||||
for _, id := range ids {
|
||||
if err := uc.repo.Delete(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateExportTemplate 更新导出模板
|
||||
func (uc *ExportTemplateUsecase) UpdateExportTemplate(ctx context.Context, template *ExportTemplate) error {
|
||||
// 删除旧的条件和关联
|
||||
if err := uc.repo.DeleteConditionsByTemplateID(ctx, template.TemplateID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := uc.repo.DeleteJoinsByTemplateID(ctx, template.TemplateID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 保存条件
|
||||
conditions := template.Conditions
|
||||
template.Conditions = nil
|
||||
|
||||
// 保存关联
|
||||
joins := template.JoinTemplate
|
||||
template.JoinTemplate = nil
|
||||
|
||||
// 更新模板
|
||||
if err := uc.repo.Update(ctx, template); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建新的条件
|
||||
if len(conditions) > 0 {
|
||||
for i := range conditions {
|
||||
conditions[i].ID = 0
|
||||
}
|
||||
if err := uc.repo.CreateConditions(ctx, conditions); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新的关联
|
||||
if len(joins) > 0 {
|
||||
for i := range joins {
|
||||
joins[i].ID = 0
|
||||
}
|
||||
if err := uc.repo.CreateJoins(ctx, joins); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetExportTemplate 根据ID获取导出模板
|
||||
func (uc *ExportTemplateUsecase) GetExportTemplate(ctx context.Context, id uint) (*ExportTemplate, error) {
|
||||
return uc.repo.FindByID(ctx, id)
|
||||
}
|
||||
|
||||
// GetExportTemplateList 分页获取导出模板列表
|
||||
func (uc *ExportTemplateUsecase) GetExportTemplateList(ctx context.Context, req *ExportTemplateSearchReq) ([]*ExportTemplate, int64, error) {
|
||||
return uc.repo.GetList(ctx, req)
|
||||
}
|
||||
|
||||
// ExportExcel 导出Excel
|
||||
func (uc *ExportTemplateUsecase) ExportExcel(ctx context.Context, templateID string, values url.Values) (*bytes.Buffer, string, error) {
|
||||
params := values.Get("params")
|
||||
paramsValues, err := url.ParseQuery(params)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("解析 params 参数失败: %v", err)
|
||||
}
|
||||
|
||||
template, err := uc.repo.FindByTemplateID(ctx, templateID)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// 解析模板信息
|
||||
var templateInfoMap = make(map[string]string)
|
||||
columns, err := getJSONKeys(template.TemplateInfo)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if err := json.Unmarshal([]byte(template.TemplateInfo), &templateInfoMap); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var tableTitle []string
|
||||
var selectKeyFmt []string
|
||||
for _, key := range columns {
|
||||
selectKeyFmt = append(selectKeyFmt, key)
|
||||
tableTitle = append(tableTitle, templateInfoMap[key])
|
||||
}
|
||||
|
||||
selects := strings.Join(selectKeyFmt, ", ")
|
||||
|
||||
// 构建SQL
|
||||
var sb strings.Builder
|
||||
sb.WriteString("SELECT ")
|
||||
sb.WriteString(selects)
|
||||
sb.WriteString(" FROM ")
|
||||
sb.WriteString(template.TableName)
|
||||
|
||||
// JOIN
|
||||
if len(template.JoinTemplate) > 0 {
|
||||
for _, join := range template.JoinTemplate {
|
||||
sb.WriteString(" ")
|
||||
sb.WriteString(join.Joins)
|
||||
sb.WriteString(" ")
|
||||
sb.WriteString(join.Table)
|
||||
sb.WriteString(" ON ")
|
||||
sb.WriteString(join.On)
|
||||
}
|
||||
}
|
||||
|
||||
// WHERE
|
||||
var wheres []string
|
||||
var args []interface{}
|
||||
|
||||
// 软删除过滤
|
||||
filterDeleted := paramsValues.Get("filterDeleted") == "true"
|
||||
if filterDeleted {
|
||||
wheres = append(wheres, fmt.Sprintf("%s.deleted_at IS NULL", template.TableName))
|
||||
for _, join := range template.JoinTemplate {
|
||||
if uc.repo.HasDeletedAtColumn(ctx, join.Table) {
|
||||
wheres = append(wheres, fmt.Sprintf("%s.deleted_at IS NULL", join.Table))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 条件
|
||||
for _, condition := range template.Conditions {
|
||||
value := paramsValues.Get(condition.From)
|
||||
op := strings.ToUpper(strings.TrimSpace(condition.Operator))
|
||||
|
||||
if op == "BETWEEN" {
|
||||
startValue := paramsValues.Get("start" + condition.From)
|
||||
endValue := paramsValues.Get("end" + condition.From)
|
||||
if startValue != "" && endValue != "" {
|
||||
wheres = append(wheres, fmt.Sprintf("%s BETWEEN ? AND ?", condition.Column))
|
||||
args = append(args, startValue, endValue)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if op == "LIKE" {
|
||||
wheres = append(wheres, fmt.Sprintf("%s LIKE ?", condition.Column))
|
||||
args = append(args, "%"+value+"%")
|
||||
} else if op == "IN" || op == "NOT IN" {
|
||||
wheres = append(wheres, fmt.Sprintf("%s %s (?)", condition.Column, op))
|
||||
args = append(args, value)
|
||||
} else {
|
||||
wheres = append(wheres, fmt.Sprintf("%s %s ?", condition.Column, op))
|
||||
args = append(args, value)
|
||||
}
|
||||
}
|
||||
|
||||
if len(wheres) > 0 {
|
||||
sb.WriteString(" WHERE ")
|
||||
sb.WriteString(strings.Join(wheres, " AND "))
|
||||
}
|
||||
|
||||
// ORDER
|
||||
order := paramsValues.Get("order")
|
||||
if order == "" && template.Order != "" {
|
||||
order = template.Order
|
||||
}
|
||||
if order != "" {
|
||||
sb.WriteString(" ORDER BY ")
|
||||
sb.WriteString(order)
|
||||
}
|
||||
|
||||
// LIMIT
|
||||
limit := paramsValues.Get("limit")
|
||||
if limit == "" && template.Limit != nil && *template.Limit != 0 {
|
||||
limit = strconv.Itoa(*template.Limit)
|
||||
}
|
||||
if limit != "" {
|
||||
sb.WriteString(" LIMIT ")
|
||||
sb.WriteString(limit)
|
||||
}
|
||||
|
||||
// OFFSET
|
||||
offset := paramsValues.Get("offset")
|
||||
if offset != "" {
|
||||
sb.WriteString(" OFFSET ")
|
||||
sb.WriteString(offset)
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
tableMap, err := uc.repo.ExecuteQuery(ctx, template.DBName, sb.String(), args...)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// 生成Excel
|
||||
return uc.generateExcel(tableMap, columns, tableTitle, template)
|
||||
}
|
||||
|
||||
// generateExcel 生成Excel文件
|
||||
func (uc *ExportTemplateUsecase) generateExcel(tableMap []map[string]interface{}, columns, tableTitle []string, template *ExportTemplate) (*bytes.Buffer, string, error) {
|
||||
// 简化实现:生成CSV格式
|
||||
var buf bytes.Buffer
|
||||
|
||||
// 写入标题行
|
||||
buf.WriteString(strings.Join(tableTitle, ","))
|
||||
buf.WriteString("\n")
|
||||
|
||||
// 写入数据行
|
||||
for _, row := range tableMap {
|
||||
var values []string
|
||||
for _, col := range columns {
|
||||
col = strings.ReplaceAll(col, "\"", "")
|
||||
col = strings.ReplaceAll(col, "`", "")
|
||||
if len(template.JoinTemplate) > 0 {
|
||||
columnAs := strings.Split(col, " as ")
|
||||
if len(columnAs) > 1 {
|
||||
col = strings.TrimSpace(columnAs[1])
|
||||
} else {
|
||||
columnArr := strings.Split(col, ".")
|
||||
if len(columnArr) > 1 {
|
||||
col = columnArr[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
if t, ok := row[col].(time.Time); ok {
|
||||
values = append(values, t.Format("2006-01-02 15:04:05"))
|
||||
} else {
|
||||
values = append(values, fmt.Sprintf("%v", row[col]))
|
||||
}
|
||||
}
|
||||
buf.WriteString(strings.Join(values, ","))
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
|
||||
return &buf, template.Name, nil
|
||||
}
|
||||
|
||||
// PreviewSQL 预览SQL
|
||||
func (uc *ExportTemplateUsecase) PreviewSQL(ctx context.Context, templateID string, values url.Values) (string, error) {
|
||||
params := values.Get("params")
|
||||
paramsValues, _ := url.ParseQuery(params)
|
||||
|
||||
template, err := uc.repo.FindByTemplateID(ctx, templateID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 解析模板信息
|
||||
var templateInfoMap = make(map[string]string)
|
||||
columns, err := getJSONKeys(template.TemplateInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := json.Unmarshal([]byte(template.TemplateInfo), &templateInfoMap); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var selectKeyFmt []string
|
||||
for _, key := range columns {
|
||||
selectKeyFmt = append(selectKeyFmt, key)
|
||||
}
|
||||
selects := strings.Join(selectKeyFmt, ", ")
|
||||
|
||||
// 构建SQL
|
||||
var sb strings.Builder
|
||||
sb.WriteString("SELECT ")
|
||||
sb.WriteString(selects)
|
||||
sb.WriteString(" FROM ")
|
||||
sb.WriteString(template.TableName)
|
||||
|
||||
// JOIN
|
||||
if len(template.JoinTemplate) > 0 {
|
||||
for _, join := range template.JoinTemplate {
|
||||
sb.WriteString(" ")
|
||||
sb.WriteString(join.Joins)
|
||||
sb.WriteString(" ")
|
||||
sb.WriteString(join.Table)
|
||||
sb.WriteString(" ON ")
|
||||
sb.WriteString(join.On)
|
||||
}
|
||||
}
|
||||
|
||||
// WHERE
|
||||
var wheres []string
|
||||
|
||||
filterDeleted := false
|
||||
if paramsValues != nil {
|
||||
filterDeleted = paramsValues.Get("filterDeleted") == "true"
|
||||
}
|
||||
if filterDeleted {
|
||||
wheres = append(wheres, fmt.Sprintf("%s.deleted_at IS NULL", template.TableName))
|
||||
for _, join := range template.JoinTemplate {
|
||||
if uc.repo.HasDeletedAtColumn(ctx, join.Table) {
|
||||
wheres = append(wheres, fmt.Sprintf("%s.deleted_at IS NULL", join.Table))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 条件
|
||||
for _, condition := range template.Conditions {
|
||||
op := strings.ToUpper(strings.TrimSpace(condition.Operator))
|
||||
col := strings.TrimSpace(condition.Column)
|
||||
|
||||
val := ""
|
||||
if paramsValues != nil {
|
||||
val = paramsValues.Get(condition.From)
|
||||
}
|
||||
|
||||
switch op {
|
||||
case "BETWEEN":
|
||||
startValue := ""
|
||||
endValue := ""
|
||||
if paramsValues != nil {
|
||||
startValue = paramsValues.Get("start" + condition.From)
|
||||
endValue = paramsValues.Get("end" + condition.From)
|
||||
}
|
||||
if startValue != "" && endValue != "" {
|
||||
wheres = append(wheres, fmt.Sprintf("%s BETWEEN '%s' AND '%s'", col, startValue, endValue))
|
||||
} else {
|
||||
wheres = append(wheres, fmt.Sprintf("%s BETWEEN {start%s} AND {end%s}", col, condition.From, condition.From))
|
||||
}
|
||||
case "IN", "NOT IN":
|
||||
if val != "" {
|
||||
wheres = append(wheres, fmt.Sprintf("%s %s ('%s')", col, op, val))
|
||||
} else {
|
||||
wheres = append(wheres, fmt.Sprintf("%s %s ({%s})", col, op, condition.From))
|
||||
}
|
||||
case "LIKE":
|
||||
if val != "" {
|
||||
wheres = append(wheres, fmt.Sprintf("%s LIKE '%%%s%%'", col, val))
|
||||
} else {
|
||||
wheres = append(wheres, fmt.Sprintf("%s LIKE {%%%s%%}", col, condition.From))
|
||||
}
|
||||
default:
|
||||
if val != "" {
|
||||
wheres = append(wheres, fmt.Sprintf("%s %s '%s'", col, op, val))
|
||||
} else {
|
||||
wheres = append(wheres, fmt.Sprintf("%s %s {%s}", col, op, condition.From))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(wheres) > 0 {
|
||||
sb.WriteString(" WHERE ")
|
||||
sb.WriteString(strings.Join(wheres, " AND "))
|
||||
}
|
||||
|
||||
// ORDER
|
||||
order := ""
|
||||
if paramsValues != nil {
|
||||
order = paramsValues.Get("order")
|
||||
}
|
||||
if order == "" && template.Order != "" {
|
||||
order = template.Order
|
||||
}
|
||||
if order != "" {
|
||||
sb.WriteString(" ORDER BY ")
|
||||
sb.WriteString(order)
|
||||
}
|
||||
|
||||
// LIMIT/OFFSET
|
||||
limitStr := ""
|
||||
offsetStr := ""
|
||||
if paramsValues != nil {
|
||||
limitStr = paramsValues.Get("limit")
|
||||
offsetStr = paramsValues.Get("offset")
|
||||
}
|
||||
if limitStr == "" && template.Limit != nil && *template.Limit != 0 {
|
||||
limitStr = strconv.Itoa(*template.Limit)
|
||||
}
|
||||
|
||||
limitInt := 0
|
||||
offsetInt := 0
|
||||
if limitStr != "" {
|
||||
if v, e := strconv.Atoi(limitStr); e == nil {
|
||||
limitInt = v
|
||||
}
|
||||
}
|
||||
if offsetStr != "" {
|
||||
if v, e := strconv.Atoi(offsetStr); e == nil {
|
||||
offsetInt = v
|
||||
}
|
||||
}
|
||||
|
||||
if limitInt > 0 {
|
||||
sb.WriteString(" LIMIT ")
|
||||
sb.WriteString(strconv.Itoa(limitInt))
|
||||
if offsetInt > 0 {
|
||||
sb.WriteString(" OFFSET ")
|
||||
sb.WriteString(strconv.Itoa(offsetInt))
|
||||
}
|
||||
} else if offsetInt > 0 {
|
||||
sb.WriteString(" OFFSET ")
|
||||
sb.WriteString(strconv.Itoa(offsetInt))
|
||||
}
|
||||
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
// ExportTemplate 导出Excel模板
|
||||
func (uc *ExportTemplateUsecase) ExportTemplate(ctx context.Context, templateID string) (*bytes.Buffer, string, error) {
|
||||
template, err := uc.repo.FindByTemplateID(ctx, templateID)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var templateInfoMap = make(map[string]string)
|
||||
columns, err := getJSONKeys(template.TemplateInfo)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if err := json.Unmarshal([]byte(template.TemplateInfo), &templateInfoMap); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var tableTitle []string
|
||||
for _, key := range columns {
|
||||
tableTitle = append(tableTitle, templateInfoMap[key])
|
||||
}
|
||||
|
||||
// 生成CSV模板
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(strings.Join(tableTitle, ","))
|
||||
buf.WriteString("\n")
|
||||
|
||||
return &buf, template.Name, nil
|
||||
}
|
||||
|
||||
// ImportExcel 导入Excel
|
||||
func (uc *ExportTemplateUsecase) ImportExcel(ctx context.Context, templateID string, file *multipart.FileHeader) error {
|
||||
template, err := uc.repo.FindByTemplateID(ctx, templateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
// 简化实现:读取CSV格式
|
||||
var templateInfoMap = make(map[string]string)
|
||||
if err := json.Unmarshal([]byte(template.TemplateInfo), &templateInfoMap); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var titleKeyMap = make(map[string]string)
|
||||
for key, title := range templateInfoMap {
|
||||
titleKeyMap[title] = key
|
||||
}
|
||||
|
||||
// 这里需要实际的Excel解析逻辑
|
||||
return errors.New("Excel导入功能需要excelize库支持")
|
||||
}
|
||||
|
||||
// getJSONKeys 获取JSON对象的键(保持顺序)
|
||||
func getJSONKeys(jsonStr string) ([]string, error) {
|
||||
var result []string
|
||||
dec := json.NewDecoder(strings.NewReader(jsonStr))
|
||||
|
||||
// 读取开始的 {
|
||||
t, err := dec.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if t != json.Delim('{') {
|
||||
return nil, errors.New("expected {")
|
||||
}
|
||||
|
||||
for dec.More() {
|
||||
// 读取键
|
||||
t, err := dec.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key, ok := t.(string)
|
||||
if !ok {
|
||||
return nil, errors.New("expected string key")
|
||||
}
|
||||
result = append(result, key)
|
||||
|
||||
// 跳过值
|
||||
var value interface{}
|
||||
if err := dec.Decode(&value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/pkg/server"
|
||||
)
|
||||
|
||||
// SystemUsecase 系统配置用例
|
||||
type SystemUsecase struct {
|
||||
diskMountPoints []string
|
||||
}
|
||||
|
||||
// NewSystemUsecase 创建系统配置用例
|
||||
func NewSystemUsecase() *SystemUsecase {
|
||||
// 默认磁盘挂载点,可通过配置扩展
|
||||
return &SystemUsecase{
|
||||
diskMountPoints: []string{"/"},
|
||||
}
|
||||
}
|
||||
|
||||
// GetServerInfo 获取服务器信息
|
||||
func (uc *SystemUsecase) GetServerInfo(ctx context.Context) (*server.Server, error) {
|
||||
return server.GetServerInfo(uc.diskMountPoints)
|
||||
}
|
||||
|
||||
// SetDiskMountPoints 设置磁盘挂载点
|
||||
func (uc *SystemUsecase) SetDiskMountPoints(mountPoints []string) {
|
||||
uc.diskMountPoints = mountPoints
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrVersionNotFound = errors.New("版本不存在")
|
||||
)
|
||||
|
||||
// SysVersion 版本管理实体
|
||||
type SysVersion struct {
|
||||
ID int64
|
||||
VersionName string
|
||||
VersionCode string
|
||||
Description string
|
||||
VersionData string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// VersionSearchReq 版本搜索请求
|
||||
type VersionSearchReq struct {
|
||||
Page int
|
||||
PageSize int
|
||||
VersionName *string
|
||||
VersionCode *string
|
||||
CreatedAtRange []time.Time
|
||||
}
|
||||
|
||||
// VersionRepo 版本仓储接口
|
||||
type VersionRepo interface {
|
||||
Create(ctx context.Context, version *SysVersion) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
DeleteByIds(ctx context.Context, ids []string) error
|
||||
GetById(ctx context.Context, id string) (*SysVersion, error)
|
||||
GetList(ctx context.Context, req *VersionSearchReq) ([]*SysVersion, int64, error)
|
||||
}
|
||||
|
||||
// VersionUsecase 版本用例
|
||||
type VersionUsecase struct {
|
||||
repo VersionRepo
|
||||
menuRepo MenuRepo
|
||||
apiRepo ApiRepo
|
||||
dictRepo DictionaryRepo
|
||||
}
|
||||
|
||||
// NewVersionUsecase 创建版本用例
|
||||
func NewVersionUsecase(repo VersionRepo, menuRepo MenuRepo, apiRepo ApiRepo, dictRepo DictionaryRepo) *VersionUsecase {
|
||||
return &VersionUsecase{
|
||||
repo: repo,
|
||||
menuRepo: menuRepo,
|
||||
apiRepo: apiRepo,
|
||||
dictRepo: dictRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateSysVersion 创建版本
|
||||
func (uc *VersionUsecase) CreateSysVersion(ctx context.Context, version *SysVersion) error {
|
||||
return uc.repo.Create(ctx, version)
|
||||
}
|
||||
|
||||
// DeleteSysVersion 删除版本
|
||||
func (uc *VersionUsecase) DeleteSysVersion(ctx context.Context, id string) error {
|
||||
return uc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// DeleteSysVersionByIds 批量删除版本
|
||||
func (uc *VersionUsecase) DeleteSysVersionByIds(ctx context.Context, ids []string) error {
|
||||
return uc.repo.DeleteByIds(ctx, ids)
|
||||
}
|
||||
|
||||
// GetSysVersion 根据ID获取版本
|
||||
func (uc *VersionUsecase) GetSysVersion(ctx context.Context, id string) (*SysVersion, error) {
|
||||
return uc.repo.GetById(ctx, id)
|
||||
}
|
||||
|
||||
// GetSysVersionInfoList 分页获取版本列表
|
||||
func (uc *VersionUsecase) GetSysVersionInfoList(ctx context.Context, req *VersionSearchReq) ([]*SysVersion, int64, error) {
|
||||
return uc.repo.GetList(ctx, req)
|
||||
}
|
||||
|
||||
// GetMenusByIds 根据ID列表获取菜单数据
|
||||
func (uc *VersionUsecase) GetMenusByIds(ctx context.Context, ids []uint) ([]*Menu, error) {
|
||||
// 转换为string类型
|
||||
strIds := make([]string, len(ids))
|
||||
for i, id := range ids {
|
||||
strIds[i] = strconv.FormatUint(uint64(id), 10)
|
||||
}
|
||||
baseMenus, err := uc.menuRepo.FindBaseMenusByIds(ctx, strIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 转换为Menu类型
|
||||
menus := make([]*Menu, len(baseMenus))
|
||||
for i, bm := range baseMenus {
|
||||
menus[i] = &Menu{
|
||||
BaseMenu: *bm,
|
||||
MenuId: bm.ID,
|
||||
}
|
||||
}
|
||||
return menus, nil
|
||||
}
|
||||
|
||||
// GetApisByIds 根据ID列表获取API数据
|
||||
func (uc *VersionUsecase) GetApisByIds(ctx context.Context, ids []uint) ([]*Api, error) {
|
||||
return uc.apiRepo.FindByIds(ctx, ids)
|
||||
}
|
||||
|
||||
// GetDictionariesByIds 根据ID列表获取字典数据(简化实现)
|
||||
func (uc *VersionUsecase) GetDictionariesByIds(ctx context.Context, ids []uint) ([]*Dictionary, error) {
|
||||
var result []*Dictionary
|
||||
for _, id := range ids {
|
||||
dict, err := uc.dictRepo.FindByID(ctx, id)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, dict)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
|
@ -2,7 +2,9 @@ package data
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"kra/internal/biz/example"
|
||||
"kra/internal/conf"
|
||||
dataexample "kra/internal/data/example"
|
||||
datasystem "kra/internal/data/system"
|
||||
pkgcasbin "kra/pkg/casbin"
|
||||
|
||||
|
|
@ -19,6 +21,9 @@ var ProviderSet = wire.NewSet(
|
|||
NewDB,
|
||||
NewData,
|
||||
NewCasbinEnforcer,
|
||||
NewOssUploader,
|
||||
NewDataAuthorityProvider,
|
||||
// System
|
||||
datasystem.NewUserRepo,
|
||||
datasystem.NewApiRepo,
|
||||
datasystem.NewAuthorityRepo,
|
||||
|
|
@ -30,6 +35,15 @@ var ProviderSet = wire.NewSet(
|
|||
datasystem.NewJwtBlacklistRepo,
|
||||
datasystem.NewOperationRecordRepo,
|
||||
datasystem.NewParamsRepo,
|
||||
datasystem.NewErrorRepo,
|
||||
datasystem.NewVersionRepo,
|
||||
datasystem.NewExportTemplateRepo,
|
||||
datasystem.NewAutoCodeRepo,
|
||||
datasystem.NewAutoCodeHistoryRepo,
|
||||
// Example
|
||||
dataexample.NewFileUploadRepo,
|
||||
dataexample.NewCustomerRepo,
|
||||
dataexample.NewAttachmentCategoryRepo,
|
||||
)
|
||||
|
||||
// Data 数据层包装器
|
||||
|
|
@ -66,3 +80,15 @@ func NewDB(c *conf.Mysql) (*gorm.DB, error) {
|
|||
func NewCasbinEnforcer(db *gorm.DB) (*casbin.SyncedCachedEnforcer, error) {
|
||||
return pkgcasbin.InitCasbin(db, "")
|
||||
}
|
||||
|
||||
// NewOssUploader 创建OSS上传器(默认使用空实现)
|
||||
func NewOssUploader() example.OssUploader {
|
||||
// TODO: 根据配置返回实际的OSS实现
|
||||
return &example.NilOssUploader{}
|
||||
}
|
||||
|
||||
// NewDataAuthorityProvider 创建数据权限提供者(默认使用简单实现)
|
||||
func NewDataAuthorityProvider() example.DataAuthorityProvider {
|
||||
// TODO: 根据需要返回实际的数据权限实现
|
||||
return &example.SimpleDataAuthorityProvider{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz/example"
|
||||
"kra/internal/data/model"
|
||||
"kra/internal/data/query"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type attachmentCategoryRepo struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewAttachmentCategoryRepo 创建附件分类仓储
|
||||
func NewAttachmentCategoryRepo(db *gorm.DB) example.AttachmentCategoryRepo {
|
||||
return &attachmentCategoryRepo{db: db}
|
||||
}
|
||||
|
||||
func (r *attachmentCategoryRepo) Create(ctx context.Context, category *example.AttachmentCategory) error {
|
||||
m := &model.ExaAttachmentCategory{
|
||||
Name: category.Name,
|
||||
Pid: int64(category.Pid),
|
||||
}
|
||||
return r.db.WithContext(ctx).Create(m).Error
|
||||
}
|
||||
|
||||
func (r *attachmentCategoryRepo) Update(ctx context.Context, category *example.AttachmentCategory) error {
|
||||
return r.db.WithContext(ctx).Model(&model.ExaAttachmentCategory{}).
|
||||
Where("id = ?", category.ID).
|
||||
Updates(map[string]any{
|
||||
"name": category.Name,
|
||||
"pid": category.Pid,
|
||||
}).Error
|
||||
}
|
||||
|
||||
func (r *attachmentCategoryRepo) Delete(ctx context.Context, id uint) error {
|
||||
return r.db.WithContext(ctx).Unscoped().
|
||||
Where("id = ?", id).
|
||||
Delete(&model.ExaAttachmentCategory{}).Error
|
||||
}
|
||||
|
||||
func (r *attachmentCategoryRepo) FindByID(ctx context.Context, id uint) (*example.AttachmentCategory, error) {
|
||||
c := query.ExaAttachmentCategory
|
||||
m, err := c.WithContext(ctx).Where(c.ID.Eq(int64(id))).First()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toCategoryBiz(m), nil
|
||||
}
|
||||
|
||||
func (r *attachmentCategoryRepo) FindByNameAndPid(ctx context.Context, name string, pid uint) (*example.AttachmentCategory, error) {
|
||||
c := query.ExaAttachmentCategory
|
||||
m, err := c.WithContext(ctx).Where(c.Name.Eq(name), c.Pid.Eq(int64(pid))).First()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toCategoryBiz(m), nil
|
||||
}
|
||||
|
||||
func (r *attachmentCategoryRepo) FindAll(ctx context.Context) ([]*example.AttachmentCategory, error) {
|
||||
c := query.ExaAttachmentCategory
|
||||
list, err := c.WithContext(ctx).Find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*example.AttachmentCategory, len(list))
|
||||
for i, m := range list {
|
||||
result[i] = toCategoryBiz(m)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *attachmentCategoryRepo) HasChildren(ctx context.Context, id uint) (bool, error) {
|
||||
c := query.ExaAttachmentCategory
|
||||
count, err := c.WithContext(ctx).Where(c.Pid.Eq(int64(id))).Count()
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// 转换函数
|
||||
func toCategoryBiz(m *model.ExaAttachmentCategory) *example.AttachmentCategory {
|
||||
return &example.AttachmentCategory{
|
||||
ID: uint(m.ID),
|
||||
Name: m.Name,
|
||||
Pid: uint(m.Pid),
|
||||
CreatedAt: m.CreatedAt,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz/example"
|
||||
"kra/internal/data/model"
|
||||
"kra/internal/data/query"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type customerRepo struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewCustomerRepo 创建客户仓储
|
||||
func NewCustomerRepo(db *gorm.DB) example.CustomerRepo {
|
||||
return &customerRepo{db: db}
|
||||
}
|
||||
|
||||
func (r *customerRepo) Create(ctx context.Context, customer *example.Customer) error {
|
||||
m := toCustomerModel(customer)
|
||||
return r.db.WithContext(ctx).Create(m).Error
|
||||
}
|
||||
|
||||
func (r *customerRepo) Update(ctx context.Context, customer *example.Customer) error {
|
||||
return r.db.WithContext(ctx).Save(toCustomerModel(customer)).Error
|
||||
}
|
||||
|
||||
func (r *customerRepo) Delete(ctx context.Context, id uint) error {
|
||||
return r.db.WithContext(ctx).Delete(&model.ExaCustomer{}, id).Error
|
||||
}
|
||||
|
||||
func (r *customerRepo) FindByID(ctx context.Context, id uint) (*example.Customer, error) {
|
||||
c := query.ExaCustomer
|
||||
m, err := c.WithContext(ctx).Where(c.ID.Eq(int64(id))).First()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toCustomerBiz(m), nil
|
||||
}
|
||||
|
||||
func (r *customerRepo) List(ctx context.Context, authorityIds []uint, page, pageSize int) ([]*example.Customer, int64, error) {
|
||||
c := query.ExaCustomer
|
||||
q := c.WithContext(ctx)
|
||||
|
||||
if len(authorityIds) > 0 {
|
||||
ids := make([]int64, len(authorityIds))
|
||||
for i, id := range authorityIds {
|
||||
ids[i] = int64(id)
|
||||
}
|
||||
q = q.Where(c.SysUserAuthorityID.In(ids...))
|
||||
}
|
||||
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
list, err := q.Offset(offset).Limit(pageSize).Find()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := make([]*example.Customer, len(list))
|
||||
for i, m := range list {
|
||||
result[i] = toCustomerBiz(m)
|
||||
}
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// 转换函数
|
||||
func toCustomerModel(c *example.Customer) *model.ExaCustomer {
|
||||
return &model.ExaCustomer{
|
||||
ID: int64(c.ID),
|
||||
CustomerName: c.CustomerName,
|
||||
CustomerPhoneData: c.CustomerPhoneData,
|
||||
SysUserID: int64(c.SysUserID),
|
||||
SysUserAuthorityID: int64(c.SysUserAuthorityID),
|
||||
}
|
||||
}
|
||||
|
||||
func toCustomerBiz(m *model.ExaCustomer) *example.Customer {
|
||||
return &example.Customer{
|
||||
ID: uint(m.ID),
|
||||
CustomerName: m.CustomerName,
|
||||
CustomerPhoneData: m.CustomerPhoneData,
|
||||
SysUserID: uint(m.SysUserID),
|
||||
SysUserAuthorityID: uint(m.SysUserAuthorityID),
|
||||
CreatedAt: m.CreatedAt,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz/example"
|
||||
"kra/internal/data/model"
|
||||
"kra/internal/data/query"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type fileUploadRepo struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewFileUploadRepo 创建文件上传仓储
|
||||
func NewFileUploadRepo(db *gorm.DB) example.FileUploadRepo {
|
||||
return &fileUploadRepo{db: db}
|
||||
}
|
||||
|
||||
func (r *fileUploadRepo) Create(ctx context.Context, file *example.FileUpload) error {
|
||||
m := toFileUploadModel(file)
|
||||
return r.db.WithContext(ctx).Create(m).Error
|
||||
}
|
||||
|
||||
func (r *fileUploadRepo) Update(ctx context.Context, file *example.FileUpload) error {
|
||||
return r.db.WithContext(ctx).Model(&model.ExaFileUploadAndDownload{}).
|
||||
Where("id = ?", file.ID).
|
||||
Updates(map[string]any{
|
||||
"name": file.Name,
|
||||
"class_id": file.ClassId,
|
||||
}).Error
|
||||
}
|
||||
|
||||
func (r *fileUploadRepo) Delete(ctx context.Context, id uint) error {
|
||||
return r.db.WithContext(ctx).Unscoped().
|
||||
Where("id = ?", id).
|
||||
Delete(&model.ExaFileUploadAndDownload{}).Error
|
||||
}
|
||||
|
||||
func (r *fileUploadRepo) FindByID(ctx context.Context, id uint) (*example.FileUpload, error) {
|
||||
f := query.ExaFileUploadAndDownload
|
||||
m, err := f.WithContext(ctx).Where(f.ID.Eq(int64(id))).First()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toFileUploadBiz(m), nil
|
||||
}
|
||||
|
||||
func (r *fileUploadRepo) FindByKey(ctx context.Context, key string) (*example.FileUpload, error) {
|
||||
f := query.ExaFileUploadAndDownload
|
||||
m, err := f.WithContext(ctx).Where(f.Key.Eq(key)).First()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toFileUploadBiz(m), nil
|
||||
}
|
||||
|
||||
func (r *fileUploadRepo) List(ctx context.Context, req *example.FileUploadSearchReq) ([]*example.FileUpload, int64, error) {
|
||||
f := query.ExaFileUploadAndDownload
|
||||
q := f.WithContext(ctx)
|
||||
|
||||
if req.Keyword != "" {
|
||||
q = q.Where(f.Name.Like("%" + req.Keyword + "%"))
|
||||
}
|
||||
if req.ClassId > 0 {
|
||||
q = q.Where(f.ClassID.Eq(int64(req.ClassId)))
|
||||
}
|
||||
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
list, err := q.Order(f.ID.Desc()).Offset(offset).Limit(req.PageSize).Find()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := make([]*example.FileUpload, len(list))
|
||||
for i, m := range list {
|
||||
result[i] = toFileUploadBiz(m)
|
||||
}
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
func (r *fileUploadRepo) BatchCreate(ctx context.Context, files []*example.FileUpload) error {
|
||||
models := make([]*model.ExaFileUploadAndDownload, len(files))
|
||||
for i, f := range files {
|
||||
models[i] = toFileUploadModel(f)
|
||||
}
|
||||
return r.db.WithContext(ctx).Create(&models).Error
|
||||
}
|
||||
|
||||
// 转换函数
|
||||
func toFileUploadModel(f *example.FileUpload) *model.ExaFileUploadAndDownload {
|
||||
return &model.ExaFileUploadAndDownload{
|
||||
ID: int64(f.ID),
|
||||
Name: f.Name,
|
||||
ClassID: int64(f.ClassId),
|
||||
URL: f.Url,
|
||||
Tag: f.Tag,
|
||||
Key: f.Key,
|
||||
}
|
||||
}
|
||||
|
||||
func toFileUploadBiz(m *model.ExaFileUploadAndDownload) *example.FileUpload {
|
||||
return &example.FileUpload{
|
||||
ID: uint(m.ID),
|
||||
Name: m.Name,
|
||||
ClassId: int(m.ClassID),
|
||||
Url: m.URL,
|
||||
Tag: m.Tag,
|
||||
Key: m.Key,
|
||||
CreatedAt: m.CreatedAt,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz/system"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type autoCodeRepo struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewAutoCodeRepo 创建自动代码仓储
|
||||
func NewAutoCodeRepo(db *gorm.DB) system.AutoCodeRepo {
|
||||
return &autoCodeRepo{db: db}
|
||||
}
|
||||
|
||||
// GetDB 获取所有数据库
|
||||
func (r *autoCodeRepo) GetDB(ctx context.Context) ([]system.Db, error) {
|
||||
var entities []system.Db
|
||||
sql := "SELECT SCHEMA_NAME AS `database` FROM INFORMATION_SCHEMA.SCHEMATA;"
|
||||
err := r.db.WithContext(ctx).Raw(sql).Scan(&entities).Error
|
||||
return entities, err
|
||||
}
|
||||
|
||||
// GetTables 获取指定数据库的所有表
|
||||
func (r *autoCodeRepo) GetTables(ctx context.Context, dbName string) ([]system.Table, error) {
|
||||
var entities []system.Table
|
||||
sql := `SELECT table_name AS table_name FROM information_schema.tables WHERE table_schema = ?`
|
||||
err := r.db.WithContext(ctx).Raw(sql, dbName).Scan(&entities).Error
|
||||
return entities, err
|
||||
}
|
||||
|
||||
// GetColumn 获取指定表的所有列
|
||||
func (r *autoCodeRepo) GetColumn(ctx context.Context, tableName, dbName string) ([]system.Column, error) {
|
||||
var entities []system.Column
|
||||
sql := `
|
||||
SELECT
|
||||
c.COLUMN_NAME column_name,
|
||||
c.DATA_TYPE data_type,
|
||||
CASE c.DATA_TYPE
|
||||
WHEN 'longtext' THEN c.CHARACTER_MAXIMUM_LENGTH
|
||||
WHEN 'varchar' THEN c.CHARACTER_MAXIMUM_LENGTH
|
||||
WHEN 'double' THEN CONCAT_WS(',', c.NUMERIC_PRECISION, c.NUMERIC_SCALE)
|
||||
WHEN 'decimal' THEN CONCAT_WS(',', c.NUMERIC_PRECISION, c.NUMERIC_SCALE)
|
||||
WHEN 'int' THEN c.NUMERIC_PRECISION
|
||||
WHEN 'bigint' THEN c.NUMERIC_PRECISION
|
||||
ELSE ''
|
||||
END AS data_type_long,
|
||||
c.COLUMN_COMMENT column_comment,
|
||||
CASE WHEN kcu.COLUMN_NAME IS NOT NULL THEN 1 ELSE 0 END AS primary_key,
|
||||
c.ORDINAL_POSITION
|
||||
FROM
|
||||
INFORMATION_SCHEMA.COLUMNS c
|
||||
LEFT JOIN
|
||||
INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
|
||||
ON
|
||||
c.TABLE_SCHEMA = kcu.TABLE_SCHEMA
|
||||
AND c.TABLE_NAME = kcu.TABLE_NAME
|
||||
AND c.COLUMN_NAME = kcu.COLUMN_NAME
|
||||
AND kcu.CONSTRAINT_NAME = 'PRIMARY'
|
||||
WHERE
|
||||
c.TABLE_NAME = ?
|
||||
AND c.TABLE_SCHEMA = ?
|
||||
ORDER BY
|
||||
c.ORDINAL_POSITION;`
|
||||
err := r.db.WithContext(ctx).Raw(sql, tableName, dbName).Scan(&entities).Error
|
||||
return entities, err
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz/system"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type autoCodeHistoryRepo struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewAutoCodeHistoryRepo 创建自动代码历史仓储
|
||||
func NewAutoCodeHistoryRepo(db *gorm.DB) system.AutoCodeHistoryRepo {
|
||||
return &autoCodeHistoryRepo{db: db}
|
||||
}
|
||||
|
||||
// First 根据id获取meta信息
|
||||
func (r *autoCodeHistoryRepo) First(ctx context.Context, id uint) (string, error) {
|
||||
var meta string
|
||||
err := r.db.WithContext(ctx).Model(&system.SysAutoCodeHistory{}).
|
||||
Where("id = ?", id).
|
||||
Pluck("request", &meta).Error
|
||||
return meta, err
|
||||
}
|
||||
|
||||
// Delete 删除历史记录
|
||||
func (r *autoCodeHistoryRepo) Delete(ctx context.Context, id uint) error {
|
||||
return r.db.WithContext(ctx).Where("id = ?", id).Delete(&system.SysAutoCodeHistory{}).Error
|
||||
}
|
||||
|
||||
// GetList 获取历史记录列表
|
||||
func (r *autoCodeHistoryRepo) GetList(ctx context.Context, page, pageSize int) ([]system.SysAutoCodeHistory, int64, error) {
|
||||
var list []system.SysAutoCodeHistory
|
||||
var total int64
|
||||
|
||||
db := r.db.WithContext(ctx).Model(&system.SysAutoCodeHistory{})
|
||||
err := db.Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
err = db.Offset(offset).Limit(pageSize).Order("updated_at desc").Find(&list).Error
|
||||
return list, total, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取历史记录
|
||||
func (r *autoCodeHistoryRepo) GetByID(ctx context.Context, id uint) (*system.SysAutoCodeHistory, error) {
|
||||
var history system.SysAutoCodeHistory
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&history).Error
|
||||
return &history, err
|
||||
}
|
||||
|
||||
// UpdateFlag 更新标记
|
||||
func (r *autoCodeHistoryRepo) UpdateFlag(ctx context.Context, id uint, flag int) error {
|
||||
return r.db.WithContext(ctx).Model(&system.SysAutoCodeHistory{}).
|
||||
Where("id = ?", id).
|
||||
Update("flag", flag).Error
|
||||
}
|
||||
|
||||
// DropTable 删除表
|
||||
func (r *autoCodeHistoryRepo) DropTable(ctx context.Context, businessDB, tableName string) error {
|
||||
// 注意:这里简化处理,实际应该支持多数据库
|
||||
return r.db.WithContext(ctx).Exec("DROP TABLE IF EXISTS " + tableName).Error
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"kra/internal/biz/system"
|
||||
"kra/internal/data/model"
|
||||
"kra/internal/data/query"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type errorRepo struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewErrorRepo 创建错误日志仓储
|
||||
func NewErrorRepo(db *gorm.DB) system.ErrorRepo {
|
||||
return &errorRepo{db: db}
|
||||
}
|
||||
|
||||
func (r *errorRepo) Create(ctx context.Context, sysError *system.SysError) error {
|
||||
m := toModelError(sysError)
|
||||
return query.SysError.WithContext(ctx).Create(m)
|
||||
}
|
||||
|
||||
func (r *errorRepo) Delete(ctx context.Context, id string) error {
|
||||
_, err := query.SysError.WithContext(ctx).Where(query.SysError.ID.Eq(parseID(id))).Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *errorRepo) DeleteByIds(ctx context.Context, ids []string) error {
|
||||
idList := make([]int64, len(ids))
|
||||
for i, id := range ids {
|
||||
idList[i] = parseID(id)
|
||||
}
|
||||
_, err := query.SysError.WithContext(ctx).Where(query.SysError.ID.In(idList...)).Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *errorRepo) Update(ctx context.Context, sysError *system.SysError) error {
|
||||
_, err := query.SysError.WithContext(ctx).Where(query.SysError.ID.Eq(sysError.ID)).Updates(map[string]any{
|
||||
"form": sysError.Form,
|
||||
"info": sysError.Info,
|
||||
"level": sysError.Level,
|
||||
"solution": sysError.Solution,
|
||||
"status": sysError.Status,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *errorRepo) GetById(ctx context.Context, id string) (*system.SysError, error) {
|
||||
m, err := query.SysError.WithContext(ctx).Where(query.SysError.ID.Eq(parseID(id))).First()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toBizError(m), nil
|
||||
}
|
||||
|
||||
func (r *errorRepo) GetList(ctx context.Context, req *system.ErrorSearchReq) ([]*system.SysError, int64, error) {
|
||||
q := query.SysError.WithContext(ctx).Order(query.SysError.CreatedAt.Desc())
|
||||
|
||||
// 条件搜索
|
||||
if len(req.CreatedAtRange) == 2 {
|
||||
q = q.Where(query.SysError.CreatedAt.Between(req.CreatedAtRange[0], req.CreatedAtRange[1]))
|
||||
}
|
||||
if req.Form != nil && *req.Form != "" {
|
||||
q = q.Where(query.SysError.Form.Eq(*req.Form))
|
||||
}
|
||||
if req.Info != nil && *req.Info != "" {
|
||||
q = q.Where(query.SysError.Info.Like("%" + *req.Info + "%"))
|
||||
}
|
||||
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if req.PageSize > 0 {
|
||||
offset := req.PageSize * (req.Page - 1)
|
||||
q = q.Limit(req.PageSize).Offset(offset)
|
||||
}
|
||||
|
||||
list, err := q.Find()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := make([]*system.SysError, len(list))
|
||||
for i, m := range list {
|
||||
result[i] = toBizError(m)
|
||||
}
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
func (r *errorRepo) UpdateStatus(ctx context.Context, id string, status string) error {
|
||||
_, err := query.SysError.WithContext(ctx).Where(query.SysError.ID.Eq(parseID(id))).Update(query.SysError.Status, status)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *errorRepo) UpdateSolution(ctx context.Context, id string, status string, solution string) error {
|
||||
_, err := query.SysError.WithContext(ctx).Where(query.SysError.ID.Eq(parseID(id))).Updates(map[string]any{
|
||||
"status": status,
|
||||
"solution": solution,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// 转换函数
|
||||
func parseID(id string) int64 {
|
||||
n, _ := strconv.ParseInt(id, 10, 64)
|
||||
return n
|
||||
}
|
||||
|
||||
func toModelError(e *system.SysError) *model.SysError {
|
||||
return &model.SysError{
|
||||
ID: e.ID,
|
||||
Form: e.Form,
|
||||
Info: e.Info,
|
||||
Level: e.Level,
|
||||
Solution: e.Solution,
|
||||
Status: e.Status,
|
||||
}
|
||||
}
|
||||
|
||||
func toBizError(m *model.SysError) *system.SysError {
|
||||
return &system.SysError{
|
||||
ID: m.ID,
|
||||
Form: m.Form,
|
||||
Info: m.Info,
|
||||
Level: m.Level,
|
||||
Solution: m.Solution,
|
||||
Status: m.Status,
|
||||
CreatedAt: m.CreatedAt,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,283 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz/system"
|
||||
"kra/internal/data/model"
|
||||
"kra/internal/data/query"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type exportTemplateRepo struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewExportTemplateRepo 创建导出模板仓储
|
||||
func NewExportTemplateRepo(db *gorm.DB) system.ExportTemplateRepo {
|
||||
return &exportTemplateRepo{db: db}
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) Create(ctx context.Context, template *system.ExportTemplate) error {
|
||||
m := toModelExportTemplate(template)
|
||||
if err := r.db.WithContext(ctx).Create(m).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
template.ID = uint(m.ID)
|
||||
|
||||
// 创建条件
|
||||
if len(template.Conditions) > 0 {
|
||||
for _, c := range template.Conditions {
|
||||
c.TemplateID = template.TemplateID
|
||||
}
|
||||
if err := r.CreateConditions(ctx, template.Conditions); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 创建关联
|
||||
if len(template.JoinTemplate) > 0 {
|
||||
for _, j := range template.JoinTemplate {
|
||||
j.TemplateID = template.TemplateID
|
||||
}
|
||||
if err := r.CreateJoins(ctx, template.JoinTemplate); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) Update(ctx context.Context, template *system.ExportTemplate) error {
|
||||
m := toModelExportTemplate(template)
|
||||
return r.db.WithContext(ctx).Model(&model.SysExportTemplate{}).Where("id = ?", template.ID).Updates(m).Error
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) Delete(ctx context.Context, id uint) error {
|
||||
return r.db.WithContext(ctx).Delete(&model.SysExportTemplate{}, id).Error
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) FindByID(ctx context.Context, id uint) (*system.ExportTemplate, error) {
|
||||
var m model.SysExportTemplate
|
||||
if err := r.db.WithContext(ctx).First(&m, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 加载条件
|
||||
var conditions []model.SysExportTemplateCondition
|
||||
r.db.WithContext(ctx).Where("template_id = ?", m.TemplateID).Find(&conditions)
|
||||
|
||||
// 加载关联
|
||||
var joins []model.SysExportTemplateJoin
|
||||
r.db.WithContext(ctx).Where("template_id = ?", m.TemplateID).Find(&joins)
|
||||
|
||||
return toBizExportTemplate(&m, conditions, joins), nil
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) FindByTemplateID(ctx context.Context, templateID string) (*system.ExportTemplate, error) {
|
||||
var m model.SysExportTemplate
|
||||
if err := r.db.WithContext(ctx).Where("template_id = ?", templateID).First(&m).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 加载条件
|
||||
var conditions []model.SysExportTemplateCondition
|
||||
r.db.WithContext(ctx).Where("template_id = ?", templateID).Find(&conditions)
|
||||
|
||||
// 加载关联
|
||||
var joins []model.SysExportTemplateJoin
|
||||
r.db.WithContext(ctx).Where("template_id = ?", templateID).Find(&joins)
|
||||
|
||||
return toBizExportTemplate(&m, conditions, joins), nil
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) GetList(ctx context.Context, req *system.ExportTemplateSearchReq) ([]*system.ExportTemplate, int64, error) {
|
||||
q := query.SysExportTemplate
|
||||
do := q.WithContext(ctx)
|
||||
|
||||
if req.Name != "" {
|
||||
do = do.Where(q.Name.Like("%" + req.Name + "%"))
|
||||
}
|
||||
if req.TableName != "" {
|
||||
do = do.Where(q.TblName.Eq(req.TableName))
|
||||
}
|
||||
if req.TemplateID != "" {
|
||||
do = do.Where(q.TemplateID.Eq(req.TemplateID))
|
||||
}
|
||||
if req.StartCreatedAt != nil && req.EndCreatedAt != nil {
|
||||
do = do.Where(q.CreatedAt.Between(*req.StartCreatedAt, *req.EndCreatedAt))
|
||||
}
|
||||
|
||||
total, err := do.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if req.PageSize > 0 {
|
||||
do = do.Limit(req.PageSize).Offset((req.Page - 1) * req.PageSize)
|
||||
}
|
||||
|
||||
list, err := do.Find()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := make([]*system.ExportTemplate, len(list))
|
||||
for i, m := range list {
|
||||
result[i] = toBizExportTemplateSimple(m)
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) DeleteConditionsByTemplateID(ctx context.Context, templateID string) error {
|
||||
return r.db.WithContext(ctx).Where("template_id = ?", templateID).Delete(&model.SysExportTemplateCondition{}).Error
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) DeleteJoinsByTemplateID(ctx context.Context, templateID string) error {
|
||||
return r.db.WithContext(ctx).Where("template_id = ?", templateID).Delete(&model.SysExportTemplateJoin{}).Error
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) CreateConditions(ctx context.Context, conditions []*system.Condition) error {
|
||||
if len(conditions) == 0 {
|
||||
return nil
|
||||
}
|
||||
models := make([]*model.SysExportTemplateCondition, len(conditions))
|
||||
for i, c := range conditions {
|
||||
models[i] = &model.SysExportTemplateCondition{
|
||||
TemplateID: c.TemplateID,
|
||||
From: c.From,
|
||||
Column: c.Column,
|
||||
Operator: c.Operator,
|
||||
}
|
||||
}
|
||||
return r.db.WithContext(ctx).Create(&models).Error
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) CreateJoins(ctx context.Context, joins []*system.JoinTemplate) error {
|
||||
if len(joins) == 0 {
|
||||
return nil
|
||||
}
|
||||
models := make([]*model.SysExportTemplateJoin, len(joins))
|
||||
for i, j := range joins {
|
||||
models[i] = &model.SysExportTemplateJoin{
|
||||
TemplateID: j.TemplateID,
|
||||
Joins: j.Joins,
|
||||
TblName: j.Table,
|
||||
On: j.On,
|
||||
}
|
||||
}
|
||||
return r.db.WithContext(ctx).Create(&models).Error
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) GetDB(dbName string) interface{} {
|
||||
// 简化实现:返回默认数据库
|
||||
return r.db
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) ExecuteQuery(ctx context.Context, dbName, sql string, args ...interface{}) ([]map[string]interface{}, error) {
|
||||
var result []map[string]interface{}
|
||||
if err := r.db.WithContext(ctx).Raw(sql, args...).Scan(&result).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) GetColumnTypes(ctx context.Context, dbName, tableName string) ([]string, error) {
|
||||
columns, err := r.db.Migrator().ColumnTypes(tableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]string, len(columns))
|
||||
for i, col := range columns {
|
||||
result[i] = col.Name()
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) HasDeletedAtColumn(ctx context.Context, tableName string) bool {
|
||||
var count int64
|
||||
r.db.Raw("SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND COLUMN_NAME = 'deleted_at'", tableName).Count(&count)
|
||||
return count > 0
|
||||
}
|
||||
|
||||
func (r *exportTemplateRepo) ImportData(ctx context.Context, dbName, tableName string, items []map[string]interface{}) error {
|
||||
return r.db.WithContext(ctx).Table(tableName).CreateInBatches(&items, 1000).Error
|
||||
}
|
||||
|
||||
// 转换函数
|
||||
func toModelExportTemplate(t *system.ExportTemplate) *model.SysExportTemplate {
|
||||
var limit int64
|
||||
if t.Limit != nil {
|
||||
limit = int64(*t.Limit)
|
||||
}
|
||||
return &model.SysExportTemplate{
|
||||
ID: int64(t.ID),
|
||||
DbName: t.DBName,
|
||||
Name: t.Name,
|
||||
TblName: t.TableName,
|
||||
TemplateID: t.TemplateID,
|
||||
TemplateInfo: t.TemplateInfo,
|
||||
Limit: limit,
|
||||
Order: t.Order,
|
||||
}
|
||||
}
|
||||
|
||||
func toBizExportTemplate(m *model.SysExportTemplate, conditions []model.SysExportTemplateCondition, joins []model.SysExportTemplateJoin) *system.ExportTemplate {
|
||||
limit := int(m.Limit)
|
||||
t := &system.ExportTemplate{
|
||||
ID: uint(m.ID),
|
||||
DBName: m.DbName,
|
||||
Name: m.Name,
|
||||
TableName: m.TblName,
|
||||
TemplateID: m.TemplateID,
|
||||
TemplateInfo: m.TemplateInfo,
|
||||
Limit: &limit,
|
||||
Order: m.Order,
|
||||
CreatedAt: m.CreatedAt,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
|
||||
// 转换条件
|
||||
t.Conditions = make([]*system.Condition, len(conditions))
|
||||
for i, c := range conditions {
|
||||
t.Conditions[i] = &system.Condition{
|
||||
ID: uint(c.ID),
|
||||
TemplateID: c.TemplateID,
|
||||
From: c.From,
|
||||
Column: c.Column,
|
||||
Operator: c.Operator,
|
||||
}
|
||||
}
|
||||
|
||||
// 转换关联
|
||||
t.JoinTemplate = make([]*system.JoinTemplate, len(joins))
|
||||
for i, j := range joins {
|
||||
t.JoinTemplate[i] = &system.JoinTemplate{
|
||||
ID: uint(j.ID),
|
||||
TemplateID: j.TemplateID,
|
||||
Joins: j.Joins,
|
||||
Table: j.TblName,
|
||||
On: j.On,
|
||||
}
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func toBizExportTemplateSimple(m *model.SysExportTemplate) *system.ExportTemplate {
|
||||
limit := int(m.Limit)
|
||||
return &system.ExportTemplate{
|
||||
ID: uint(m.ID),
|
||||
DBName: m.DbName,
|
||||
Name: m.Name,
|
||||
TableName: m.TblName,
|
||||
TemplateID: m.TemplateID,
|
||||
TemplateInfo: m.TemplateInfo,
|
||||
Limit: &limit,
|
||||
Order: m.Order,
|
||||
CreatedAt: m.CreatedAt,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"kra/internal/biz/system"
|
||||
"kra/internal/data/model"
|
||||
"kra/internal/data/query"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type versionRepo struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewVersionRepo 创建版本仓储
|
||||
func NewVersionRepo(db *gorm.DB) system.VersionRepo {
|
||||
return &versionRepo{db: db}
|
||||
}
|
||||
|
||||
func (r *versionRepo) Create(ctx context.Context, version *system.SysVersion) error {
|
||||
m := &model.SysVersion{
|
||||
VersionName: version.VersionName,
|
||||
VersionCode: version.VersionCode,
|
||||
Description: version.Description,
|
||||
VersionData: version.VersionData,
|
||||
}
|
||||
return query.SysVersion.WithContext(ctx).Create(m)
|
||||
}
|
||||
|
||||
func (r *versionRepo) Delete(ctx context.Context, id string) error {
|
||||
idInt, _ := strconv.ParseInt(id, 10, 64)
|
||||
_, err := query.SysVersion.WithContext(ctx).Where(query.SysVersion.ID.Eq(idInt)).Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *versionRepo) DeleteByIds(ctx context.Context, ids []string) error {
|
||||
idList := make([]int64, len(ids))
|
||||
for i, id := range ids {
|
||||
idList[i], _ = strconv.ParseInt(id, 10, 64)
|
||||
}
|
||||
_, err := query.SysVersion.WithContext(ctx).Where(query.SysVersion.ID.In(idList...)).Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *versionRepo) GetById(ctx context.Context, id string) (*system.SysVersion, error) {
|
||||
idInt, _ := strconv.ParseInt(id, 10, 64)
|
||||
m, err := query.SysVersion.WithContext(ctx).Where(query.SysVersion.ID.Eq(idInt)).First()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toBizVersion(m), nil
|
||||
}
|
||||
|
||||
func (r *versionRepo) GetList(ctx context.Context, req *system.VersionSearchReq) ([]*system.SysVersion, int64, error) {
|
||||
q := query.SysVersion.WithContext(ctx).Order(query.SysVersion.CreatedAt.Desc())
|
||||
|
||||
// 条件搜索
|
||||
if len(req.CreatedAtRange) == 2 {
|
||||
q = q.Where(query.SysVersion.CreatedAt.Between(req.CreatedAtRange[0], req.CreatedAtRange[1]))
|
||||
}
|
||||
if req.VersionName != nil && *req.VersionName != "" {
|
||||
q = q.Where(query.SysVersion.VersionName.Like("%" + *req.VersionName + "%"))
|
||||
}
|
||||
if req.VersionCode != nil && *req.VersionCode != "" {
|
||||
q = q.Where(query.SysVersion.VersionCode.Eq(*req.VersionCode))
|
||||
}
|
||||
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if req.PageSize > 0 {
|
||||
offset := req.PageSize * (req.Page - 1)
|
||||
q = q.Limit(req.PageSize).Offset(offset)
|
||||
}
|
||||
|
||||
list, err := q.Find()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := make([]*system.SysVersion, len(list))
|
||||
for i, m := range list {
|
||||
result[i] = toBizVersion(m)
|
||||
}
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
func toBizVersion(m *model.SysVersion) *system.SysVersion {
|
||||
return &system.SysVersion{
|
||||
ID: m.ID,
|
||||
VersionName: m.VersionName,
|
||||
VersionCode: m.VersionCode,
|
||||
Description: m.Description,
|
||||
VersionData: m.VersionData,
|
||||
CreatedAt: m.CreatedAt,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
|
@ -3,8 +3,10 @@ package server
|
|||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz/example"
|
||||
"kra/internal/biz/system"
|
||||
"kra/internal/conf"
|
||||
examplehandler "kra/internal/server/handler/example"
|
||||
handler "kra/internal/server/handler/system"
|
||||
"kra/internal/server/middleware"
|
||||
"kra/internal/server/router"
|
||||
|
|
@ -33,6 +35,16 @@ func NewGinRouter(
|
|||
casbinUsecase *system.CasbinUsecase,
|
||||
operationRecordUsecase *system.OperationRecordUsecase,
|
||||
paramsUsecase *system.ParamsUsecase,
|
||||
errorUsecase *system.ErrorUsecase,
|
||||
versionUsecase *system.VersionUsecase,
|
||||
systemUsecase *system.SystemUsecase,
|
||||
exportTemplateUsecase *system.ExportTemplateUsecase,
|
||||
autoCodeUsecase *system.AutoCodeUsecase,
|
||||
autoCodeHistoryUsecase *system.AutoCodeHistoryUsecase,
|
||||
// Example usecases
|
||||
fileUploadUsecase *example.FileUploadUsecase,
|
||||
customerUsecase *example.CustomerUsecase,
|
||||
attachmentCategoryUsecase *example.AttachmentCategoryUsecase,
|
||||
) *gin.Engine {
|
||||
gin.SetMode(gin.DebugMode)
|
||||
|
||||
|
|
@ -61,7 +73,7 @@ func NewGinRouter(
|
|||
RouterPrefix: "",
|
||||
})
|
||||
|
||||
// 初始化handler依赖
|
||||
// 初始化system handler依赖
|
||||
handler.InitUsecases(
|
||||
userUsecase,
|
||||
apiUsecase,
|
||||
|
|
@ -73,15 +85,28 @@ func NewGinRouter(
|
|||
jwtBlacklistUsecase,
|
||||
operationRecordUsecase,
|
||||
paramsUsecase,
|
||||
errorUsecase,
|
||||
versionUsecase,
|
||||
systemUsecase,
|
||||
exportTemplateUsecase,
|
||||
autoCodeUsecase,
|
||||
autoCodeHistoryUsecase,
|
||||
)
|
||||
handler.SetJWTInstance(jwtPkg)
|
||||
|
||||
// 初始化example handler依赖
|
||||
examplehandler.InitUsecases(
|
||||
fileUploadUsecase,
|
||||
customerUsecase,
|
||||
attachmentCategoryUsecase,
|
||||
)
|
||||
|
||||
// 创建路由组
|
||||
publicGroup := engine.Group("")
|
||||
privateGroup := engine.Group("")
|
||||
privateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
|
||||
|
||||
// 注册路由
|
||||
// 注册System路由
|
||||
systemRouter := router.RouterGroupApp.System
|
||||
systemRouter.InitBaseRouter(publicGroup)
|
||||
systemRouter.InitUserRouter(privateGroup)
|
||||
|
|
@ -89,10 +114,24 @@ func NewGinRouter(
|
|||
systemRouter.InitAuthorityRouter(privateGroup)
|
||||
systemRouter.InitMenuRouter(privateGroup)
|
||||
systemRouter.InitDictionaryRouter(privateGroup)
|
||||
systemRouter.InitSysDictionaryDetailRouter(privateGroup)
|
||||
systemRouter.InitCasbinRouter(privateGroup)
|
||||
systemRouter.InitJwtRouter(privateGroup)
|
||||
systemRouter.InitOperationRecordRouter(privateGroup)
|
||||
systemRouter.InitParamsRouter(privateGroup)
|
||||
systemRouter.InitSysErrorRouter(privateGroup, publicGroup)
|
||||
systemRouter.InitSysVersionRouter(privateGroup, publicGroup)
|
||||
systemRouter.InitSystemRouter(privateGroup)
|
||||
systemRouter.InitSysExportTemplateRouter(privateGroup, publicGroup)
|
||||
systemRouter.InitInitRouter(publicGroup)
|
||||
systemRouter.InitAutoCodeRouter(privateGroup, publicGroup)
|
||||
systemRouter.InitAutoCodeHistoryRouter(privateGroup)
|
||||
|
||||
// 注册Example路由
|
||||
exampleRouter := router.RouterGroupApp.Example
|
||||
exampleRouter.InitFileUploadRouter(privateGroup)
|
||||
exampleRouter.InitCustomerRouter(privateGroup)
|
||||
exampleRouter.InitAttachmentCategoryRouter(privateGroup)
|
||||
|
||||
return engine
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package example
|
||||
|
||||
import "kra/internal/biz/example"
|
||||
|
||||
// ApiGroup Example API组
|
||||
type ApiGroup struct {
|
||||
FileUploadApi
|
||||
CustomerApi
|
||||
AttachmentCategoryApi
|
||||
}
|
||||
|
||||
// 业务层依赖
|
||||
var (
|
||||
fileUploadUsecase *example.FileUploadUsecase
|
||||
customerUsecase *example.CustomerUsecase
|
||||
attachmentCategoryUsecase *example.AttachmentCategoryUsecase
|
||||
)
|
||||
|
||||
// InitUsecases 初始化业务层依赖
|
||||
func InitUsecases(
|
||||
fileUpload *example.FileUploadUsecase,
|
||||
customer *example.CustomerUsecase,
|
||||
attachmentCategory *example.AttachmentCategoryUsecase,
|
||||
) {
|
||||
fileUploadUsecase = fileUpload
|
||||
customerUsecase = customer
|
||||
attachmentCategoryUsecase = attachmentCategory
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
"kra/internal/biz/example"
|
||||
"kra/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AttachmentCategoryApi struct{}
|
||||
|
||||
// AddCategory 创建/更新分类
|
||||
// @Summary 创建/更新分类
|
||||
// @Tags ExaAttachmentCategory
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body CategoryRequest true "分类信息"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /attachmentCategory/addCategory [post]
|
||||
func (api *AttachmentCategoryApi) AddCategory(c *gin.Context) {
|
||||
var req CategoryRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage("参数错误", c)
|
||||
return
|
||||
}
|
||||
|
||||
category := &example.AttachmentCategory{
|
||||
ID: req.ID,
|
||||
Name: req.Name,
|
||||
Pid: req.Pid,
|
||||
}
|
||||
|
||||
if err := attachmentCategoryUsecase.AddCategory(c.Request.Context(), category); err != nil {
|
||||
response.FailWithMessage("创建/更新失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("创建/更新成功", c)
|
||||
}
|
||||
|
||||
// DeleteCategory 删除分类
|
||||
// @Summary 删除分类
|
||||
// @Tags ExaAttachmentCategory
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body DeleteCategoryRequest true "分类ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /attachmentCategory/deleteCategory [post]
|
||||
func (api *AttachmentCategoryApi) DeleteCategory(c *gin.Context) {
|
||||
var req DeleteCategoryRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage("参数错误", c)
|
||||
return
|
||||
}
|
||||
|
||||
if req.ID == 0 {
|
||||
response.FailWithMessage("参数错误", c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := attachmentCategoryUsecase.DeleteCategory(c.Request.Context(), req.ID); err != nil {
|
||||
response.FailWithMessage("删除失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// GetCategoryList 获取分类列表
|
||||
// @Summary 获取分类列表
|
||||
// @Tags ExaAttachmentCategory
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} response.Response{data=[]CategoryResponse}
|
||||
// @Router /attachmentCategory/getCategoryList [get]
|
||||
func (api *AttachmentCategoryApi) GetCategoryList(c *gin.Context) {
|
||||
list, err := attachmentCategoryUsecase.GetCategoryList(c.Request.Context())
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取分类列表失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
respList := toCategoryResponseList(list)
|
||||
response.OkWithData(respList, c)
|
||||
}
|
||||
|
||||
// Request/Response 结构
|
||||
type CategoryRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
Pid uint `json:"pid"`
|
||||
}
|
||||
|
||||
type DeleteCategoryRequest struct {
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
|
||||
type CategoryResponse struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
Pid uint `json:"pid"`
|
||||
Children []CategoryResponse `json:"children"`
|
||||
}
|
||||
|
||||
func toCategoryResponseList(categories []*example.AttachmentCategory) []CategoryResponse {
|
||||
result := make([]CategoryResponse, len(categories))
|
||||
for i, cat := range categories {
|
||||
result[i] = CategoryResponse{
|
||||
ID: cat.ID,
|
||||
Name: cat.Name,
|
||||
Pid: cat.Pid,
|
||||
Children: toCategoryResponseList(cat.Children),
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
"kra/internal/biz/example"
|
||||
"kra/pkg/response"
|
||||
"kra/pkg/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type CustomerApi struct{}
|
||||
|
||||
// CreateExaCustomer 创建客户
|
||||
// @Summary 创建客户
|
||||
// @Tags ExaCustomer
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body CustomerRequest true "客户信息"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /customer/customer [post]
|
||||
func (api *CustomerApi) CreateExaCustomer(c *gin.Context) {
|
||||
var req CustomerRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
customer := &example.Customer{
|
||||
CustomerName: req.CustomerName,
|
||||
CustomerPhoneData: req.CustomerPhoneData,
|
||||
SysUserID: utils.GetUserID(c),
|
||||
SysUserAuthorityID: utils.GetUserAuthorityId(c),
|
||||
}
|
||||
|
||||
if err := customerUsecase.CreateExaCustomer(c.Request.Context(), customer); err != nil {
|
||||
response.FailWithMessage("创建失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("创建成功", c)
|
||||
}
|
||||
|
||||
// DeleteExaCustomer 删除客户
|
||||
// @Summary 删除客户
|
||||
// @Tags ExaCustomer
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body DeleteCustomerRequest true "客户ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /customer/customer [delete]
|
||||
func (api *CustomerApi) DeleteExaCustomer(c *gin.Context) {
|
||||
var req DeleteCustomerRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := customerUsecase.DeleteExaCustomer(c.Request.Context(), req.ID); err != nil {
|
||||
response.FailWithMessage("删除失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// UpdateExaCustomer 更新客户
|
||||
// @Summary 更新客户
|
||||
// @Tags ExaCustomer
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body CustomerRequest true "客户信息"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /customer/customer [put]
|
||||
func (api *CustomerApi) UpdateExaCustomer(c *gin.Context) {
|
||||
var req CustomerRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
customer := &example.Customer{
|
||||
ID: req.ID,
|
||||
CustomerName: req.CustomerName,
|
||||
CustomerPhoneData: req.CustomerPhoneData,
|
||||
}
|
||||
|
||||
if err := customerUsecase.UpdateExaCustomer(c.Request.Context(), customer); err != nil {
|
||||
response.FailWithMessage("更新失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("更新成功", c)
|
||||
}
|
||||
|
||||
// GetExaCustomer 获取客户信息
|
||||
// @Summary 获取客户信息
|
||||
// @Tags ExaCustomer
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body GetCustomerRequest true "客户ID"
|
||||
// @Success 200 {object} response.Response{data=CustomerResponse}
|
||||
// @Router /customer/customer [get]
|
||||
func (api *CustomerApi) GetExaCustomer(c *gin.Context) {
|
||||
var req GetCustomerRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
customer, err := customerUsecase.GetExaCustomer(c.Request.Context(), req.ID)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithDetailed(toCustomerResponse(customer), "获取成功", c)
|
||||
}
|
||||
|
||||
// GetExaCustomerList 分页获取客户列表
|
||||
// @Summary 分页获取客户列表
|
||||
// @Tags ExaCustomer
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body GetCustomerListRequest true "分页参数"
|
||||
// @Success 200 {object} response.Response{data=response.PageResult}
|
||||
// @Router /customer/customerList [get]
|
||||
func (api *CustomerApi) GetExaCustomerList(c *gin.Context) {
|
||||
var req GetCustomerListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
authorityId := utils.GetUserAuthorityId(c)
|
||||
list, total, err := customerUsecase.GetCustomerInfoList(c.Request.Context(), authorityId, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
respList := make([]CustomerResponse, len(list))
|
||||
for i, cust := range list {
|
||||
respList[i] = *toCustomerResponse(cust)
|
||||
}
|
||||
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: respList,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
||||
// Request/Response 结构
|
||||
type CustomerRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
CustomerName string `json:"customerName"`
|
||||
CustomerPhoneData string `json:"customerPhoneData"`
|
||||
}
|
||||
|
||||
type DeleteCustomerRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
|
||||
type GetCustomerRequest struct {
|
||||
ID uint `form:"ID"`
|
||||
}
|
||||
|
||||
type GetCustomerListRequest struct {
|
||||
Page int `form:"page"`
|
||||
PageSize int `form:"pageSize"`
|
||||
}
|
||||
|
||||
type CustomerResponse struct {
|
||||
ID uint `json:"ID"`
|
||||
CustomerName string `json:"customerName"`
|
||||
CustomerPhoneData string `json:"customerPhoneData"`
|
||||
SysUserID uint `json:"sysUserId"`
|
||||
SysUserAuthorityID uint `json:"sysUserAuthorityID"`
|
||||
SysUserName string `json:"sysUserName"`
|
||||
}
|
||||
|
||||
func toCustomerResponse(c *example.Customer) *CustomerResponse {
|
||||
return &CustomerResponse{
|
||||
ID: c.ID,
|
||||
CustomerName: c.CustomerName,
|
||||
CustomerPhoneData: c.CustomerPhoneData,
|
||||
SysUserID: c.SysUserID,
|
||||
SysUserAuthorityID: c.SysUserAuthorityID,
|
||||
SysUserName: c.SysUserName,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/biz/example"
|
||||
"kra/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type FileUploadApi struct{}
|
||||
|
||||
// UploadFile 上传文件
|
||||
// @Summary 上传文件
|
||||
// @Tags ExaFileUploadAndDownload
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param file formance file true "上传文件"
|
||||
// @Success 200 {object} response.Response{data=FileUploadResponse}
|
||||
// @Router /fileUploadAndDownload/upload [post]
|
||||
func (api *FileUploadApi) UploadFile(c *gin.Context) {
|
||||
noSave := c.DefaultQuery("noSave", "0")
|
||||
classIdStr := c.DefaultQuery("classId", "0")
|
||||
classId, _ := strconv.Atoi(classIdStr)
|
||||
|
||||
_, header, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
response.FailWithMessage("接收文件失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
file, err := fileUploadUsecase.UploadFile(c.Request.Context(), header, noSave, classId)
|
||||
if err != nil {
|
||||
response.FailWithMessage("上传失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithDetailed(toFileUploadResponse(file), "上传成功", c)
|
||||
}
|
||||
|
||||
// DeleteFile 删除文件
|
||||
// @Summary 删除文件
|
||||
// @Tags ExaFileUploadAndDownload
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body DeleteFileRequest true "文件ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /fileUploadAndDownload/deleteFile [post]
|
||||
func (api *FileUploadApi) DeleteFile(c *gin.Context) {
|
||||
var req DeleteFileRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := fileUploadUsecase.DeleteFile(c.Request.Context(), req.ID); err != nil {
|
||||
response.FailWithMessage("删除失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// EditFileName 编辑文件名
|
||||
// @Summary 编辑文件名
|
||||
// @Tags ExaFileUploadAndDownload
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body EditFileNameRequest true "文件信息"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /fileUploadAndDownload/editFileName [post]
|
||||
func (api *FileUploadApi) EditFileName(c *gin.Context) {
|
||||
var req EditFileNameRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := fileUploadUsecase.EditFileName(c.Request.Context(), req.ID, req.Name); err != nil {
|
||||
response.FailWithMessage("编辑失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("编辑成功", c)
|
||||
}
|
||||
|
||||
// GetFileList 分页获取文件列表
|
||||
// @Summary 分页获取文件列表
|
||||
// @Tags ExaFileUploadAndDownload
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body GetFileListRequest true "分页参数"
|
||||
// @Success 200 {object} response.Response{data=response.PageResult}
|
||||
// @Router /fileUploadAndDownload/getFileList [post]
|
||||
func (api *FileUploadApi) GetFileList(c *gin.Context) {
|
||||
var req GetFileListRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
searchReq := &example.FileUploadSearchReq{
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
Keyword: req.Keyword,
|
||||
ClassId: req.ClassId,
|
||||
}
|
||||
|
||||
list, total, err := fileUploadUsecase.GetFileRecordInfoList(c.Request.Context(), searchReq)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
respList := make([]FileUploadResponse, len(list))
|
||||
for i, f := range list {
|
||||
respList[i] = *toFileUploadResponse(f)
|
||||
}
|
||||
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: respList,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
||||
// ImportURL 导入URL
|
||||
// @Summary 导入URL
|
||||
// @Tags ExaFileUploadAndDownload
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body []FileUploadResponse true "文件列表"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /fileUploadAndDownload/importURL [post]
|
||||
func (api *FileUploadApi) ImportURL(c *gin.Context) {
|
||||
var req []FileUploadResponse
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
files := make([]*example.FileUpload, len(req))
|
||||
for i, r := range req {
|
||||
files[i] = &example.FileUpload{
|
||||
Name: r.Name,
|
||||
ClassId: r.ClassId,
|
||||
Url: r.Url,
|
||||
Tag: r.Tag,
|
||||
Key: r.Key,
|
||||
}
|
||||
}
|
||||
|
||||
if err := fileUploadUsecase.ImportURL(c.Request.Context(), files); err != nil {
|
||||
response.FailWithMessage("导入失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("导入成功", c)
|
||||
}
|
||||
|
||||
// Request/Response 结构
|
||||
type DeleteFileRequest struct {
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
|
||||
type EditFileNameRequest struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type GetFileListRequest struct {
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Keyword string `json:"keyword"`
|
||||
ClassId int `json:"classId"`
|
||||
}
|
||||
|
||||
type FileUploadResponse struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
ClassId int `json:"classId"`
|
||||
Url string `json:"url"`
|
||||
Tag string `json:"tag"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
func toFileUploadResponse(f *example.FileUpload) *FileUploadResponse {
|
||||
return &FileUploadResponse{
|
||||
ID: f.ID,
|
||||
Name: f.Name,
|
||||
ClassId: f.ClassId,
|
||||
Url: f.Url,
|
||||
Tag: f.Tag,
|
||||
Key: f.Key,
|
||||
}
|
||||
}
|
||||
|
|
@ -10,10 +10,18 @@ type ApiGroup struct {
|
|||
AuthorityApi
|
||||
MenuApi
|
||||
DictionaryApi
|
||||
DictionaryDetailApi
|
||||
CasbinApi
|
||||
JwtApi
|
||||
OperationRecordApi
|
||||
ParamsApi
|
||||
ErrorApi
|
||||
VersionApi
|
||||
SystemApi
|
||||
ExportTemplateApi
|
||||
DBApi
|
||||
AutoCodeApi
|
||||
AutoCodeHistoryApi
|
||||
}
|
||||
|
||||
// 业务层依赖
|
||||
|
|
@ -28,6 +36,12 @@ var (
|
|||
jwtBlacklistUsecase *system.JwtBlacklistUsecase
|
||||
operationRecordUsecase *system.OperationRecordUsecase
|
||||
paramsUsecase *system.ParamsUsecase
|
||||
errorUsecase *system.ErrorUsecase
|
||||
versionUsecase *system.VersionUsecase
|
||||
systemUsecase *system.SystemUsecase
|
||||
exportTemplateUsecase *system.ExportTemplateUsecase
|
||||
autoCodeUsecase *system.AutoCodeUsecase
|
||||
autoCodeHistoryUsecase *system.AutoCodeHistoryUsecase
|
||||
)
|
||||
|
||||
// InitUsecases 初始化业务层依赖
|
||||
|
|
@ -42,6 +56,12 @@ func InitUsecases(
|
|||
jwtBlacklist *system.JwtBlacklistUsecase,
|
||||
operationRecord *system.OperationRecordUsecase,
|
||||
params *system.ParamsUsecase,
|
||||
sysError *system.ErrorUsecase,
|
||||
version *system.VersionUsecase,
|
||||
sysSystem *system.SystemUsecase,
|
||||
exportTemplate *system.ExportTemplateUsecase,
|
||||
autoCode *system.AutoCodeUsecase,
|
||||
autoCodeHistory *system.AutoCodeHistoryUsecase,
|
||||
) {
|
||||
userUsecase = user
|
||||
apiUsecase = api
|
||||
|
|
@ -53,4 +73,10 @@ func InitUsecases(
|
|||
jwtBlacklistUsecase = jwtBlacklist
|
||||
operationRecordUsecase = operationRecord
|
||||
paramsUsecase = params
|
||||
errorUsecase = sysError
|
||||
versionUsecase = version
|
||||
systemUsecase = sysSystem
|
||||
exportTemplateUsecase = exportTemplate
|
||||
autoCodeUsecase = autoCode
|
||||
autoCodeHistoryUsecase = autoCodeHistory
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"kra/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AutoCodeApi struct{}
|
||||
|
||||
// GetDB 获取当前所有数据库
|
||||
// @Summary 获取当前所有数据库
|
||||
// @Tags AutoCode
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} response.Response{data=map[string]interface{}}
|
||||
// @Router /autoCode/getDB [get]
|
||||
func (api *AutoCodeApi) GetDB(c *gin.Context) {
|
||||
dbs, err := autoCodeUsecase.GetDB(c.Request.Context())
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(gin.H{"dbs": dbs}, "获取成功", c)
|
||||
}
|
||||
|
||||
// GetTables 获取当前数据库所有表
|
||||
// @Summary 获取当前数据库所有表
|
||||
// @Tags AutoCode
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param dbName query string false "数据库名"
|
||||
// @Success 200 {object} response.Response{data=map[string]interface{}}
|
||||
// @Router /autoCode/getTables [get]
|
||||
func (api *AutoCodeApi) GetTables(c *gin.Context) {
|
||||
dbName := c.Query("dbName")
|
||||
if dbName == "" {
|
||||
response.FailWithMessage("数据库名不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
tables, err := autoCodeUsecase.GetTables(c.Request.Context(), dbName)
|
||||
if err != nil {
|
||||
response.FailWithMessage("查询table失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(gin.H{"tables": tables}, "获取成功", c)
|
||||
}
|
||||
|
||||
// GetColumn 获取当前表所有字段
|
||||
// @Summary 获取当前表所有字段
|
||||
// @Tags AutoCode
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param dbName query string false "数据库名"
|
||||
// @Param tableName query string true "表名"
|
||||
// @Success 200 {object} response.Response{data=map[string]interface{}}
|
||||
// @Router /autoCode/getColumn [get]
|
||||
func (api *AutoCodeApi) GetColumn(c *gin.Context) {
|
||||
dbName := c.Query("dbName")
|
||||
tableName := c.Query("tableName")
|
||||
if tableName == "" {
|
||||
response.FailWithMessage("表名不能为空", c)
|
||||
return
|
||||
}
|
||||
if dbName == "" {
|
||||
response.FailWithMessage("数据库名不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
columns, err := autoCodeUsecase.GetColumn(c.Request.Context(), tableName, dbName)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(gin.H{"columns": columns}, "获取成功", c)
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"kra/internal/biz/system"
|
||||
"kra/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AutoCodeHistoryApi struct{}
|
||||
|
||||
// GetByIdReq 获取请求
|
||||
type GetByIdReq struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
}
|
||||
|
||||
// First 获取meta信息
|
||||
// @Summary 获取meta信息
|
||||
// @Tags AutoCode
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body GetByIdReq true "请求参数"
|
||||
// @Success 200 {object} response.Response{data=map[string]interface{}}
|
||||
// @Router /autoCode/getMeta [post]
|
||||
func (api *AutoCodeHistoryApi) First(c *gin.Context) {
|
||||
var req GetByIdReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
data, err := autoCodeHistoryUsecase.First(c.Request.Context(), req.ID)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(gin.H{"meta": data}, "获取成功", c)
|
||||
}
|
||||
|
||||
// Delete 删除回滚记录
|
||||
// @Summary 删除回滚记录
|
||||
// @Tags AutoCode
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body GetByIdReq true "请求参数"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /autoCode/delSysHistory [post]
|
||||
func (api *AutoCodeHistoryApi) Delete(c *gin.Context) {
|
||||
var req GetByIdReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
err := autoCodeHistoryUsecase.Delete(c.Request.Context(), req.ID)
|
||||
if err != nil {
|
||||
response.FailWithMessage("删除失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// RollBack 回滚自动生成代码
|
||||
// @Summary 回滚自动生成代码
|
||||
// @Tags AutoCode
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body system.SysAutoHistoryRollBack true "请求参数"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /autoCode/rollback [post]
|
||||
func (api *AutoCodeHistoryApi) RollBack(c *gin.Context) {
|
||||
var req system.SysAutoHistoryRollBack
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
err := autoCodeHistoryUsecase.RollBack(c.Request.Context(), req)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("回滚成功", c)
|
||||
}
|
||||
|
||||
// PageInfoReq 分页请求
|
||||
type PageInfoReq struct {
|
||||
Page int `json:"page" form:"page"`
|
||||
PageSize int `json:"pageSize" form:"pageSize"`
|
||||
}
|
||||
|
||||
// GetList 查询回滚记录
|
||||
// @Summary 查询回滚记录
|
||||
// @Tags AutoCode
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body PageInfoReq true "请求参数"
|
||||
// @Success 200 {object} response.Response{data=response.PageResult}
|
||||
// @Router /autoCode/getSysHistory [post]
|
||||
func (api *AutoCodeHistoryApi) GetList(c *gin.Context) {
|
||||
var req PageInfoReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
list, total, err := autoCodeHistoryUsecase.GetList(c.Request.Context(), req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: list,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/biz/system"
|
||||
"kra/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type DictionaryDetailApi struct{}
|
||||
|
||||
// DictionaryDetailRequest 字典详情请求
|
||||
type DictionaryDetailRequest struct {
|
||||
ID uint `json:"id"`
|
||||
Label string `json:"label"`
|
||||
Value string `json:"value"`
|
||||
Extend string `json:"extend"`
|
||||
Status *bool `json:"status"`
|
||||
Sort int `json:"sort"`
|
||||
SysDictionaryID uint `json:"sysDictionaryID"`
|
||||
ParentID *uint `json:"parentId"`
|
||||
}
|
||||
|
||||
// DictionaryDetailSearchRequest 字典详情搜索请求
|
||||
type DictionaryDetailSearchRequest struct {
|
||||
Page int `json:"page" form:"page"`
|
||||
PageSize int `json:"pageSize" form:"pageSize"`
|
||||
Label string `json:"label" form:"label"`
|
||||
Value string `json:"value" form:"value"`
|
||||
Status *bool `json:"status" form:"status"`
|
||||
SysDictionaryID uint `json:"sysDictionaryID" form:"sysDictionaryID"`
|
||||
ParentID *uint `json:"parentId" form:"parentId"`
|
||||
Level *int `json:"level" form:"level"`
|
||||
}
|
||||
|
||||
// GetDictionaryDetailsByParentRequest 根据父级获取字典详情请求
|
||||
type GetDictionaryDetailsByParentRequest struct {
|
||||
SysDictionaryID uint `json:"sysDictionaryID" form:"sysDictionaryID" binding:"required"`
|
||||
ParentID *uint `json:"parentId" form:"parentId"`
|
||||
IncludeChildren bool `json:"includeChildren" form:"includeChildren"`
|
||||
}
|
||||
|
||||
// CreateSysDictionaryDetail 创建字典详情
|
||||
func (d *DictionaryDetailApi) CreateSysDictionaryDetail(c *gin.Context) {
|
||||
var req DictionaryDetailRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
detail := &system.DictionaryDetail{
|
||||
Label: req.Label,
|
||||
Value: req.Value,
|
||||
Extend: req.Extend,
|
||||
Status: req.Status,
|
||||
Sort: req.Sort,
|
||||
SysDictionaryID: req.SysDictionaryID,
|
||||
ParentID: req.ParentID,
|
||||
}
|
||||
|
||||
if err := dictionaryUsecase.CreateDictionaryDetail(c.Request.Context(), detail); err != nil {
|
||||
response.FailWithMessage("创建失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("创建成功", c)
|
||||
}
|
||||
|
||||
// DeleteSysDictionaryDetail 删除字典详情
|
||||
func (d *DictionaryDetailApi) DeleteSysDictionaryDetail(c *gin.Context) {
|
||||
var req DictionaryDetailRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := dictionaryUsecase.DeleteDictionaryDetail(c.Request.Context(), req.ID); err != nil {
|
||||
response.FailWithMessage("删除失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// UpdateSysDictionaryDetail 更新字典详情
|
||||
func (d *DictionaryDetailApi) UpdateSysDictionaryDetail(c *gin.Context) {
|
||||
var req DictionaryDetailRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
detail := &system.DictionaryDetail{
|
||||
ID: req.ID,
|
||||
Label: req.Label,
|
||||
Value: req.Value,
|
||||
Extend: req.Extend,
|
||||
Status: req.Status,
|
||||
Sort: req.Sort,
|
||||
SysDictionaryID: req.SysDictionaryID,
|
||||
ParentID: req.ParentID,
|
||||
}
|
||||
|
||||
if err := dictionaryUsecase.UpdateDictionaryDetail(c.Request.Context(), detail); err != nil {
|
||||
response.FailWithMessage("更新失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("更新成功", c)
|
||||
}
|
||||
|
||||
// FindSysDictionaryDetail 根据ID获取字典详情
|
||||
func (d *DictionaryDetailApi) FindSysDictionaryDetail(c *gin.Context) {
|
||||
idStr := c.Query("ID")
|
||||
if idStr == "" {
|
||||
response.FailWithMessage("缺少参数: ID", c)
|
||||
return
|
||||
}
|
||||
id, _ := strconv.ParseUint(idStr, 10, 32)
|
||||
|
||||
detail, err := dictionaryUsecase.GetDictionaryDetail(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
response.FailWithMessage("查询失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(gin.H{"reSysDictionaryDetail": toDictionaryDetailResponse(detail)}, "查询成功", c)
|
||||
}
|
||||
|
||||
// GetSysDictionaryDetailList 分页获取字典详情列表
|
||||
func (d *DictionaryDetailApi) GetSysDictionaryDetailList(c *gin.Context) {
|
||||
var req DictionaryDetailSearchRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Page == 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize == 0 {
|
||||
req.PageSize = 10
|
||||
}
|
||||
|
||||
filters := make(map[string]interface{})
|
||||
if req.Label != "" {
|
||||
filters["label"] = req.Label
|
||||
}
|
||||
if req.Value != "" {
|
||||
filters["value"] = req.Value
|
||||
}
|
||||
if req.Status != nil {
|
||||
filters["status"] = req.Status
|
||||
}
|
||||
if req.SysDictionaryID != 0 {
|
||||
filters["sysDictionaryID"] = req.SysDictionaryID
|
||||
}
|
||||
if req.ParentID != nil {
|
||||
filters["parentId"] = req.ParentID
|
||||
}
|
||||
if req.Level != nil {
|
||||
filters["level"] = req.Level
|
||||
}
|
||||
|
||||
list, total, err := dictionaryUsecase.GetDictionaryDetailList(c.Request.Context(), req.Page, req.PageSize, filters)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
result := make([]map[string]interface{}, len(list))
|
||||
for i, item := range list {
|
||||
result[i] = toDictionaryDetailResponse(item)
|
||||
}
|
||||
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: result,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
||||
// GetDictionaryTreeList 获取字典详情树形结构
|
||||
func (d *DictionaryDetailApi) GetDictionaryTreeList(c *gin.Context) {
|
||||
sysDictionaryID := c.Query("sysDictionaryID")
|
||||
if sysDictionaryID == "" {
|
||||
response.FailWithMessage("字典ID不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(sysDictionaryID, 10, 32)
|
||||
if err != nil {
|
||||
response.FailWithMessage("字典ID格式错误", c)
|
||||
return
|
||||
}
|
||||
|
||||
list, err := dictionaryUsecase.GetDictionaryTreeList(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(gin.H{"list": toDictionaryDetailTreeResponse(list)}, "获取成功", c)
|
||||
}
|
||||
|
||||
// GetDictionaryTreeListByType 根据字典类型获取字典详情树形结构
|
||||
func (d *DictionaryDetailApi) GetDictionaryTreeListByType(c *gin.Context) {
|
||||
dictType := c.Query("type")
|
||||
if dictType == "" {
|
||||
response.FailWithMessage("字典类型不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
list, err := dictionaryUsecase.GetDictionaryTreeListByType(c.Request.Context(), dictType)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(gin.H{"list": toDictionaryDetailTreeResponse(list)}, "获取成功", c)
|
||||
}
|
||||
|
||||
// GetDictionaryDetailsByParent 根据父级ID获取字典详情
|
||||
func (d *DictionaryDetailApi) GetDictionaryDetailsByParent(c *gin.Context) {
|
||||
var req GetDictionaryDetailsByParentRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
list, err := dictionaryUsecase.GetDictionaryDetailsByParent(c.Request.Context(), req.SysDictionaryID, req.ParentID, req.IncludeChildren)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(gin.H{"list": toDictionaryDetailTreeResponse(list)}, "获取成功", c)
|
||||
}
|
||||
|
||||
// GetDictionaryPath 获取字典详情的完整路径
|
||||
func (d *DictionaryDetailApi) GetDictionaryPath(c *gin.Context) {
|
||||
idStr := c.Query("id")
|
||||
if idStr == "" {
|
||||
response.FailWithMessage("字典详情ID不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
response.FailWithMessage("字典详情ID格式错误", c)
|
||||
return
|
||||
}
|
||||
|
||||
path, err := dictionaryUsecase.GetDictionaryPath(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
result := make([]map[string]interface{}, len(path))
|
||||
for i, item := range path {
|
||||
result[i] = toDictionaryDetailResponse(item)
|
||||
}
|
||||
response.OkWithDetailed(gin.H{"path": result}, "获取成功", c)
|
||||
}
|
||||
|
||||
func toDictionaryDetailResponse(d *system.DictionaryDetail) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": d.ID,
|
||||
"label": d.Label,
|
||||
"value": d.Value,
|
||||
"extend": d.Extend,
|
||||
"status": d.Status,
|
||||
"sort": d.Sort,
|
||||
"sysDictionaryID": d.SysDictionaryID,
|
||||
"parentId": d.ParentID,
|
||||
"level": d.Level,
|
||||
"path": d.Path,
|
||||
"disabled": d.Disabled,
|
||||
}
|
||||
}
|
||||
|
||||
func toDictionaryDetailTreeResponse(list []*system.DictionaryDetail) []map[string]interface{} {
|
||||
result := make([]map[string]interface{}, len(list))
|
||||
for i, item := range list {
|
||||
resp := toDictionaryDetailResponse(item)
|
||||
if len(item.Children) > 0 {
|
||||
resp["children"] = toDictionaryDetailTreeResponse(item.Children)
|
||||
}
|
||||
result[i] = resp
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"kra/internal/biz/system"
|
||||
"kra/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ErrorApi struct{}
|
||||
|
||||
// SysErrorRequest 错误日志请求
|
||||
type SysErrorRequest struct {
|
||||
ID int64 `json:"id"`
|
||||
Form string `json:"form" binding:"required"`
|
||||
Info string `json:"info"`
|
||||
Level string `json:"level"`
|
||||
Solution string `json:"solution"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// SysErrorSearchRequest 错误日志搜索请求
|
||||
type SysErrorSearchRequest struct {
|
||||
Page int `json:"page" form:"page"`
|
||||
PageSize int `json:"pageSize" form:"pageSize"`
|
||||
Form *string `json:"form" form:"form"`
|
||||
Info *string `json:"info" form:"info"`
|
||||
CreatedAtRange []time.Time `json:"createdAtRange" form:"createdAtRange[]"`
|
||||
}
|
||||
|
||||
// CreateSysError 创建错误日志
|
||||
func (e *ErrorApi) CreateSysError(c *gin.Context) {
|
||||
var req SysErrorRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
sysError := &system.SysError{
|
||||
Form: req.Form,
|
||||
Info: req.Info,
|
||||
Level: req.Level,
|
||||
Status: "未处理",
|
||||
}
|
||||
|
||||
if err := errorUsecase.CreateSysError(c.Request.Context(), sysError); err != nil {
|
||||
response.FailWithMessage("创建失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("创建成功", c)
|
||||
}
|
||||
|
||||
// DeleteSysError 删除错误日志
|
||||
func (e *ErrorApi) DeleteSysError(c *gin.Context) {
|
||||
id := c.Query("ID")
|
||||
if id == "" {
|
||||
response.FailWithMessage("缺少参数: ID", c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := errorUsecase.DeleteSysError(c.Request.Context(), id); err != nil {
|
||||
response.FailWithMessage("删除失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// DeleteSysErrorByIds 批量删除错误日志
|
||||
func (e *ErrorApi) DeleteSysErrorByIds(c *gin.Context) {
|
||||
ids := c.QueryArray("IDs[]")
|
||||
if len(ids) == 0 {
|
||||
response.FailWithMessage("缺少参数: IDs", c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := errorUsecase.DeleteSysErrorByIds(c.Request.Context(), ids); err != nil {
|
||||
response.FailWithMessage("批量删除失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("批量删除成功", c)
|
||||
}
|
||||
|
||||
// UpdateSysError 更新错误日志
|
||||
func (e *ErrorApi) UpdateSysError(c *gin.Context) {
|
||||
var req SysErrorRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
sysError := &system.SysError{
|
||||
ID: req.ID,
|
||||
Form: req.Form,
|
||||
Info: req.Info,
|
||||
Level: req.Level,
|
||||
Solution: req.Solution,
|
||||
Status: req.Status,
|
||||
}
|
||||
|
||||
if err := errorUsecase.UpdateSysError(c.Request.Context(), sysError); err != nil {
|
||||
response.FailWithMessage("更新失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("更新成功", c)
|
||||
}
|
||||
|
||||
// FindSysError 根据ID获取错误日志
|
||||
func (e *ErrorApi) FindSysError(c *gin.Context) {
|
||||
id := c.Query("ID")
|
||||
if id == "" {
|
||||
response.FailWithMessage("缺少参数: ID", c)
|
||||
return
|
||||
}
|
||||
|
||||
sysError, err := errorUsecase.GetSysError(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
response.FailWithMessage("查询失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithData(toErrorResponse(sysError), c)
|
||||
}
|
||||
|
||||
// GetSysErrorList 分页获取错误日志列表
|
||||
func (e *ErrorApi) GetSysErrorList(c *gin.Context) {
|
||||
var req SysErrorSearchRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Page == 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize == 0 {
|
||||
req.PageSize = 10
|
||||
}
|
||||
|
||||
searchReq := &system.ErrorSearchReq{
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
Form: req.Form,
|
||||
Info: req.Info,
|
||||
CreatedAtRange: req.CreatedAtRange,
|
||||
}
|
||||
|
||||
list, total, err := errorUsecase.GetSysErrorInfoList(c.Request.Context(), searchReq)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
result := make([]map[string]interface{}, len(list))
|
||||
for i, item := range list {
|
||||
result[i] = toErrorResponse(item)
|
||||
}
|
||||
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: result,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
||||
// GetSysErrorSolution 触发AI处理错误日志
|
||||
func (e *ErrorApi) GetSysErrorSolution(c *gin.Context) {
|
||||
id := c.Query("id")
|
||||
if id == "" {
|
||||
response.FailWithMessage("缺少参数: id", c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := errorUsecase.GetSysErrorSolution(c.Request.Context(), id); err != nil {
|
||||
response.FailWithMessage("处理触发失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("已提交至AI处理", c)
|
||||
}
|
||||
|
||||
// toErrorResponse 转换错误日志响应
|
||||
func toErrorResponse(e *system.SysError) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": e.ID,
|
||||
"form": e.Form,
|
||||
"info": e.Info,
|
||||
"level": e.Level,
|
||||
"solution": e.Solution,
|
||||
"status": e.Status,
|
||||
"createdAt": e.CreatedAt,
|
||||
"updatedAt": e.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,539 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"kra/internal/biz/system"
|
||||
"kra/pkg/response"
|
||||
"kra/pkg/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 用于token一次性存储
|
||||
var (
|
||||
exportTokenCache = make(map[string]interface{})
|
||||
exportTokenExpiration = make(map[string]time.Time)
|
||||
tokenMutex sync.RWMutex
|
||||
)
|
||||
|
||||
// 五分钟检测窗口过期
|
||||
func cleanupExpiredTokens() {
|
||||
for {
|
||||
time.Sleep(5 * time.Minute)
|
||||
tokenMutex.Lock()
|
||||
now := time.Now()
|
||||
for token, expiry := range exportTokenExpiration {
|
||||
if now.After(expiry) {
|
||||
delete(exportTokenCache, token)
|
||||
delete(exportTokenExpiration, token)
|
||||
}
|
||||
}
|
||||
tokenMutex.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
go cleanupExpiredTokens()
|
||||
}
|
||||
|
||||
type ExportTemplateApi struct{}
|
||||
|
||||
// CreateSysExportTemplateRequest 创建导出模板请求
|
||||
type CreateSysExportTemplateRequest struct {
|
||||
DBName string `json:"dbName"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
TableName string `json:"tableName"`
|
||||
TemplateID string `json:"templateID"`
|
||||
TemplateInfo string `json:"templateInfo"`
|
||||
Limit *int `json:"limit"`
|
||||
Order string `json:"order"`
|
||||
Conditions []*ConditionRequest `json:"conditions"`
|
||||
JoinTemplate []*JoinTemplateRequest `json:"joinTemplate"`
|
||||
}
|
||||
|
||||
type ConditionRequest struct {
|
||||
TemplateID string `json:"templateID"`
|
||||
From string `json:"from"`
|
||||
Column string `json:"column"`
|
||||
Operator string `json:"operator"`
|
||||
}
|
||||
|
||||
type JoinTemplateRequest struct {
|
||||
TemplateID string `json:"templateID"`
|
||||
Joins string `json:"joins"`
|
||||
Table string `json:"table"`
|
||||
On string `json:"on"`
|
||||
}
|
||||
|
||||
// UpdateSysExportTemplateRequest 更新导出模板请求
|
||||
type UpdateSysExportTemplateRequest struct {
|
||||
ID uint `json:"ID" binding:"required"`
|
||||
DBName string `json:"dbName"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
TableName string `json:"tableName"`
|
||||
TemplateID string `json:"templateID"`
|
||||
TemplateInfo string `json:"templateInfo"`
|
||||
Limit *int `json:"limit"`
|
||||
Order string `json:"order"`
|
||||
Conditions []*ConditionRequest `json:"conditions"`
|
||||
JoinTemplate []*JoinTemplateRequest `json:"joinTemplate"`
|
||||
}
|
||||
|
||||
// DeleteSysExportTemplateRequest 删除导出模板请求
|
||||
type DeleteSysExportTemplateRequest struct {
|
||||
ID uint `json:"ID" binding:"required"`
|
||||
}
|
||||
|
||||
// DeleteSysExportTemplateByIdsRequest 批量删除导出模板请求
|
||||
type DeleteSysExportTemplateByIdsRequest struct {
|
||||
Ids []uint `json:"ids" binding:"required"`
|
||||
}
|
||||
|
||||
// GetSysExportTemplateListRequest 获取导出模板列表请求
|
||||
type GetSysExportTemplateListRequest struct {
|
||||
Page int `form:"page"`
|
||||
PageSize int `form:"pageSize"`
|
||||
Name string `form:"name"`
|
||||
TableName string `form:"tableName"`
|
||||
TemplateID string `form:"templateID"`
|
||||
StartCreatedAt *time.Time `form:"startCreatedAt"`
|
||||
EndCreatedAt *time.Time `form:"endCreatedAt"`
|
||||
}
|
||||
|
||||
// CreateSysExportTemplate 创建导出模板
|
||||
func (e *ExportTemplateApi) CreateSysExportTemplate(c *gin.Context) {
|
||||
var req CreateSysExportTemplateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
template := &system.ExportTemplate{
|
||||
DBName: req.DBName,
|
||||
Name: req.Name,
|
||||
TableName: req.TableName,
|
||||
TemplateID: req.TemplateID,
|
||||
TemplateInfo: req.TemplateInfo,
|
||||
Limit: req.Limit,
|
||||
Order: req.Order,
|
||||
}
|
||||
|
||||
// 转换条件
|
||||
if len(req.Conditions) > 0 {
|
||||
template.Conditions = make([]*system.Condition, len(req.Conditions))
|
||||
for i, c := range req.Conditions {
|
||||
template.Conditions[i] = &system.Condition{
|
||||
TemplateID: c.TemplateID,
|
||||
From: c.From,
|
||||
Column: c.Column,
|
||||
Operator: c.Operator,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 转换关联
|
||||
if len(req.JoinTemplate) > 0 {
|
||||
template.JoinTemplate = make([]*system.JoinTemplate, len(req.JoinTemplate))
|
||||
for i, j := range req.JoinTemplate {
|
||||
template.JoinTemplate[i] = &system.JoinTemplate{
|
||||
TemplateID: j.TemplateID,
|
||||
Joins: j.Joins,
|
||||
Table: j.Table,
|
||||
On: j.On,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := exportTemplateUsecase.CreateExportTemplate(c, template); err != nil {
|
||||
response.FailWithMessage("创建失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("创建成功", c)
|
||||
}
|
||||
|
||||
// DeleteSysExportTemplate 删除导出模板
|
||||
func (e *ExportTemplateApi) DeleteSysExportTemplate(c *gin.Context) {
|
||||
var req DeleteSysExportTemplateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := exportTemplateUsecase.DeleteExportTemplate(c, req.ID); err != nil {
|
||||
response.FailWithMessage("删除失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// DeleteSysExportTemplateByIds 批量删除导出模板
|
||||
func (e *ExportTemplateApi) DeleteSysExportTemplateByIds(c *gin.Context) {
|
||||
var req DeleteSysExportTemplateByIdsRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := exportTemplateUsecase.DeleteExportTemplateByIds(c, req.Ids); err != nil {
|
||||
response.FailWithMessage("批量删除失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("批量删除成功", c)
|
||||
}
|
||||
|
||||
// UpdateSysExportTemplate 更新导出模板
|
||||
func (e *ExportTemplateApi) UpdateSysExportTemplate(c *gin.Context) {
|
||||
var req UpdateSysExportTemplateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
template := &system.ExportTemplate{
|
||||
ID: req.ID,
|
||||
DBName: req.DBName,
|
||||
Name: req.Name,
|
||||
TableName: req.TableName,
|
||||
TemplateID: req.TemplateID,
|
||||
TemplateInfo: req.TemplateInfo,
|
||||
Limit: req.Limit,
|
||||
Order: req.Order,
|
||||
}
|
||||
|
||||
// 转换条件
|
||||
if len(req.Conditions) > 0 {
|
||||
template.Conditions = make([]*system.Condition, len(req.Conditions))
|
||||
for i, c := range req.Conditions {
|
||||
template.Conditions[i] = &system.Condition{
|
||||
TemplateID: c.TemplateID,
|
||||
From: c.From,
|
||||
Column: c.Column,
|
||||
Operator: c.Operator,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 转换关联
|
||||
if len(req.JoinTemplate) > 0 {
|
||||
template.JoinTemplate = make([]*system.JoinTemplate, len(req.JoinTemplate))
|
||||
for i, j := range req.JoinTemplate {
|
||||
template.JoinTemplate[i] = &system.JoinTemplate{
|
||||
TemplateID: j.TemplateID,
|
||||
Joins: j.Joins,
|
||||
Table: j.Table,
|
||||
On: j.On,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := exportTemplateUsecase.UpdateExportTemplate(c, template); err != nil {
|
||||
response.FailWithMessage("更新失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("更新成功", c)
|
||||
}
|
||||
|
||||
// FindSysExportTemplate 根据ID获取导出模板
|
||||
func (e *ExportTemplateApi) FindSysExportTemplate(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `form:"ID" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
template, err := exportTemplateUsecase.GetExportTemplate(c, req.ID)
|
||||
if err != nil {
|
||||
response.FailWithMessage("查询失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithData(gin.H{"resysExportTemplate": toExportTemplateResponse(template)}, c)
|
||||
}
|
||||
|
||||
// GetSysExportTemplateList 分页获取导出模板列表
|
||||
func (e *ExportTemplateApi) GetSysExportTemplateList(c *gin.Context) {
|
||||
var req GetSysExportTemplateListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
searchReq := &system.ExportTemplateSearchReq{
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
Name: req.Name,
|
||||
TableName: req.TableName,
|
||||
TemplateID: req.TemplateID,
|
||||
StartCreatedAt: req.StartCreatedAt,
|
||||
EndCreatedAt: req.EndCreatedAt,
|
||||
}
|
||||
|
||||
list, total, err := exportTemplateUsecase.GetExportTemplateList(c, searchReq)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
respList := make([]interface{}, len(list))
|
||||
for i, t := range list {
|
||||
respList[i] = toExportTemplateResponse(t)
|
||||
}
|
||||
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: respList,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
||||
// ExportExcel 导出Excel(获取token)
|
||||
func (e *ExportTemplateApi) ExportExcel(c *gin.Context) {
|
||||
templateID := c.Query("templateID")
|
||||
if templateID == "" {
|
||||
response.FailWithMessage("模板ID不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
queryParams := c.Request.URL.Query()
|
||||
|
||||
// 创造一次性token
|
||||
token := utils.RandomString(32)
|
||||
|
||||
// 记录本次请求参数
|
||||
exportParams := map[string]interface{}{
|
||||
"templateID": templateID,
|
||||
"queryParams": queryParams,
|
||||
}
|
||||
|
||||
// 参数保留记录完成鉴权
|
||||
tokenMutex.Lock()
|
||||
exportTokenCache[token] = exportParams
|
||||
exportTokenExpiration[token] = time.Now().Add(30 * time.Minute)
|
||||
tokenMutex.Unlock()
|
||||
|
||||
// 生成一次性链接
|
||||
exportUrl := fmt.Sprintf("/sysExportTemplate/exportExcelByToken?token=%s", token)
|
||||
response.OkWithData(exportUrl, c)
|
||||
}
|
||||
|
||||
// ExportExcelByToken 通过token导出Excel
|
||||
func (e *ExportTemplateApi) ExportExcelByToken(c *gin.Context) {
|
||||
token := c.Query("token")
|
||||
if token == "" {
|
||||
response.FailWithMessage("导出token不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取token并且从缓存中剔除
|
||||
tokenMutex.RLock()
|
||||
exportParamsRaw, exists := exportTokenCache[token]
|
||||
expiry, _ := exportTokenExpiration[token]
|
||||
tokenMutex.RUnlock()
|
||||
|
||||
if !exists || time.Now().After(expiry) {
|
||||
response.FailWithMessage("导出token无效或已过期", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 从token获取参数
|
||||
exportParams, ok := exportParamsRaw.(map[string]interface{})
|
||||
if !ok {
|
||||
response.FailWithMessage("解析导出参数失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取导出参数
|
||||
templateID := exportParams["templateID"].(string)
|
||||
queryParams := exportParams["queryParams"].(url.Values)
|
||||
|
||||
// 清理一次性token
|
||||
tokenMutex.Lock()
|
||||
delete(exportTokenCache, token)
|
||||
delete(exportTokenExpiration, token)
|
||||
tokenMutex.Unlock()
|
||||
|
||||
// 导出
|
||||
file, name, err := exportTemplateUsecase.ExportExcel(c, templateID, queryParams)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name+utils.RandomString(6)+".csv"))
|
||||
c.Header("success", "true")
|
||||
c.Data(http.StatusOK, "text/csv", file.Bytes())
|
||||
}
|
||||
|
||||
// PreviewSQL 预览SQL
|
||||
func (e *ExportTemplateApi) PreviewSQL(c *gin.Context) {
|
||||
templateID := c.Query("templateID")
|
||||
if templateID == "" {
|
||||
response.FailWithMessage("模板ID不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
queryParams := c.Request.URL.Query()
|
||||
|
||||
sqlPreview, err := exportTemplateUsecase.PreviewSQL(c, templateID, queryParams)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithData(gin.H{"sql": sqlPreview}, c)
|
||||
}
|
||||
|
||||
// ExportTemplate 导出Excel模板(获取token)
|
||||
func (e *ExportTemplateApi) ExportTemplate(c *gin.Context) {
|
||||
templateID := c.Query("templateID")
|
||||
if templateID == "" {
|
||||
response.FailWithMessage("模板ID不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 创造一次性token
|
||||
token := utils.RandomString(32)
|
||||
|
||||
// 记录本次请求参数
|
||||
exportParams := map[string]interface{}{
|
||||
"templateID": templateID,
|
||||
"isTemplate": true,
|
||||
}
|
||||
|
||||
// 参数保留记录完成鉴权
|
||||
tokenMutex.Lock()
|
||||
exportTokenCache[token] = exportParams
|
||||
exportTokenExpiration[token] = time.Now().Add(30 * time.Minute)
|
||||
tokenMutex.Unlock()
|
||||
|
||||
// 生成一次性链接
|
||||
exportUrl := fmt.Sprintf("/sysExportTemplate/exportTemplateByToken?token=%s", token)
|
||||
response.OkWithData(exportUrl, c)
|
||||
}
|
||||
|
||||
// ExportTemplateByToken 通过token导出模板
|
||||
func (e *ExportTemplateApi) ExportTemplateByToken(c *gin.Context) {
|
||||
token := c.Query("token")
|
||||
if token == "" {
|
||||
response.FailWithMessage("导出token不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取token并且从缓存中剔除
|
||||
tokenMutex.RLock()
|
||||
exportParamsRaw, exists := exportTokenCache[token]
|
||||
expiry, _ := exportTokenExpiration[token]
|
||||
tokenMutex.RUnlock()
|
||||
|
||||
if !exists || time.Now().After(expiry) {
|
||||
response.FailWithMessage("导出token无效或已过期", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 从token获取参数
|
||||
exportParams, ok := exportParamsRaw.(map[string]interface{})
|
||||
if !ok {
|
||||
response.FailWithMessage("解析导出参数失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否为模板导出
|
||||
isTemplate, _ := exportParams["isTemplate"].(bool)
|
||||
if !isTemplate {
|
||||
response.FailWithMessage("token类型错误", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取导出参数
|
||||
templateID := exportParams["templateID"].(string)
|
||||
|
||||
// 清理一次性token
|
||||
tokenMutex.Lock()
|
||||
delete(exportTokenCache, token)
|
||||
delete(exportTokenExpiration, token)
|
||||
tokenMutex.Unlock()
|
||||
|
||||
// 导出模板
|
||||
file, name, err := exportTemplateUsecase.ExportTemplate(c, templateID)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name+"模板.csv"))
|
||||
c.Header("success", "true")
|
||||
c.Data(http.StatusOK, "text/csv", file.Bytes())
|
||||
}
|
||||
|
||||
// ImportExcel 导入Excel
|
||||
func (e *ExportTemplateApi) ImportExcel(c *gin.Context) {
|
||||
templateID := c.Query("templateID")
|
||||
if templateID == "" {
|
||||
response.FailWithMessage("模板ID不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
response.FailWithMessage("文件获取失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := exportTemplateUsecase.ImportExcel(c, templateID, file); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("导入成功", c)
|
||||
}
|
||||
|
||||
// 转换为响应结构
|
||||
func toExportTemplateResponse(t *system.ExportTemplate) map[string]interface{} {
|
||||
resp := map[string]interface{}{
|
||||
"ID": t.ID,
|
||||
"dbName": t.DBName,
|
||||
"name": t.Name,
|
||||
"tableName": t.TableName,
|
||||
"templateID": t.TemplateID,
|
||||
"templateInfo": t.TemplateInfo,
|
||||
"limit": t.Limit,
|
||||
"order": t.Order,
|
||||
"createdAt": t.CreatedAt,
|
||||
"updatedAt": t.UpdatedAt,
|
||||
}
|
||||
|
||||
if len(t.Conditions) > 0 {
|
||||
conditions := make([]map[string]interface{}, len(t.Conditions))
|
||||
for i, c := range t.Conditions {
|
||||
conditions[i] = map[string]interface{}{
|
||||
"ID": c.ID,
|
||||
"templateID": c.TemplateID,
|
||||
"from": c.From,
|
||||
"column": c.Column,
|
||||
"operator": c.Operator,
|
||||
}
|
||||
}
|
||||
resp["conditions"] = conditions
|
||||
}
|
||||
|
||||
if len(t.JoinTemplate) > 0 {
|
||||
joins := make([]map[string]interface{}, len(t.JoinTemplate))
|
||||
for i, j := range t.JoinTemplate {
|
||||
joins[i] = map[string]interface{}{
|
||||
"ID": j.ID,
|
||||
"templateID": j.TemplateID,
|
||||
"joins": j.Joins,
|
||||
"table": j.Table,
|
||||
"on": j.On,
|
||||
}
|
||||
}
|
||||
resp["joinTemplate"] = joins
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"kra/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type DBApi struct{}
|
||||
|
||||
// InitDBRequest 初始化数据库请求
|
||||
type InitDBRequest struct {
|
||||
AdminPassword string `json:"adminPassword" binding:"required"`
|
||||
DBType string `json:"dbType"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
UserName string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
DBName string `json:"dbName"`
|
||||
DBPath string `json:"dbPath"`
|
||||
}
|
||||
|
||||
// InitDB 初始化数据库
|
||||
// 注意:KRA 项目使用 Kratos 框架,数据库配置通过 config.yaml 管理
|
||||
// 此接口主要用于兼容 GVA 前端
|
||||
func (d *DBApi) InitDB(c *gin.Context) {
|
||||
// KRA 项目数据库已通过配置文件初始化
|
||||
// 此接口返回成功以兼容前端
|
||||
response.OkWithMessage("数据库已初始化", c)
|
||||
}
|
||||
|
||||
// CheckDB 检测是否需要初始化数据库
|
||||
func (d *DBApi) CheckDB(c *gin.Context) {
|
||||
// KRA 项目数据库通过配置文件管理,无需初始化
|
||||
response.OkWithDetailed(gin.H{"needInit": false}, "数据库无需初始化", c)
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"kra/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type SystemApi struct{}
|
||||
|
||||
// GetServerInfo 获取服务器信息
|
||||
func (s *SystemApi) GetServerInfo(c *gin.Context) {
|
||||
serverInfo, err := systemUsecase.GetServerInfo(c.Request.Context())
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(gin.H{"server": serverInfo}, "获取成功", c)
|
||||
}
|
||||
|
||||
// GetSystemConfig 获取配置文件内容
|
||||
func (s *SystemApi) GetSystemConfig(c *gin.Context) {
|
||||
// 简化实现:返回基本配置信息
|
||||
response.OkWithDetailed(gin.H{
|
||||
"config": gin.H{
|
||||
"system": gin.H{
|
||||
"env": "production",
|
||||
},
|
||||
},
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
||||
// SetSystemConfig 设置配置文件内容
|
||||
func (s *SystemApi) SetSystemConfig(c *gin.Context) {
|
||||
// 简化实现:配置设置功能
|
||||
response.OkWithMessage("设置成功", c)
|
||||
}
|
||||
|
||||
// ReloadSystem 重载系统
|
||||
func (s *SystemApi) ReloadSystem(c *gin.Context) {
|
||||
// 简化实现:系统重载功能
|
||||
response.OkWithMessage("重载系统成功", c)
|
||||
}
|
||||
|
|
@ -0,0 +1,338 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"kra/internal/biz/system"
|
||||
"kra/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type VersionApi struct{}
|
||||
|
||||
// VersionSearchRequest 版本搜索请求
|
||||
type VersionSearchRequest struct {
|
||||
Page int `json:"page" form:"page"`
|
||||
PageSize int `json:"pageSize" form:"pageSize"`
|
||||
VersionName *string `json:"versionName" form:"versionName"`
|
||||
VersionCode *string `json:"versionCode" form:"versionCode"`
|
||||
CreatedAtRange []time.Time `json:"createdAtRange" form:"createdAtRange[]"`
|
||||
}
|
||||
|
||||
// ExportVersionRequest 导出版本请求
|
||||
type ExportVersionRequest struct {
|
||||
VersionName string `json:"versionName" binding:"required"`
|
||||
VersionCode string `json:"versionCode" binding:"required"`
|
||||
Description string `json:"description"`
|
||||
MenuIds []uint `json:"menuIds"`
|
||||
ApiIds []uint `json:"apiIds"`
|
||||
DictIds []uint `json:"dictIds"`
|
||||
}
|
||||
|
||||
// VersionInfo 版本信息
|
||||
type VersionInfo struct {
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Description string `json:"description"`
|
||||
ExportTime string `json:"exportTime"`
|
||||
}
|
||||
|
||||
// ExportVersionResponse 导出版本响应
|
||||
type ExportVersionResponse struct {
|
||||
Version VersionInfo `json:"version"`
|
||||
Menus []map[string]interface{} `json:"menus"`
|
||||
Apis []map[string]interface{} `json:"apis"`
|
||||
Dictionaries []map[string]interface{} `json:"dictionaries"`
|
||||
}
|
||||
|
||||
// DeleteSysVersion 删除版本
|
||||
func (v *VersionApi) DeleteSysVersion(c *gin.Context) {
|
||||
id := c.Query("ID")
|
||||
if id == "" {
|
||||
response.FailWithMessage("缺少参数: ID", c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := versionUsecase.DeleteSysVersion(c.Request.Context(), id); err != nil {
|
||||
response.FailWithMessage("删除失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// DeleteSysVersionByIds 批量删除版本
|
||||
func (v *VersionApi) DeleteSysVersionByIds(c *gin.Context) {
|
||||
ids := c.QueryArray("IDs[]")
|
||||
if len(ids) == 0 {
|
||||
response.FailWithMessage("缺少参数: IDs", c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := versionUsecase.DeleteSysVersionByIds(c.Request.Context(), ids); err != nil {
|
||||
response.FailWithMessage("批量删除失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("批量删除成功", c)
|
||||
}
|
||||
|
||||
// FindSysVersion 根据ID获取版本
|
||||
func (v *VersionApi) FindSysVersion(c *gin.Context) {
|
||||
id := c.Query("ID")
|
||||
if id == "" {
|
||||
response.FailWithMessage("缺少参数: ID", c)
|
||||
return
|
||||
}
|
||||
|
||||
version, err := versionUsecase.GetSysVersion(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
response.FailWithMessage("查询失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithData(toVersionResponse(version), c)
|
||||
}
|
||||
|
||||
// GetSysVersionList 分页获取版本列表
|
||||
func (v *VersionApi) GetSysVersionList(c *gin.Context) {
|
||||
var req VersionSearchRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Page == 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize == 0 {
|
||||
req.PageSize = 10
|
||||
}
|
||||
|
||||
searchReq := &system.VersionSearchReq{
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
VersionName: req.VersionName,
|
||||
VersionCode: req.VersionCode,
|
||||
CreatedAtRange: req.CreatedAtRange,
|
||||
}
|
||||
|
||||
list, total, err := versionUsecase.GetSysVersionInfoList(c.Request.Context(), searchReq)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
result := make([]map[string]interface{}, len(list))
|
||||
for i, item := range list {
|
||||
result[i] = toVersionResponse(item)
|
||||
}
|
||||
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: result,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
||||
// GetSysVersionPublic 公开版本接口
|
||||
func (v *VersionApi) GetSysVersionPublic(c *gin.Context) {
|
||||
response.OkWithDetailed(gin.H{
|
||||
"info": "不需要鉴权的版本管理接口信息",
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
||||
// ExportVersion 创建发版数据
|
||||
func (v *VersionApi) ExportVersion(c *gin.Context) {
|
||||
var req ExportVersionRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := c.Request.Context()
|
||||
|
||||
// 获取选中的菜单数据
|
||||
var menuData []map[string]interface{}
|
||||
if len(req.MenuIds) > 0 {
|
||||
menus, err := versionUsecase.GetMenusByIds(ctx, req.MenuIds)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取菜单数据失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
for _, m := range menus {
|
||||
menuData = append(menuData, map[string]interface{}{
|
||||
"path": m.Path,
|
||||
"name": m.Name,
|
||||
"hidden": m.Hidden,
|
||||
"component": m.Component,
|
||||
"sort": m.Sort,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 获取选中的API数据
|
||||
var apiData []map[string]interface{}
|
||||
if len(req.ApiIds) > 0 {
|
||||
apis, err := versionUsecase.GetApisByIds(ctx, req.ApiIds)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取API数据失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
for _, a := range apis {
|
||||
apiData = append(apiData, map[string]interface{}{
|
||||
"path": a.Path,
|
||||
"description": a.Description,
|
||||
"apiGroup": a.ApiGroup,
|
||||
"method": a.Method,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 获取选中的字典数据
|
||||
var dictData []map[string]interface{}
|
||||
if len(req.DictIds) > 0 {
|
||||
dicts, err := versionUsecase.GetDictionariesByIds(ctx, req.DictIds)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取字典数据失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
for _, d := range dicts {
|
||||
dictData = append(dictData, map[string]interface{}{
|
||||
"name": d.Name,
|
||||
"type": d.Type,
|
||||
"status": d.Status,
|
||||
"desc": d.Desc,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 构建导出数据
|
||||
exportData := ExportVersionResponse{
|
||||
Version: VersionInfo{
|
||||
Name: req.VersionName,
|
||||
Code: req.VersionCode,
|
||||
Description: req.Description,
|
||||
ExportTime: time.Now().Format("2006-01-02 15:04:05"),
|
||||
},
|
||||
Menus: menuData,
|
||||
Apis: apiData,
|
||||
Dictionaries: dictData,
|
||||
}
|
||||
|
||||
// 转换为JSON
|
||||
jsonData, err := json.MarshalIndent(exportData, "", " ")
|
||||
if err != nil {
|
||||
response.FailWithMessage("JSON序列化失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
// 保存版本记录
|
||||
version := &system.SysVersion{
|
||||
VersionName: req.VersionName,
|
||||
VersionCode: req.VersionCode,
|
||||
Description: req.Description,
|
||||
VersionData: string(jsonData),
|
||||
}
|
||||
|
||||
if err := versionUsecase.CreateSysVersion(ctx, version); err != nil {
|
||||
response.FailWithMessage("保存版本记录失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("创建发版成功", c)
|
||||
}
|
||||
|
||||
// DownloadVersionJson 下载版本JSON数据
|
||||
func (v *VersionApi) DownloadVersionJson(c *gin.Context) {
|
||||
id := c.Query("ID")
|
||||
if id == "" {
|
||||
response.FailWithMessage("版本ID不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
version, err := versionUsecase.GetSysVersion(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
response.FailWithMessage("获取版本记录失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
var jsonData []byte
|
||||
if version.VersionData != "" {
|
||||
jsonData = []byte(version.VersionData)
|
||||
} else {
|
||||
basicData := ExportVersionResponse{
|
||||
Version: VersionInfo{
|
||||
Name: version.VersionName,
|
||||
Code: version.VersionCode,
|
||||
Description: version.Description,
|
||||
ExportTime: version.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
},
|
||||
}
|
||||
jsonData, _ = json.MarshalIndent(basicData, "", " ")
|
||||
}
|
||||
|
||||
filename := fmt.Sprintf("version_%s_%s.json", version.VersionCode, time.Now().Format("20060102150405"))
|
||||
c.Header("Content-Type", "application/json")
|
||||
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
|
||||
c.Header("Content-Length", strconv.Itoa(len(jsonData)))
|
||||
|
||||
c.Data(http.StatusOK, "application/json", jsonData)
|
||||
}
|
||||
|
||||
// ImportVersion 导入版本数据
|
||||
func (v *VersionApi) ImportVersion(c *gin.Context) {
|
||||
var importData map[string]interface{}
|
||||
if err := c.ShouldBindJSON(&importData); err != nil {
|
||||
response.FailWithMessage("解析JSON数据失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证数据格式
|
||||
versionInfo, ok := importData["version"].(map[string]interface{})
|
||||
if !ok {
|
||||
response.FailWithMessage("版本信息格式错误", c)
|
||||
return
|
||||
}
|
||||
|
||||
name, _ := versionInfo["name"].(string)
|
||||
code, _ := versionInfo["code"].(string)
|
||||
desc, _ := versionInfo["description"].(string)
|
||||
|
||||
if name == "" || code == "" {
|
||||
response.FailWithMessage("版本名称和版本号不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建导入记录
|
||||
jsonData, _ := json.Marshal(importData)
|
||||
version := &system.SysVersion{
|
||||
VersionName: name,
|
||||
VersionCode: fmt.Sprintf("%s_imported_%s", code, time.Now().Format("20060102150405")),
|
||||
Description: fmt.Sprintf("导入版本: %s", desc),
|
||||
VersionData: string(jsonData),
|
||||
}
|
||||
|
||||
if err := versionUsecase.CreateSysVersion(c.Request.Context(), version); err != nil {
|
||||
response.FailWithMessage("保存导入记录失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("导入成功", c)
|
||||
}
|
||||
|
||||
// toVersionResponse 转换版本响应
|
||||
func toVersionResponse(v *system.SysVersion) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": v.ID,
|
||||
"versionName": v.VersionName,
|
||||
"versionCode": v.VersionCode,
|
||||
"description": v.Description,
|
||||
"versionData": v.VersionData,
|
||||
"createdAt": v.CreatedAt,
|
||||
"updatedAt": v.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,13 @@
|
|||
package router
|
||||
|
||||
import "kra/internal/server/router/system"
|
||||
import (
|
||||
"kra/internal/server/router/example"
|
||||
"kra/internal/server/router/system"
|
||||
)
|
||||
|
||||
var RouterGroupApp = new(RouterGroup)
|
||||
|
||||
type RouterGroup struct {
|
||||
System system.RouterGroup
|
||||
System system.RouterGroup
|
||||
Example example.RouterGroup
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
package example
|
||||
|
||||
// RouterGroup Example路由组
|
||||
type RouterGroup struct {
|
||||
FileUploadRouter
|
||||
CustomerRouter
|
||||
AttachmentCategoryRouter
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
handler "kra/internal/server/handler/example"
|
||||
"kra/internal/server/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AttachmentCategoryRouter struct{}
|
||||
|
||||
func (r *AttachmentCategoryRouter) InitAttachmentCategoryRouter(Router *gin.RouterGroup) {
|
||||
categoryRouter := Router.Group("attachmentCategory").Use(middleware.OperationRecordMiddleware())
|
||||
categoryRouterWithoutRecord := Router.Group("attachmentCategory")
|
||||
var api handler.AttachmentCategoryApi
|
||||
{
|
||||
categoryRouter.POST("addCategory", api.AddCategory)
|
||||
categoryRouter.POST("deleteCategory", api.DeleteCategory)
|
||||
}
|
||||
{
|
||||
categoryRouterWithoutRecord.GET("getCategoryList", api.GetCategoryList)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
handler "kra/internal/server/handler/example"
|
||||
"kra/internal/server/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type CustomerRouter struct{}
|
||||
|
||||
func (r *CustomerRouter) InitCustomerRouter(Router *gin.RouterGroup) {
|
||||
customerRouter := Router.Group("customer").Use(middleware.OperationRecordMiddleware())
|
||||
customerRouterWithoutRecord := Router.Group("customer")
|
||||
var api handler.CustomerApi
|
||||
{
|
||||
customerRouter.POST("customer", api.CreateExaCustomer)
|
||||
customerRouter.PUT("customer", api.UpdateExaCustomer)
|
||||
customerRouter.DELETE("customer", api.DeleteExaCustomer)
|
||||
}
|
||||
{
|
||||
customerRouterWithoutRecord.GET("customer", api.GetExaCustomer)
|
||||
customerRouterWithoutRecord.GET("customerList", api.GetExaCustomerList)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package example
|
||||
|
||||
import (
|
||||
handler "kra/internal/server/handler/example"
|
||||
"kra/internal/server/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type FileUploadRouter struct{}
|
||||
|
||||
func (r *FileUploadRouter) InitFileUploadRouter(Router *gin.RouterGroup) {
|
||||
fileUploadRouter := Router.Group("fileUploadAndDownload").Use(middleware.OperationRecordMiddleware())
|
||||
fileUploadRouterWithoutRecord := Router.Group("fileUploadAndDownload")
|
||||
var api handler.FileUploadApi
|
||||
{
|
||||
fileUploadRouter.POST("upload", api.UploadFile)
|
||||
fileUploadRouter.POST("deleteFile", api.DeleteFile)
|
||||
fileUploadRouter.POST("editFileName", api.EditFileName)
|
||||
fileUploadRouter.POST("importURL", api.ImportURL)
|
||||
}
|
||||
{
|
||||
fileUploadRouterWithoutRecord.POST("getFileList", api.GetFileList)
|
||||
}
|
||||
}
|
||||
|
|
@ -9,21 +9,37 @@ type RouterGroup struct {
|
|||
AuthorityRouter
|
||||
MenuRouter
|
||||
DictionaryRouter
|
||||
SysDictionaryDetailRouter
|
||||
CasbinRouter
|
||||
JwtRouter
|
||||
OperationRecordRouter
|
||||
ParamsRouter
|
||||
SysErrorRouter
|
||||
SysVersionRouter
|
||||
SysSystemRouter
|
||||
SysExportTemplateRouter
|
||||
InitRouter
|
||||
AutoCodeRouter
|
||||
AutoCodeHistoryRouter
|
||||
}
|
||||
|
||||
var (
|
||||
baseApi = api.BaseApi{}
|
||||
userApi = api.UserApi{}
|
||||
apiApi = api.ApiApi{}
|
||||
authorityApi = api.AuthorityApi{}
|
||||
menuApi = api.MenuApi{}
|
||||
dictionaryApi = api.DictionaryApi{}
|
||||
casbinApi = api.CasbinApi{}
|
||||
jwtApi = api.JwtApi{}
|
||||
operationRecordApi = api.OperationRecordApi{}
|
||||
paramsApi = api.ParamsApi{}
|
||||
baseApi = api.BaseApi{}
|
||||
userApi = api.UserApi{}
|
||||
apiApi = api.ApiApi{}
|
||||
authorityApi = api.AuthorityApi{}
|
||||
menuApi = api.MenuApi{}
|
||||
dictionaryApi = api.DictionaryApi{}
|
||||
dictionaryDetailApi = api.DictionaryDetailApi{}
|
||||
casbinApi = api.CasbinApi{}
|
||||
jwtApi = api.JwtApi{}
|
||||
operationRecordApi = api.OperationRecordApi{}
|
||||
paramsApi = api.ParamsApi{}
|
||||
errorApi = api.ErrorApi{}
|
||||
versionApi = api.VersionApi{}
|
||||
systemApi = api.SystemApi{}
|
||||
exportTemplateApi = api.ExportTemplateApi{}
|
||||
dbApi = api.DBApi{}
|
||||
autoCodeApi = api.AutoCodeApi{}
|
||||
autoCodeHistoryApi = api.AutoCodeHistoryApi{}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"kra/internal/server/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AutoCodeRouter struct{}
|
||||
|
||||
// InitAutoCodeRouter 初始化自动代码路由
|
||||
func (s *AutoCodeRouter) InitAutoCodeRouter(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup) {
|
||||
autoCodeRouter := Router.Group("autoCode").Use(middleware.OperationRecordMiddleware())
|
||||
autoCodeRouterWithoutRecord := Router.Group("autoCode")
|
||||
{
|
||||
autoCodeRouterWithoutRecord.GET("getDB", autoCodeApi.GetDB) // 获取数据库
|
||||
autoCodeRouterWithoutRecord.GET("getTables", autoCodeApi.GetTables) // 获取对应数据库的表
|
||||
autoCodeRouterWithoutRecord.GET("getColumn", autoCodeApi.GetColumn) // 获取指定表所有字段信息
|
||||
}
|
||||
// 预留其他路由
|
||||
_ = autoCodeRouter
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AutoCodeHistoryRouter struct{}
|
||||
|
||||
// InitAutoCodeHistoryRouter 初始化自动代码历史路由
|
||||
func (s *AutoCodeRouter) InitAutoCodeHistoryRouter(Router *gin.RouterGroup) {
|
||||
autoCodeHistoryRouter := Router.Group("autoCode")
|
||||
{
|
||||
autoCodeHistoryRouter.POST("getMeta", autoCodeHistoryApi.First) // 根据id获取meta信息
|
||||
autoCodeHistoryRouter.POST("rollback", autoCodeHistoryApi.RollBack) // 回滚
|
||||
autoCodeHistoryRouter.POST("delSysHistory", autoCodeHistoryApi.Delete) // 删除回滚记录
|
||||
autoCodeHistoryRouter.POST("getSysHistory", autoCodeHistoryApi.GetList) // 获取回滚记录分页
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"kra/internal/server/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type SysDictionaryDetailRouter struct{}
|
||||
|
||||
// InitSysDictionaryDetailRouter 初始化字典详情路由
|
||||
func (s *SysDictionaryDetailRouter) InitSysDictionaryDetailRouter(Router *gin.RouterGroup) {
|
||||
dictionaryDetailRouter := Router.Group("sysDictionaryDetail").Use(middleware.OperationRecordMiddleware())
|
||||
dictionaryDetailRouterWithoutRecord := Router.Group("sysDictionaryDetail")
|
||||
{
|
||||
dictionaryDetailRouter.POST("createSysDictionaryDetail", dictionaryDetailApi.CreateSysDictionaryDetail) // 新建字典详情
|
||||
dictionaryDetailRouter.DELETE("deleteSysDictionaryDetail", dictionaryDetailApi.DeleteSysDictionaryDetail) // 删除字典详情
|
||||
dictionaryDetailRouter.PUT("updateSysDictionaryDetail", dictionaryDetailApi.UpdateSysDictionaryDetail) // 更新字典详情
|
||||
}
|
||||
{
|
||||
dictionaryDetailRouterWithoutRecord.GET("findSysDictionaryDetail", dictionaryDetailApi.FindSysDictionaryDetail) // 根据ID获取字典详情
|
||||
dictionaryDetailRouterWithoutRecord.GET("getSysDictionaryDetailList", dictionaryDetailApi.GetSysDictionaryDetailList) // 获取字典详情列表
|
||||
dictionaryDetailRouterWithoutRecord.GET("getDictionaryTreeList", dictionaryDetailApi.GetDictionaryTreeList) // 获取字典详情树形结构
|
||||
dictionaryDetailRouterWithoutRecord.GET("getDictionaryTreeListByType", dictionaryDetailApi.GetDictionaryTreeListByType) // 根据字典类型获取字典详情树形结构
|
||||
dictionaryDetailRouterWithoutRecord.GET("getDictionaryDetailsByParent", dictionaryDetailApi.GetDictionaryDetailsByParent) // 根据父级ID获取字典详情
|
||||
dictionaryDetailRouterWithoutRecord.GET("getDictionaryPath", dictionaryDetailApi.GetDictionaryPath) // 获取字典详情的完整路径
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"kra/internal/server/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type SysErrorRouter struct{}
|
||||
|
||||
// InitSysErrorRouter 初始化错误日志路由
|
||||
func (s *SysErrorRouter) InitSysErrorRouter(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup) {
|
||||
sysErrorRouter := Router.Group("sysError").Use(middleware.OperationRecordMiddleware())
|
||||
sysErrorRouterWithoutRecord := Router.Group("sysError")
|
||||
sysErrorRouterWithoutAuth := PublicRouter.Group("sysError")
|
||||
{
|
||||
sysErrorRouter.DELETE("deleteSysError", errorApi.DeleteSysError) // 删除错误日志
|
||||
sysErrorRouter.DELETE("deleteSysErrorByIds", errorApi.DeleteSysErrorByIds) // 批量删除错误日志
|
||||
sysErrorRouter.PUT("updateSysError", errorApi.UpdateSysError) // 更新错误日志
|
||||
sysErrorRouter.GET("getSysErrorSolution", errorApi.GetSysErrorSolution) // 触发错误日志处理
|
||||
}
|
||||
{
|
||||
sysErrorRouterWithoutRecord.GET("findSysError", errorApi.FindSysError) // 根据ID获取错误日志
|
||||
sysErrorRouterWithoutRecord.GET("getSysErrorList", errorApi.GetSysErrorList) // 获取错误日志列表
|
||||
}
|
||||
{
|
||||
sysErrorRouterWithoutAuth.POST("createSysError", errorApi.CreateSysError) // 新建错误日志(公开接口)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"kra/internal/server/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type SysExportTemplateRouter struct{}
|
||||
|
||||
// InitSysExportTemplateRouter 初始化导出模板路由
|
||||
func (s *SysExportTemplateRouter) InitSysExportTemplateRouter(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup) {
|
||||
sysExportTemplateRouter := Router.Group("sysExportTemplate").Use(middleware.OperationRecordMiddleware())
|
||||
sysExportTemplateRouterWithoutRecord := Router.Group("sysExportTemplate")
|
||||
sysExportTemplateRouterWithoutAuth := PublicRouter.Group("sysExportTemplate")
|
||||
|
||||
{
|
||||
sysExportTemplateRouter.POST("createSysExportTemplate", exportTemplateApi.CreateSysExportTemplate) // 新建导出模板
|
||||
sysExportTemplateRouter.DELETE("deleteSysExportTemplate", exportTemplateApi.DeleteSysExportTemplate) // 删除导出模板
|
||||
sysExportTemplateRouter.DELETE("deleteSysExportTemplateByIds", exportTemplateApi.DeleteSysExportTemplateByIds) // 批量删除导出模板
|
||||
sysExportTemplateRouter.PUT("updateSysExportTemplate", exportTemplateApi.UpdateSysExportTemplate) // 更新导出模板
|
||||
sysExportTemplateRouter.POST("importExcel", exportTemplateApi.ImportExcel) // 导入excel模板数据
|
||||
}
|
||||
{
|
||||
sysExportTemplateRouterWithoutRecord.GET("findSysExportTemplate", exportTemplateApi.FindSysExportTemplate) // 根据ID获取导出模板
|
||||
sysExportTemplateRouterWithoutRecord.GET("getSysExportTemplateList", exportTemplateApi.GetSysExportTemplateList) // 获取导出模板列表
|
||||
sysExportTemplateRouterWithoutRecord.GET("exportExcel", exportTemplateApi.ExportExcel) // 获取导出token
|
||||
sysExportTemplateRouterWithoutRecord.GET("exportTemplate", exportTemplateApi.ExportTemplate) // 导出表格模板
|
||||
sysExportTemplateRouterWithoutRecord.GET("previewSQL", exportTemplateApi.PreviewSQL) // 预览SQL
|
||||
}
|
||||
{
|
||||
sysExportTemplateRouterWithoutAuth.GET("exportExcelByToken", exportTemplateApi.ExportExcelByToken) // 通过token导出表格
|
||||
sysExportTemplateRouterWithoutAuth.GET("exportTemplateByToken", exportTemplateApi.ExportTemplateByToken) // 通过token导出模板
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type InitRouter struct{}
|
||||
|
||||
// InitInitRouter 初始化数据库初始化路由
|
||||
func (s *InitRouter) InitInitRouter(Router *gin.RouterGroup) {
|
||||
initRouter := Router.Group("init")
|
||||
{
|
||||
initRouter.POST("initdb", dbApi.InitDB) // 初始化数据库
|
||||
initRouter.POST("checkdb", dbApi.CheckDB) // 检测是否需要初始化数据库
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"kra/internal/server/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type SysSystemRouter struct{}
|
||||
|
||||
// InitSystemRouter 初始化系统配置路由
|
||||
func (s *SysSystemRouter) InitSystemRouter(Router *gin.RouterGroup) {
|
||||
sysRouter := Router.Group("system").Use(middleware.OperationRecordMiddleware())
|
||||
sysRouterWithoutRecord := Router.Group("system")
|
||||
{
|
||||
sysRouter.POST("setSystemConfig", systemApi.SetSystemConfig) // 设置配置文件内容
|
||||
sysRouter.POST("reloadSystem", systemApi.ReloadSystem) // 重启服务
|
||||
}
|
||||
{
|
||||
sysRouterWithoutRecord.POST("getSystemConfig", systemApi.GetSystemConfig) // 获取配置文件内容
|
||||
sysRouterWithoutRecord.POST("getServerInfo", systemApi.GetServerInfo) // 获取服务器信息
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"kra/internal/server/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type SysVersionRouter struct{}
|
||||
|
||||
// InitSysVersionRouter 初始化版本管理路由
|
||||
func (s *SysVersionRouter) InitSysVersionRouter(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup) {
|
||||
sysVersionRouter := Router.Group("sysVersion").Use(middleware.OperationRecordMiddleware())
|
||||
sysVersionRouterWithoutRecord := Router.Group("sysVersion")
|
||||
sysVersionRouterWithoutAuth := PublicRouter.Group("sysVersion")
|
||||
{
|
||||
sysVersionRouter.DELETE("deleteSysVersion", versionApi.DeleteSysVersion) // 删除版本
|
||||
sysVersionRouter.DELETE("deleteSysVersionByIds", versionApi.DeleteSysVersionByIds) // 批量删除版本
|
||||
sysVersionRouter.POST("exportVersion", versionApi.ExportVersion) // 导出版本数据
|
||||
sysVersionRouter.POST("importVersion", versionApi.ImportVersion) // 导入版本数据
|
||||
}
|
||||
{
|
||||
sysVersionRouterWithoutRecord.GET("findSysVersion", versionApi.FindSysVersion) // 根据ID获取版本
|
||||
sysVersionRouterWithoutRecord.GET("getSysVersionList", versionApi.GetSysVersionList) // 获取版本列表
|
||||
sysVersionRouterWithoutRecord.GET("downloadVersionJson", versionApi.DownloadVersionJson) // 下载版本JSON
|
||||
}
|
||||
{
|
||||
sysVersionRouterWithoutAuth.GET("getSysVersionPublic", versionApi.GetSysVersionPublic) // 公开接口
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
var seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
// RandomString 生成指定长度的随机字符串
|
||||
func RandomString(length int) string {
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = charset[seededRand.Intn(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
Loading…
Reference in New Issue