后端重构

This commit is contained in:
Yvan 2026-01-08 19:28:58 +08:00
parent 8800c069d9
commit 9cb6b965e0
49 changed files with 4907 additions and 14 deletions

1
go.sum
View File

@ -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=

View File

@ -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,
)

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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{}
}

View File

@ -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,
}
}

View File

@ -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,
}
}

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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,
}
}

View File

@ -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,
}
}

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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,
}
}

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -0,0 +1,8 @@
package example
// RouterGroup Example路由组
type RouterGroup struct {
FileUploadRouter
CustomerRouter
AttachmentCategoryRouter
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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{}
)

View File

@ -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
}

View File

@ -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) // 获取回滚记录分页
}
}

View File

@ -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) // 获取字典详情的完整路径
}
}

View File

@ -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) // 新建错误日志(公开接口)
}
}

View File

@ -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导出模板
}
}

View File

@ -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) // 检测是否需要初始化数据库
}
}

View File

@ -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) // 获取服务器信息
}
}

View File

@ -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) // 公开接口
}
}

19
pkg/utils/random.go Normal file
View File

@ -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)
}