后端重构

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
+56
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)
}
+101
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)
}
+101
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
}
+598
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
}
+30
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
}
+124
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
}