后端重构

This commit is contained in:
Yvan
2026-01-14 14:34:49 +08:00
parent f5f77b32fe
commit 30842b42e5
274 changed files with 39754 additions and 1005 deletions
+7
View File
@@ -0,0 +1,7 @@
代码解压后把fe的api文件内容粘贴进前端api文件夹下并修改为自己想要的名字即可
后端代码解压后同理,放到自己想要的 mvc对应路径 并且到 initRouter中注册自动生成的路由 到registerTable中注册自动生成的model
项目github:"https://github.com/flipped-aurora/kratos-admin"
希望大家给个star多多鼓励
+251
View File
@@ -0,0 +1,251 @@
package {{.Package}}
import (
{{if not .OnlyTemplate}}
"{{.Module}}/pkg/response"
"{{.Module}}/internal/biz/{{.Package}}"
model "{{.Module}}/internal/data/model/{{.Package}}"
{{- if not .IsTree}}
{{.Package}}Req "{{.Module}}/internal/service/types/{{.Package}}/request"
{{- end }}
"github.com/gin-gonic/gin"
"github.com/go-kratos/kratos/v2/log"
{{- if .AutoCreateResource}}
"{{.Module}}/pkg/utils"
{{- end }}
{{- else}}
"{{.Module}}/pkg/response"
"github.com/gin-gonic/gin"
{{- end}}
)
type {{.StructName}}Handler struct {
uc *{{.Package}}.{{.StructName}}Usecase
log *log.Helper
}
func New{{.StructName}}Handler(uc *{{.Package}}.{{.StructName}}Usecase, logger log.Logger) *{{.StructName}}Handler {
return &{{.StructName}}Handler{
uc: uc,
log: log.NewHelper(logger),
}
}
{{if not .OnlyTemplate}}
// Create{{.StructName}} 创建{{.Description}}
// @Tags {{.StructName}}
// @Summary 创建{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "创建{{.Description}}"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /{{.Abbreviation}}/create{{.StructName}} [post]
func (h *{{.StructName}}Handler) Create{{.StructName}}(c *gin.Context) {
ctx := c.Request.Context()
var {{.Abbreviation}} model.{{.StructName}}
if err := c.ShouldBindJSON(&{{.Abbreviation}}); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
{{- if .AutoCreateResource }}
{{.Abbreviation}}.CreatedBy = utils.GetUserID(c)
{{- end }}
if err := h.uc.Create(ctx, &{{.Abbreviation}}); err != nil {
h.log.WithContext(ctx).Errorf("创建失败: %v", err)
response.FailWithMessage("创建失败: "+err.Error(), c)
return
}
response.OkWithMessage("创建成功", c)
}
// Delete{{.StructName}} 删除{{.Description}}
// @Tags {{.StructName}}
// @Summary 删除{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "删除{{.Description}}"
// @Success 200 {object} response.Response{msg=string} "删除成功"
// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete]
func (h *{{.StructName}}Handler) Delete{{.StructName}}(c *gin.Context) {
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}} := c.Query("{{.PrimaryField.FieldJson}}")
{{- if .AutoCreateResource }}
userID := utils.GetUserID(c)
{{- end }}
if err := h.uc.Delete(ctx, {{.PrimaryField.FieldJson}}{{- if .AutoCreateResource -}}, userID{{- end -}}); err != nil {
h.log.WithContext(ctx).Errorf("删除失败: %v", err)
response.FailWithMessage("删除失败: "+err.Error(), c)
return
}
response.OkWithMessage("删除成功", c)
}
// Delete{{.StructName}}ByIds 批量删除{{.Description}}
// @Tags {{.StructName}}
// @Summary 批量删除{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "批量删除成功"
// @Router /{{.Abbreviation}}/delete{{.StructName}}ByIds [delete]
func (h *{{.StructName}}Handler) Delete{{.StructName}}ByIds(c *gin.Context) {
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}}s := c.QueryArray("{{.PrimaryField.FieldJson}}s[]")
{{- if .AutoCreateResource }}
userID := utils.GetUserID(c)
{{- end }}
if err := h.uc.DeleteByIds(ctx, {{.PrimaryField.FieldJson}}s{{- if .AutoCreateResource }}, userID{{- end }}); err != nil {
h.log.WithContext(ctx).Errorf("批量删除失败: %v", err)
response.FailWithMessage("批量删除失败: "+err.Error(), c)
return
}
response.OkWithMessage("批量删除成功", c)
}
// Update{{.StructName}} 更新{{.Description}}
// @Tags {{.StructName}}
// @Summary 更新{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "更新{{.Description}}"
// @Success 200 {object} response.Response{msg=string} "更新成功"
// @Router /{{.Abbreviation}}/update{{.StructName}} [put]
func (h *{{.StructName}}Handler) Update{{.StructName}}(c *gin.Context) {
ctx := c.Request.Context()
var {{.Abbreviation}} model.{{.StructName}}
if err := c.ShouldBindJSON(&{{.Abbreviation}}); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
{{- if .AutoCreateResource }}
{{.Abbreviation}}.UpdatedBy = utils.GetUserID(c)
{{- end }}
if err := h.uc.Update(ctx, &{{.Abbreviation}}); err != nil {
h.log.WithContext(ctx).Errorf("更新失败: %v", err)
response.FailWithMessage("更新失败: "+err.Error(), c)
return
}
response.OkWithMessage("更新成功", c)
}
// Find{{.StructName}} 用id查询{{.Description}}
// @Tags {{.StructName}}
// @Summary 用id查询{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param {{.PrimaryField.FieldJson}} query {{.PrimaryField.FieldType}} true "用id查询{{.Description}}"
// @Success 200 {object} response.Response{data=model.{{.StructName}},msg=string} "查询成功"
// @Router /{{.Abbreviation}}/find{{.StructName}} [get]
func (h *{{.StructName}}Handler) Find{{.StructName}}(c *gin.Context) {
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}} := c.Query("{{.PrimaryField.FieldJson}}")
re{{.Abbreviation}}, err := h.uc.FindByID(ctx, {{.PrimaryField.FieldJson}})
if err != nil {
h.log.WithContext(ctx).Errorf("查询失败: %v", err)
response.FailWithMessage("查询失败: "+err.Error(), c)
return
}
response.OkWithData(re{{.Abbreviation}}, c)
}
{{- if .IsTree }}
// Get{{.StructName}}List 分页获取{{.Description}}列表,Tree模式下不接受参数
// @Tags {{.StructName}}
// @Summary 分页获取{{.Description}}列表
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func (h *{{.StructName}}Handler) Get{{.StructName}}List(c *gin.Context) {
ctx := c.Request.Context()
list, err := h.uc.List(ctx)
if err != nil {
h.log.WithContext(ctx).Errorf("获取失败: %v", err)
response.FailWithMessage("获取失败: "+err.Error(), c)
return
}
response.OkWithDetailed(list, "获取成功", c)
}
{{- else }}
// Get{{.StructName}}List 分页获取{{.Description}}列表
// @Tags {{.StructName}}
// @Summary 分页获取{{.Description}}列表
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query {{.Package}}Req.{{.StructName}}Search true "分页获取{{.Description}}列表"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func (h *{{.StructName}}Handler) Get{{.StructName}}List(c *gin.Context) {
ctx := c.Request.Context()
var pageInfo {{.Package}}Req.{{.StructName}}Search
if err := c.ShouldBindQuery(&pageInfo); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := h.uc.List(ctx, &pageInfo)
if err != nil {
h.log.WithContext(ctx).Errorf("获取失败: %v", err)
response.FailWithMessage("获取失败: "+err.Error(), c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
{{- end }}
{{- if .HasDataSource }}
// Get{{.StructName}}DataSource 获取{{.StructName}}的数据源
// @Tags {{.StructName}}
// @Summary 获取{{.StructName}}的数据源
// @Accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=object,msg=string} "查询成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}DataSource [get]
func (h *{{.StructName}}Handler) Get{{.StructName}}DataSource(c *gin.Context) {
ctx := c.Request.Context()
dataSource, err := h.uc.GetDataSource(ctx)
if err != nil {
h.log.WithContext(ctx).Errorf("查询失败: %v", err)
response.FailWithMessage("查询失败: "+err.Error(), c)
return
}
response.OkWithData(dataSource, c)
}
{{- end }}
{{- end }}
// Get{{.StructName}}Public 不需要鉴权的{{.Description}}接口
// @Tags {{.StructName}}
// @Summary 不需要鉴权的{{.Description}}接口
// @Accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
func (h *{{.StructName}}Handler) Get{{.StructName}}Public(c *gin.Context) {
ctx := c.Request.Context()
h.uc.GetPublic(ctx)
response.OkWithDetailed(gin.H{
"info": "不需要鉴权的{{.Description}}接口信息",
}, "获取成功", c)
}
+12
View File
@@ -0,0 +1,12 @@
{{- if .IsAdd }}
// 请在 {{.Package}} 包的 enter.go 文件中的 ProviderSet 添加以下内容:
// New{{.StructName}}Handler,
{{- else }}
package {{ .Package }}
import "github.com/google/wire"
// ProviderSet is {{.Package}} handler providers.
// 包含 {{.Description}} 相关的 HTTP 处理器
var ProviderSet = wire.NewSet(New{{.StructName}}Handler)
{{- end }}
+217
View File
@@ -0,0 +1,217 @@
{{- if .IsAdd}}
// 在 {{.StructName}}Repo 接口中新增如下方法
// 请根据实际需求添加
{{- else}}
package {{.Package}}
import (
{{- if not .OnlyTemplate }}
"context"
{{- if .IsTree }}
"errors"
{{- end }}
"{{.Module}}/internal/data/model/{{.Package}}"
{{- if not .IsTree}}
{{.Package}}Req "{{.Module}}/internal/service/types/{{.Package}}/request"
{{- end }}
"github.com/go-kratos/kratos/v2/log"
"gorm.io/gorm"
{{- end }}
)
// {{.StructName}}Repo {{.Description}}仓储接口
type {{.StructName}}Repo interface {
{{- if not .OnlyTemplate }}
Create(ctx context.Context, {{.Abbreviation}} *{{.Package}}.{{.StructName}}) error
Delete(ctx context.Context, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}{{- if .AutoCreateResource -}}, userID uint{{- end -}}) error
DeleteByIds(ctx context.Context, {{.PrimaryField.FieldJson}}s []{{.PrimaryField.FieldType}}{{- if .AutoCreateResource -}}, deletedBy uint{{- end -}}) error
{{- if .AutoCreateResource }}
// DeleteWithTx 在事务中删除记录(用于 AutoCreateResource 场景)
DeleteWithTx(ctx context.Context, tx *gorm.DB, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}) error
// DeleteByIdsWithTx 在事务中批量删除记录(用于 AutoCreateResource 场景)
DeleteByIdsWithTx(ctx context.Context, tx *gorm.DB, {{.PrimaryField.FieldJson}}s []{{.PrimaryField.FieldType}}) error
{{- end }}
Update(ctx context.Context, {{.Abbreviation}} *{{.Package}}.{{.StructName}}) error
FindByID(ctx context.Context, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}) (*{{.Package}}.{{.StructName}}, error)
{{- if .IsTree }}
List(ctx context.Context) ([]*{{.Package}}.{{.StructName}}, error)
HasChildren(ctx context.Context, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}) (bool, error)
{{- else }}
List(ctx context.Context, req *{{.Package}}Req.{{.StructName}}Search) ([]*{{.Package}}.{{.StructName}}, int64, error)
{{- end }}
{{- if .HasDataSource }}
GetDataSource(ctx context.Context) (map[string][]map[string]any, error)
{{- end }}
{{- end }}
{{- if .HasCustomMethods }}
{{ GenerateCustomMethodInterface .CustomMethods .StructName .Package }}
{{- end }}
}
// {{.StructName}}Usecase {{.Description}}用例
type {{.StructName}}Usecase struct {
repo {{.StructName}}Repo
log *log.Helper
}
// New{{.StructName}}Usecase 创建{{.Description}}用例
func New{{.StructName}}Usecase(repo {{.StructName}}Repo, logger log.Logger) *{{.StructName}}Usecase {
return &{{.StructName}}Usecase{
repo: repo,
log: log.NewHelper(logger),
}
}
{{- if not .OnlyTemplate }}
// Create 创建{{.Description}}
func (uc *{{.StructName}}Usecase) Create(ctx context.Context, {{.Abbreviation}} *{{.Package}}.{{.StructName}}) error {
uc.log.WithContext(ctx).Infof("创建{{.Description}}")
if err := uc.repo.Create(ctx, {{.Abbreviation}}); err != nil {
uc.log.WithContext(ctx).Errorf("创建{{.Description}}失败: %v", err)
return err
}
return nil
}
// Delete 删除{{.Description}}
func (uc *{{.StructName}}Usecase) Delete(ctx context.Context, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}{{- if .AutoCreateResource -}}, userID uint{{- end -}}) error {
uc.log.WithContext(ctx).Infof("删除{{.Description}}, {{.PrimaryField.FieldJson}}: %v", {{.PrimaryField.FieldJson}})
{{- if .IsTree }}
// 检查是否有子节点
hasChildren, err := uc.repo.HasChildren(ctx, {{.PrimaryField.FieldJson}})
if err != nil {
uc.log.WithContext(ctx).Errorf("检查子节点失败: %v", err)
return err
}
if hasChildren {
uc.log.WithContext(ctx).Warn("此节点存在子节点不允许删除")
return errors.New("此节点存在子节点不允许删除")
}
{{- end }}
if err := uc.repo.Delete(ctx, {{.PrimaryField.FieldJson}}{{- if .AutoCreateResource -}}, userID{{- end -}}); err != nil {
uc.log.WithContext(ctx).Errorf("删除{{.Description}}失败: %v", err)
return err
}
return nil
}
// DeleteByIds 批量删除{{.Description}}
func (uc *{{.StructName}}Usecase) DeleteByIds(ctx context.Context, {{.PrimaryField.FieldJson}}s []{{.PrimaryField.FieldType}}{{- if .AutoCreateResource -}}, deletedBy uint{{- end -}}) error {
uc.log.WithContext(ctx).Infof("批量删除{{.Description}}, 数量: %d", len({{.PrimaryField.FieldJson}}s))
if err := uc.repo.DeleteByIds(ctx, {{.PrimaryField.FieldJson}}s{{- if .AutoCreateResource -}}, deletedBy{{- end -}}); err != nil {
uc.log.WithContext(ctx).Errorf("批量删除{{.Description}}失败: %v", err)
return err
}
return nil
}
{{- if .AutoCreateResource }}
// DeleteWithTx 在事务中删除{{.Description}}(用于 AutoCreateResource 场景)
// @param ctx 上下文
// @param tx 事务对象
// @param {{.PrimaryField.FieldJson}} 主键ID
// @return error 删除失败时返回错误
func (uc *{{.StructName}}Usecase) DeleteWithTx(ctx context.Context, tx *gorm.DB, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}) error {
uc.log.WithContext(ctx).Infof("事务删除{{.Description}}, {{.PrimaryField.FieldJson}}: %v", {{.PrimaryField.FieldJson}})
{{- if .IsTree }}
// 检查是否有子节点
hasChildren, err := uc.repo.HasChildren(ctx, {{.PrimaryField.FieldJson}})
if err != nil {
uc.log.WithContext(ctx).Errorf("检查子节点失败: %v", err)
return err
}
if hasChildren {
uc.log.WithContext(ctx).Warn("此节点存在子节点不允许删除")
return errors.New("此节点存在子节点不允许删除")
}
{{- end }}
if err := uc.repo.DeleteWithTx(ctx, tx, {{.PrimaryField.FieldJson}}); err != nil {
uc.log.WithContext(ctx).Errorf("事务删除{{.Description}}失败: %v", err)
return err
}
return nil
}
// DeleteByIdsWithTx 在事务中批量删除{{.Description}}(用于 AutoCreateResource 场景)
// @param ctx 上下文
// @param tx 事务对象
// @param {{.PrimaryField.FieldJson}}s 主键ID列表
// @return error 删除失败时返回错误
func (uc *{{.StructName}}Usecase) DeleteByIdsWithTx(ctx context.Context, tx *gorm.DB, {{.PrimaryField.FieldJson}}s []{{.PrimaryField.FieldType}}) error {
uc.log.WithContext(ctx).Infof("事务批量删除{{.Description}}, 数量: %d", len({{.PrimaryField.FieldJson}}s))
if err := uc.repo.DeleteByIdsWithTx(ctx, tx, {{.PrimaryField.FieldJson}}s); err != nil {
uc.log.WithContext(ctx).Errorf("事务批量删除{{.Description}}失败: %v", err)
return err
}
return nil
}
{{- end }}
// Update 更新{{.Description}}
func (uc *{{.StructName}}Usecase) Update(ctx context.Context, {{.Abbreviation}} *{{.Package}}.{{.StructName}}) error {
uc.log.WithContext(ctx).Infof("更新{{.Description}}")
if err := uc.repo.Update(ctx, {{.Abbreviation}}); err != nil {
uc.log.WithContext(ctx).Errorf("更新{{.Description}}失败: %v", err)
return err
}
return nil
}
// FindByID 根据ID获取{{.Description}}
func (uc *{{.StructName}}Usecase) FindByID(ctx context.Context, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}) (*{{.Package}}.{{.StructName}}, error) {
uc.log.WithContext(ctx).Debugf("查询{{.Description}}, {{.PrimaryField.FieldJson}}: %v", {{.PrimaryField.FieldJson}})
result, err := uc.repo.FindByID(ctx, {{.PrimaryField.FieldJson}})
if err != nil {
uc.log.WithContext(ctx).Errorf("查询{{.Description}}失败: %v", err)
return nil, err
}
return result, nil
}
{{- if .IsTree }}
// List 获取{{.Description}}列表(树形)
func (uc *{{.StructName}}Usecase) List(ctx context.Context) ([]*{{.Package}}.{{.StructName}}, error) {
uc.log.WithContext(ctx).Debug("获取{{.Description}}树形列表")
result, err := uc.repo.List(ctx)
if err != nil {
uc.log.WithContext(ctx).Errorf("获取{{.Description}}列表失败: %v", err)
return nil, err
}
return result, nil
}
{{- else }}
// List 分页获取{{.Description}}列表
func (uc *{{.StructName}}Usecase) List(ctx context.Context, req *{{.Package}}Req.{{.StructName}}Search) ([]*{{.Package}}.{{.StructName}}, int64, error) {
uc.log.WithContext(ctx).Debugf("获取{{.Description}}列表, 页码: %d, 每页: %d", req.Page, req.PageSize)
list, total, err := uc.repo.List(ctx, req)
if err != nil {
uc.log.WithContext(ctx).Errorf("获取{{.Description}}列表失败: %v", err)
return nil, 0, err
}
return list, total, nil
}
{{- end }}
{{- if .HasDataSource }}
// GetDataSource 获取{{.Description}}数据源
func (uc *{{.StructName}}Usecase) GetDataSource(ctx context.Context) (map[string][]map[string]any, error) {
uc.log.WithContext(ctx).Debug("获取{{.Description}}数据源")
result, err := uc.repo.GetDataSource(ctx)
if err != nil {
uc.log.WithContext(ctx).Errorf("获取{{.Description}}数据源失败: %v", err)
return nil, err
}
return result, nil
}
{{- end }}
{{- end }}
// GetPublic 获取{{.Description}}公开数据
func (uc *{{.StructName}}Usecase) GetPublic(ctx context.Context) {
// 此方法为获取公开数据
// 请自行实现
}
{{- end }}
+14
View File
@@ -0,0 +1,14 @@
{{- if .IsAdd }}
// 请在 {{.Package}} 包的 enter.go 文件中的 ProviderSet 添加以下内容:
// New{{.StructName}}Usecase,
{{- else }}
package {{.Package}}
import "github.com/google/wire"
// ProviderSet is {{.Package}} biz providers.
// 包含 {{.Description}} 相关的业务逻辑用例
var ProviderSet = wire.NewSet(
New{{.StructName}}Usecase,
)
{{- end }}
+322
View File
@@ -0,0 +1,322 @@
{{- $db := "r.data.db" }}
{{- if .IsAdd}}
// Get{{.StructName}}List 新增搜索语句 (GORM Gen 风格)
// 在 List 方法中添加以下条件:
{{ GenerateGormGenSearchConditions .Fields .StructName }}
// Get{{.StructName}}List 新增排序语句
// 在 List 方法中添加以下排序字段到 orderMap:
{{- range .Fields}}
{{- if .Sort}}
// orderMap["{{.ColumnName}}"] = t.{{.FieldName}}
{{- end}}
{{- end}}
{{- if .HasDataSource }}
// GetDataSource 方法新增关联语句
{{range $key, $value := .DataSourceMap}}
{{$key}} := make([]map[string]any, 0)
{{ $dataDB := "r.data.db" }}
{{$dataDB}}.Table("{{$value.Table}}"){{- if $value.HasDeletedAt}}.Where("deleted_at IS NULL"){{ end }}.Select("{{$value.Label}} as label,{{$value.Value}} as value").Scan(&{{$key}})
res["{{$key}}"] = {{$key}}
{{- end }}
{{- end }}
{{- else}}
package {{.Package}}
import (
{{- if not .OnlyTemplate }}
"context"
"{{.Module}}/internal/biz/{{.Package}}"
"{{.Module}}/internal/data/model"
"{{.Module}}/internal/data/query"
{{- if not .IsTree}}
{{.Package}}Req "{{.Module}}/internal/service/types/{{.Package}}/request"
{{- else }}
"{{.Module}}/pkg/utils"
{{- end }}
{{- if .AutoCreateResource }}
"gorm.io/gorm"
{{- end}}
{{- if .NeedSort}}
"gorm.io/gen/field"
{{- end}}
"github.com/go-kratos/kratos/v2/log"
{{- end }}
)
type {{.Abbreviation}}Repo struct {
data *Data
log *log.Helper
}
// New{{.StructName}}Repo 创建{{.Description}}仓储
// 实现 {{.Package}}.{{.StructName}}Repo 接口
func New{{.StructName}}Repo(data *Data, logger log.Logger) {{.Package}}.{{.StructName}}Repo {
return &{{.Abbreviation}}Repo{
data: data,
log: log.NewHelper(logger),
}
}
// Create 创建{{.Description}}
func (r *{{.Abbreviation}}Repo) Create(ctx context.Context, {{.Abbreviation}} *{{.Package}}.{{.StructName}}) error {
m := toModel{{.StructName}}({{.Abbreviation}})
if err := query.{{.StructName}}.WithContext(ctx).Create(m); err != nil {
return err
}
// 回写生成的ID
{{.Abbreviation}}.{{.PrimaryField.FieldName}} = {{- if eq .PrimaryField.FieldType "uint"}} uint(m.{{.PrimaryField.FieldName}}){{- else if eq .PrimaryField.FieldType "int"}} int(m.{{.PrimaryField.FieldName}}){{- else if eq .PrimaryField.FieldType "int64"}} m.{{.PrimaryField.FieldName}}{{- else}} m.{{.PrimaryField.FieldName}}{{- end}}
return nil
}
// Delete 删除{{.Description}}
func (r *{{.Abbreviation}}Repo) Delete(ctx context.Context, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}{{- if .AutoCreateResource -}}, userID uint{{- end -}}) error {
t := query.{{.StructName}}
{{- if .AutoCreateResource }}
return {{$db}}.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
q := query.Use(tx).{{.StructName}}
if _, err := q.WithContext(ctx).Where(t.{{.PrimaryField.FieldName}}.Eq({{- if eq .PrimaryField.FieldType "uint"}}int64({{.PrimaryField.FieldJson}}){{- else if eq .PrimaryField.FieldType "int"}}int64({{.PrimaryField.FieldJson}}){{- else}}{{.PrimaryField.FieldJson}}{{- end}})).Update(t.DeletedBy, userID); err != nil {
return err
}
if _, err := q.WithContext(ctx).Where(t.{{.PrimaryField.FieldName}}.Eq({{- if eq .PrimaryField.FieldType "uint"}}int64({{.PrimaryField.FieldJson}}){{- else if eq .PrimaryField.FieldType "int"}}int64({{.PrimaryField.FieldJson}}){{- else}}{{.PrimaryField.FieldJson}}{{- end}})).Delete(); err != nil {
return err
}
return nil
})
{{- else }}
_, err := t.WithContext(ctx).Where(t.{{.PrimaryField.FieldName}}.Eq({{- if eq .PrimaryField.FieldType "uint"}}int64({{.PrimaryField.FieldJson}}){{- else if eq .PrimaryField.FieldType "int"}}int64({{.PrimaryField.FieldJson}}){{- else}}{{.PrimaryField.FieldJson}}{{- end}})).Delete()
return err
{{- end }}
}
// DeleteByIds 批量删除{{.Description}}
func (r *{{.Abbreviation}}Repo) DeleteByIds(ctx context.Context, {{.PrimaryField.FieldJson}}s []{{.PrimaryField.FieldType}}{{- if .AutoCreateResource -}}, deletedBy uint{{- end -}}) error {
t := query.{{.StructName}}
// 转换 ID 类型
int64Ids := make([]int64, len({{.PrimaryField.FieldJson}}s))
for i, id := range {{.PrimaryField.FieldJson}}s {
int64Ids[i] = int64(id)
}
{{- if .AutoCreateResource }}
return {{$db}}.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
q := query.Use(tx).{{.StructName}}
if _, err := q.WithContext(ctx).Where(t.{{.PrimaryField.FieldName}}.In(int64Ids...)).Update(t.DeletedBy, deletedBy); err != nil {
return err
}
if _, err := q.WithContext(ctx).Where(t.{{.PrimaryField.FieldName}}.In(int64Ids...)).Delete(); err != nil {
return err
}
return nil
})
{{- else}}
_, err := t.WithContext(ctx).Where(t.{{.PrimaryField.FieldName}}.In(int64Ids...)).Delete()
return err
{{- end}}
}
{{- if .AutoCreateResource }}
// DeleteWithTx 在事务中删除{{.Description}}(用于 Service 层事务管理)
// @param ctx 上下文
// @param tx 事务对象(由 Service 层传入)
// @param {{.PrimaryField.FieldJson}} 主键ID
// @return error 删除失败时返回错误
func (r *{{.Abbreviation}}Repo) DeleteWithTx(ctx context.Context, tx *gorm.DB, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}) error {
t := query.{{.StructName}}
q := query.Use(tx).{{.StructName}}
_, err := q.WithContext(ctx).Where(t.{{.PrimaryField.FieldName}}.Eq({{- if eq .PrimaryField.FieldType "uint"}}int64({{.PrimaryField.FieldJson}}){{- else if eq .PrimaryField.FieldType "int"}}int64({{.PrimaryField.FieldJson}}){{- else}}{{.PrimaryField.FieldJson}}{{- end}})).Delete()
return err
}
// DeleteByIdsWithTx 在事务中批量删除{{.Description}}(用于 Service 层事务管理)
// @param ctx 上下文
// @param tx 事务对象(由 Service 层传入)
// @param {{.PrimaryField.FieldJson}}s 主键ID列表
// @return error 删除失败时返回错误
func (r *{{.Abbreviation}}Repo) DeleteByIdsWithTx(ctx context.Context, tx *gorm.DB, {{.PrimaryField.FieldJson}}s []{{.PrimaryField.FieldType}}) error {
t := query.{{.StructName}}
// 转换 ID 类型
int64Ids := make([]int64, len({{.PrimaryField.FieldJson}}s))
for i, id := range {{.PrimaryField.FieldJson}}s {
int64Ids[i] = int64(id)
}
q := query.Use(tx).{{.StructName}}
_, err := q.WithContext(ctx).Where(t.{{.PrimaryField.FieldName}}.In(int64Ids...)).Delete()
return err
}
{{- end }}
// Update 更新{{.Description}}
func (r *{{.Abbreviation}}Repo) Update(ctx context.Context, {{.Abbreviation}} *{{.Package}}.{{.StructName}}) error {
t := query.{{.StructName}}
m := toModel{{.StructName}}({{.Abbreviation}})
_, err := t.WithContext(ctx).Where(t.{{.PrimaryField.FieldName}}.Eq(m.{{.PrimaryField.FieldName}})).Updates(m)
return err
}
// FindByID 根据ID获取{{.Description}}
func (r *{{.Abbreviation}}Repo) FindByID(ctx context.Context, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}) (*{{.Package}}.{{.StructName}}, error) {
t := query.{{.StructName}}
m, err := t.WithContext(ctx).Where(t.{{.PrimaryField.FieldName}}.Eq({{- if eq .PrimaryField.FieldType "uint"}}int64({{.PrimaryField.FieldJson}}){{- else if eq .PrimaryField.FieldType "int"}}int64({{.PrimaryField.FieldJson}}){{- else}}{{.PrimaryField.FieldJson}}{{- end}})).First()
if err != nil {
return nil, err
}
return toBiz{{.StructName}}(m), nil
}
{{- if .IsTree }}
// List 获取{{.Description}}列表(树形)
func (r *{{.Abbreviation}}Repo) List(ctx context.Context) ([]*{{.Package}}.{{.StructName}}, error) {
t := query.{{.StructName}}
models, err := t.WithContext(ctx).Find()
if err != nil {
return nil, err
}
// 转换为 biz 类型
result := make([]*{{.Package}}.{{.StructName}}, len(models))
for i, m := range models {
result[i] = toBiz{{.StructName}}(m)
}
return utils.BuildTree(result), nil
}
// HasChildren 检查是否有子节点
func (r *{{.Abbreviation}}Repo) HasChildren(ctx context.Context, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}) (bool, error) {
t := query.{{.StructName}}
count, err := t.WithContext(ctx).Where(t.ParentID.Eq({{- if eq .PrimaryField.FieldType "uint"}}int64({{.PrimaryField.FieldJson}}){{- else if eq .PrimaryField.FieldType "int"}}int64({{.PrimaryField.FieldJson}}){{- else}}{{.PrimaryField.FieldJson}}{{- end}})).Count()
return count > 0, err
}
{{- else }}
// List 分页获取{{.Description}}列表
func (r *{{.Abbreviation}}Repo) List(ctx context.Context, req *{{.Package}}Req.{{.StructName}}Search) ([]*{{.Package}}.{{.StructName}}, int64, error) {
t := query.{{.StructName}}
q := t.WithContext(ctx)
// 条件搜索 (使用 GORM Gen 类型安全查询)
{{- if .GvaModel }}
if len(req.CreatedAtRange) == 2 {
q = q.Where(t.CreatedAt.Between(req.CreatedAtRange[0], req.CreatedAtRange[1]))
}
{{- end }}
{{ GenerateGormGenSearchConditions .Fields .StructName }}
// 统计总数
total, err := q.Count()
if err != nil {
return nil, 0, err
}
{{- if .NeedSort}}
// 排序 (使用 GORM Gen 类型安全排序)
orderMap := make(map[string]func() field.OrderExpr)
{{- if .GvaModel }}
orderMap["id"] = func() field.OrderExpr { return t.ID }
orderMap["created_at"] = func() field.OrderExpr { return t.CreatedAt }
{{- end }}
{{- range .Fields}}
{{- if .Sort}}
orderMap["{{.ColumnName}}"] = func() field.OrderExpr { return t.{{.FieldName}} }
{{- end}}
{{- end}}
if orderFn, ok := orderMap[req.Sort]; ok {
if req.Order == "descending" {
q = q.Order(orderFn().Desc())
} else {
q = q.Order(orderFn())
}
}
{{- end}}
// 分页
limit := req.PageSize
offset := req.PageSize * (req.Page - 1)
if limit != 0 {
q = q.Limit(limit).Offset(offset)
}
models, err := q.Find()
if err != nil {
return nil, 0, err
}
// 转换为 biz 类型
result := make([]*{{.Package}}.{{.StructName}}, len(models))
for i, m := range models {
result[i] = toBiz{{.StructName}}(m)
}
return result, total, nil
}
{{- end }}
{{- if .HasDataSource }}
// GetDataSource 获取{{.Description}}数据源
func (r *{{.Abbreviation}}Repo) GetDataSource(ctx context.Context) (map[string][]map[string]any, error) {
res := make(map[string][]map[string]any)
{{range $key, $value := .DataSourceMap}}
{{$key}} := make([]map[string]any, 0)
if err := r.data.db.WithContext(ctx).Table("{{$value.Table}}"){{- if $value.HasDeletedAt}}.Where("deleted_at IS NULL"){{ end }}.Select("{{$value.Label}} as label, {{$value.Value}} as value").Scan(&{{$key}}).Error; err != nil {
return nil, err
}
res["{{$key}}"] = {{$key}}
{{- end }}
return res, nil
}
{{- end }}
// toModel{{.StructName}} 将 biz 层对象转换为 model 层对象
func toModel{{.StructName}}(b *{{.Package}}.{{.StructName}}) *model.{{.StructName}} {
if b == nil {
return nil
}
return &model.{{.StructName}}{
{{- if .GvaModel }}
GVA_MODEL: model.GVA_MODEL{
ID: int64(b.ID),
CreatedAt: b.CreatedAt,
UpdatedAt: b.UpdatedAt,
},
{{- else }}
{{.PrimaryField.FieldName}}: {{- if eq .PrimaryField.FieldType "uint"}} int64(b.{{.PrimaryField.FieldName}}){{- else if eq .PrimaryField.FieldType "int"}} int64(b.{{.PrimaryField.FieldName}}){{- else}} b.{{.PrimaryField.FieldName}}{{- end}},
{{- end }}
{{- range .Fields}}
{{- if not .PrimaryKey}}
{{.FieldName}}: b.{{.FieldName}},
{{- end}}
{{- end}}
}
}
// toBiz{{.StructName}} 将 model 层对象转换为 biz 层对象
func toBiz{{.StructName}}(m *model.{{.StructName}}) *{{.Package}}.{{.StructName}} {
if m == nil {
return nil
}
return &{{.Package}}.{{.StructName}}{
{{- if .GvaModel }}
ID: uint(m.ID),
CreatedAt: m.CreatedAt,
UpdatedAt: m.UpdatedAt,
{{- else }}
{{.PrimaryField.FieldName}}: {{- if eq .PrimaryField.FieldType "uint"}} uint(m.{{.PrimaryField.FieldName}}){{- else if eq .PrimaryField.FieldType "int"}} int(m.{{.PrimaryField.FieldName}}){{- else}} m.{{.PrimaryField.FieldName}}{{- end}},
{{- end }}
{{- range .Fields}}
{{- if not .PrimaryKey}}
{{.FieldName}}: m.{{.FieldName}},
{{- end}}
{{- end}}
}
}
{{- if .HasCustomMethods }}
{{ GenerateCustomMethodImpl .CustomMethods .StructName .Package .Abbreviation }}
{{- end }}
{{- end}}
+14
View File
@@ -0,0 +1,14 @@
{{- if .IsAdd }}
// 请在 {{.Package}} 包的 enter.go 文件中的 ProviderSet 添加以下内容:
// New{{.StructName}}Repo,
{{- else }}
package {{.Package}}
import "github.com/google/wire"
// ProviderSet is {{.Package}} data providers.
// 包含 {{.Description}} 相关的数据访问层实现
var ProviderSet = wire.NewSet(
New{{.StructName}}Repo,
)
{{- end }}
+86
View File
@@ -0,0 +1,86 @@
{{- if .IsAdd}}
// 在 model.{{.StructName}} 结构体中新增如下字段
{{- range .Fields}}
{{ GenerateModelField . }}
{{- end }}
{{ else }}
// Code generated by KRA AutoCode. DO NOT EDIT.
// 自动生成模板 {{.StructName}}
package model
import (
{{- if .GvaModel }}
"time"
"gorm.io/gorm"
{{- else }}
{{- if or .HasTimer }}
"time"
{{- end }}
{{- if .NeedJSON }}
"gorm.io/datatypes"
{{- end }}
{{- end }}
)
const TableName{{.StructName}} = "{{.TableName}}"
// {{.StructName}} {{.Description}}
// mapped from table <{{.TableName}}>
type {{.StructName}} struct {
{{- if .GvaModel }}
ID int64 `gorm:"column:id;type:bigint(20) unsigned;primaryKey;autoIncrement:true" json:"id"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime(3)" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime(3)" json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:datetime(3);index:idx_{{.TableName}}_deleted_at,priority:1" json:"deleted_at"`
{{- else }}
{{- with .PrimaryField}}
{{.FieldName}} int64 `gorm:"column:{{.ColumnName}};type:bigint(20) unsigned;primaryKey;autoIncrement:true" json:"{{.FieldJson}}"` // {{.FieldDesc}}
{{- end}}
{{- end }}
{{- range .Fields}}
{{- if not .PrimaryKey}}
{{ GenerateModelField . }}
{{- end}}
{{- end }}
{{- if .AutoCreateResource }}
CreatedBy int64 `gorm:"column:created_by;type:bigint(20) unsigned;comment:创建者" json:"created_by"` // 创建者
UpdatedBy int64 `gorm:"column:updated_by;type:bigint(20) unsigned;comment:更新者" json:"updated_by"` // 更新者
DeletedBy int64 `gorm:"column:deleted_by;type:bigint(20) unsigned;comment:删除者" json:"deleted_by"` // 删除者
{{- end }}
{{- if .IsTree }}
ParentID int64 `gorm:"column:parent_id;type:bigint(20);comment:父节点ID" json:"parent_id"` // 父节点ID
Children []*{{.StructName}} `gorm:"-" json:"children"` // 子节点
{{- end }}
}
// TableName {{.StructName}}'s table name
func (*{{.StructName}}) TableName() string {
return TableName{{.StructName}}
}
{{- if .IsTree }}
// GetChildren 实现 TreeNode 接口
func (s *{{.StructName}}) GetChildren() []*{{.StructName}} {
return s.Children
}
// SetChildren 实现 TreeNode 接口
func (s *{{.StructName}}) SetChildren(child *{{.StructName}}) {
s.Children = append(s.Children, child)
}
// GetID 实现 TreeNode 接口
func (s *{{.StructName}}) GetID() int {
return int(s.{{- if .GvaModel}}ID{{- else}}{{.PrimaryField.FieldName}}{{- end}})
}
// GetParentID 实现 TreeNode 接口
func (s *{{.StructName}}) GetParentID() int {
return int(s.ParentID)
}
{{- end }}
{{ end }}
@@ -0,0 +1,13 @@
{{- if .IsAdd }}
// 请在 {{.Package}} 包的 enter.go 文件中的 ProviderSet 添加以下内容:
// New{{.StructName}}Handler,
{{- else }}
package {{ .Package }}
import "github.com/google/wire"
// ProviderSet is {{.Package}} handler providers.
// 包含 {{.Description}} 相关的 HTTP 处理器
// Handler 层负责处理 HTTP 请求,调用 Biz 层 Usecase 完成业务逻辑
var ProviderSet = wire.NewSet(New{{.StructName}}Handler)
{{- end }}
@@ -0,0 +1,272 @@
{{- if .IsAdd}}
// 在 {{.StructName}}Handler 中新增如下方法
// 请根据实际需求添加
{{- else}}
package {{.Package}}
import (
{{if not .OnlyTemplate}}
"{{.Module}}/pkg/response"
"{{.Module}}/internal/biz/{{.Package}}"
model "{{.Module}}/internal/data/model/{{.Package}}"
{{- if not .IsTree}}
{{.Package}}Req "{{.Module}}/internal/service/types/{{.Package}}/request"
{{- end }}
"github.com/gin-gonic/gin"
"github.com/go-kratos/kratos/v2/log"
{{- if .AutoCreateResource}}
"{{.Module}}/pkg/utils"
{{- end }}
{{- else}}
"{{.Module}}/pkg/response"
"github.com/gin-gonic/gin"
{{- end}}
)
// {{.StructName}}Handler {{.Description}}处理器
// 负责处理 HTTP 请求,调用 Biz 层 Usecase 完成业务逻辑
type {{.StructName}}Handler struct {
uc *{{.Package}}.{{.StructName}}Usecase
log *log.Helper
}
// New{{.StructName}}Handler 创建{{.Description}}处理器
// @param uc Biz 层 Usecase,包含业务逻辑
// @param logger 日志记录器
func New{{.StructName}}Handler(uc *{{.Package}}.{{.StructName}}Usecase, logger log.Logger) *{{.StructName}}Handler {
return &{{.StructName}}Handler{
uc: uc,
log: log.NewHelper(logger),
}
}
{{if not .OnlyTemplate}}
// Create{{.StructName}} 创建{{.Description}}
// @Tags {{.StructName}}
// @Summary 创建{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "创建{{.Description}}"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /{{.Abbreviation}}/create{{.StructName}} [post]
func (h *{{.StructName}}Handler) Create{{.StructName}}(c *gin.Context) {
ctx := c.Request.Context()
var {{.Abbreviation}} model.{{.StructName}}
if err := c.ShouldBindJSON(&{{.Abbreviation}}); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
{{- if .AutoCreateResource }}
{{.Abbreviation}}.CreatedBy = utils.GetUserID(c)
{{- end }}
// 调用 Biz 层 Usecase 创建实体
if err := h.uc.Create(ctx, &{{.Abbreviation}}); err != nil {
h.log.WithContext(ctx).Errorf("创建失败: %v", err)
response.FailWithMessage("创建失败: "+err.Error(), c)
return
}
response.OkWithMessage("创建成功", c)
}
// Delete{{.StructName}} 删除{{.Description}}
// @Tags {{.StructName}}
// @Summary 删除{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "删除{{.Description}}"
// @Success 200 {object} response.Response{msg=string} "删除成功"
// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete]
func (h *{{.StructName}}Handler) Delete{{.StructName}}(c *gin.Context) {
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}} := c.Query("{{.PrimaryField.FieldJson}}")
{{- if .AutoCreateResource }}
userID := utils.GetUserID(c)
{{- end }}
// 调用 Biz 层 Usecase 删除实体
if err := h.uc.Delete(ctx, {{.PrimaryField.FieldJson}}{{- if .AutoCreateResource -}}, userID{{- end -}}); err != nil {
h.log.WithContext(ctx).Errorf("删除失败: %v", err)
response.FailWithMessage("删除失败: "+err.Error(), c)
return
}
response.OkWithMessage("删除成功", c)
}
// Delete{{.StructName}}ByIds 批量删除{{.Description}}
// @Tags {{.StructName}}
// @Summary 批量删除{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param {{.PrimaryField.FieldJson}}s query []{{.PrimaryField.FieldType}} true "批量删除{{.Description}}"
// @Success 200 {object} response.Response{msg=string} "批量删除成功"
// @Router /{{.Abbreviation}}/delete{{.StructName}}ByIds [delete]
func (h *{{.StructName}}Handler) Delete{{.StructName}}ByIds(c *gin.Context) {
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}}s := c.QueryArray("{{.PrimaryField.FieldJson}}s[]")
{{- if .AutoCreateResource }}
userID := utils.GetUserID(c)
{{- end }}
// 调用 Biz 层 Usecase 批量删除实体
if err := h.uc.DeleteByIds(ctx, {{.PrimaryField.FieldJson}}s{{- if .AutoCreateResource }}, userID{{- end }}); err != nil {
h.log.WithContext(ctx).Errorf("批量删除失败: %v", err)
response.FailWithMessage("批量删除失败: "+err.Error(), c)
return
}
response.OkWithMessage("批量删除成功", c)
}
// Update{{.StructName}} 更新{{.Description}}
// @Tags {{.StructName}}
// @Summary 更新{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "更新{{.Description}}"
// @Success 200 {object} response.Response{msg=string} "更新成功"
// @Router /{{.Abbreviation}}/update{{.StructName}} [put]
func (h *{{.StructName}}Handler) Update{{.StructName}}(c *gin.Context) {
ctx := c.Request.Context()
var {{.Abbreviation}} model.{{.StructName}}
if err := c.ShouldBindJSON(&{{.Abbreviation}}); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
{{- if .AutoCreateResource }}
{{.Abbreviation}}.UpdatedBy = utils.GetUserID(c)
{{- end }}
// 调用 Biz 层 Usecase 更新实体
if err := h.uc.Update(ctx, &{{.Abbreviation}}); err != nil {
h.log.WithContext(ctx).Errorf("更新失败: %v", err)
response.FailWithMessage("更新失败: "+err.Error(), c)
return
}
response.OkWithMessage("更新成功", c)
}
// Find{{.StructName}} 用id查询{{.Description}}
// @Tags {{.StructName}}
// @Summary 用id查询{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param {{.PrimaryField.FieldJson}} query {{.PrimaryField.FieldType}} true "用id查询{{.Description}}"
// @Success 200 {object} response.Response{data=model.{{.StructName}},msg=string} "查询成功"
// @Router /{{.Abbreviation}}/find{{.StructName}} [get]
func (h *{{.StructName}}Handler) Find{{.StructName}}(c *gin.Context) {
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}} := c.Query("{{.PrimaryField.FieldJson}}")
// 调用 Biz 层 Usecase 查询实体
re{{.Abbreviation}}, err := h.uc.FindByID(ctx, {{.PrimaryField.FieldJson}})
if err != nil {
h.log.WithContext(ctx).Errorf("查询失败: %v", err)
response.FailWithMessage("查询失败: "+err.Error(), c)
return
}
response.OkWithData(re{{.Abbreviation}}, c)
}
{{- if .IsTree }}
// Get{{.StructName}}List 获取{{.Description}}列表(树形结构)
// @Tags {{.StructName}}
// @Summary 获取{{.Description}}列表(树形结构)
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func (h *{{.StructName}}Handler) Get{{.StructName}}List(c *gin.Context) {
ctx := c.Request.Context()
// 调用 Biz 层 Usecase 获取树形列表
list, err := h.uc.List(ctx)
if err != nil {
h.log.WithContext(ctx).Errorf("获取失败: %v", err)
response.FailWithMessage("获取失败: "+err.Error(), c)
return
}
response.OkWithDetailed(list, "获取成功", c)
}
{{- else }}
// Get{{.StructName}}List 分页获取{{.Description}}列表
// @Tags {{.StructName}}
// @Summary 分页获取{{.Description}}列表
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query {{.Package}}Req.{{.StructName}}Search true "分页获取{{.Description}}列表"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func (h *{{.StructName}}Handler) Get{{.StructName}}List(c *gin.Context) {
ctx := c.Request.Context()
var pageInfo {{.Package}}Req.{{.StructName}}Search
if err := c.ShouldBindQuery(&pageInfo); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
// 调用 Biz 层 Usecase 获取分页列表
list, total, err := h.uc.List(ctx, &pageInfo)
if err != nil {
h.log.WithContext(ctx).Errorf("获取失败: %v", err)
response.FailWithMessage("获取失败: "+err.Error(), c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
{{- end }}
{{- if .HasDataSource }}
// Get{{.StructName}}DataSource 获取{{.StructName}}的数据源
// @Tags {{.StructName}}
// @Summary 获取{{.StructName}}的数据源
// @Accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=object,msg=string} "查询成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}DataSource [get]
func (h *{{.StructName}}Handler) Get{{.StructName}}DataSource(c *gin.Context) {
ctx := c.Request.Context()
// 调用 Biz 层 Usecase 获取数据源
dataSource, err := h.uc.GetDataSource(ctx)
if err != nil {
h.log.WithContext(ctx).Errorf("查询失败: %v", err)
response.FailWithMessage("查询失败: "+err.Error(), c)
return
}
response.OkWithData(dataSource, c)
}
{{- end }}
{{- end }}
// Get{{.StructName}}Public 不需要鉴权的{{.Description}}接口
// @Tags {{.StructName}}
// @Summary 不需要鉴权的{{.Description}}接口
// @Accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
func (h *{{.StructName}}Handler) Get{{.StructName}}Public(c *gin.Context) {
ctx := c.Request.Context()
// 调用 Biz 层 Usecase 获取公开数据
h.uc.GetPublic(ctx)
response.OkWithDetailed(gin.H{
"info": "不需要鉴权的{{.Description}}接口信息",
}, "获取成功", c)
}
{{- end }}
@@ -0,0 +1,75 @@
{{- if .IsAdd}}
// 在结构体中新增如下字段
{{- range .Fields}}
{{ GenerateField . }}
{{- end }}
{{ else }}
// 自动生成模板{{.StructName}}
package {{.Package}}
{{- if not .OnlyTemplate}}
import (
{{- if .GvaModel }}
"{{.Module}}/internal/data/model"
{{- end }}
{{- if or .HasTimer }}
"time"
{{- end }}
{{- if .NeedJSON }}
"gorm.io/datatypes"
{{- end }}
)
{{- end }}
// {{.Description}} 结构体 {{.StructName}}
type {{.StructName}} struct {
{{- if not .OnlyTemplate}}
{{- if .GvaModel }}
model.KRA_MODEL
{{- end }}
{{- range .Fields}}
{{ GenerateField . }}
{{- end }}
{{- if .AutoCreateResource }}
CreatedBy uint `gorm:"column:created_by;comment:创建者"`
UpdatedBy uint `gorm:"column:updated_by;comment:更新者"`
DeletedBy uint `gorm:"column:deleted_by;comment:删除者"`
{{- end }}
{{- if .IsTree }}
Children []*{{.StructName}} `json:"children" gorm:"-"` //子节点
ParentID int `json:"parentID" gorm:"column:parent_id;comment:父节点"`
{{- end }}
{{- end }}
}
{{ if .TableName }}
// TableName {{.Description}} {{.StructName}}自定义表名 {{.TableName}}
func ({{.StructName}}) TableName() string {
return "{{.TableName}}"
}
{{ end }}
{{if .IsTree }}
// GetChildren 实现TreeNode接口
func (s *{{.StructName}}) GetChildren() []*{{.StructName}} {
return s.Children
}
// SetChildren 实现TreeNode接口
func (s *{{.StructName}}) SetChildren(children *{{.StructName}}) {
s.Children = append(s.Children, children)
}
// GetID 实现TreeNode接口
func (s *{{.StructName}}) GetID() int {
return int({{if not .GvaModel}}*{{- end }}s.{{.PrimaryField.FieldName}})
}
// GetParentID 实现TreeNode接口
func (s *{{.StructName}}) GetParentID() int {
return s.ParentID
}
{{ end }}
{{ end }}
@@ -0,0 +1,39 @@
{{- if .IsAdd}}
// 在结构体中新增如下字段
{{- range .Fields}}
{{- if ne .FieldSearchType ""}}
{{ GenerateSearchField . }}
{{- end}}
{{- end }}
{{- if .NeedSort}}
Sort string `json:"sort" form:"sort"`
Order string `json:"order" form:"order"`
{{- end}}
{{- else }}
package request
import (
{{- if not .OnlyTemplate }}
"{{.Module}}/internal/service/types/common"
{{ if or .HasSearchTimer .GvaModel }}"time"{{ end }}
{{- end }}
)
type {{.StructName}}Search struct{
{{- if not .OnlyTemplate}}
{{- if .GvaModel }}
CreatedAtRange []time.Time `json:"createdAtRange" form:"createdAtRange[]"`
{{- end }}
{{- range .Fields}}
{{- if ne .FieldSearchType ""}}
{{ GenerateSearchField . }}
{{- end}}
{{- end }}
common.PageInfo
{{- if .NeedSort}}
Sort string `json:"sort" form:"sort"`
Order string `json:"order" form:"order"`
{{- end}}
{{- end}}
}
{{- end }}
@@ -0,0 +1,26 @@
{{- if .IsAdd }}
// ==================== Wire Provider 注入说明 ====================
// 请在 {{.Package}} 包的 enter.go 文件中的 ProviderSet 添加以下内容:
// New{{.StructName}}Router,
//
// 同时在 RouterGroup 结构体中添加:
// {{.StructName}}Router
//
// 并在 var 块中添加 handler 引用:
// {{.Abbreviation}}Handler = handler.{{.StructName}}Handler{}
{{- else }}
package {{ .Package }}
import "github.com/google/wire"
// ProviderSet is {{.Package}} router providers.
// 包含 {{.Description}} 相关的路由配置
// 使用 Wire 进行依赖注入
var ProviderSet = wire.NewSet(New{{.StructName}}Router)
// RouterGroup {{.Package}} 路由组
// 包含该包下所有路由的集合
type RouterGroup struct {
{{.StructName}}Router
}
{{- end }}
@@ -0,0 +1,75 @@
package {{.Package}}
import (
{{- if not .OnlyTemplate}}
"{{.Module}}/internal/server/middleware"
{{- else}}
// "{{.Module}}/internal/server/middleware"
{{- end}}
"{{.Module}}/internal/server/handler/{{.Package}}"
"github.com/gin-gonic/gin"
)
// {{.StructName}}Router {{.Description}}路由
// 负责注册 {{.Description}} 相关的 HTTP 路由
type {{.StructName}}Router struct {
handler *{{.Package}}.{{.StructName}}Handler
}
// New{{.StructName}}Router 创建{{.Description}}路由
// @param handler {{.Description}}处理器
func New{{.StructName}}Router(handler *{{.Package}}.{{.StructName}}Handler) *{{.StructName}}Router {
return &{{.StructName}}Router{handler: handler}
}
// Init{{.StructName}}Router 初始化 {{.Description}} 路由信息
// @param Router 需要认证的路由组
// @param PublicRouter 公开路由组(不需要认证)
func (r *{{.StructName}}Router) Init{{.StructName}}Router(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup) {
{{- if not .OnlyTemplate}}
// 需要认证 + 操作记录的路由组(用于写操作:创建、更新、删除)
{{.Abbreviation}}Router := Router.Group("{{.Abbreviation}}").Use(middleware.OperationRecord())
// 需要认证但不记录操作的路由组(用于读操作:查询、列表)
{{.Abbreviation}}RouterWithoutRecord := Router.Group("{{.Abbreviation}}")
{{- else}}
// {{.Abbreviation}}Router := Router.Group("{{.Abbreviation}}").Use(middleware.OperationRecord())
// {{.Abbreviation}}RouterWithoutRecord := Router.Group("{{.Abbreviation}}")
{{- end}}
// 公开路由组(不需要认证)
{{.Abbreviation}}RouterWithoutAuth := PublicRouter.Group("{{.Abbreviation}}")
{{- if not .OnlyTemplate}}
// ==================== 需要认证 + 操作记录的路由 ====================
// 这些路由会记录操作日志,用于审计和追踪
{
{{.Abbreviation}}Router.POST("create{{.StructName}}", r.handler.Create{{.StructName}}) // 新建{{.Description}}
{{.Abbreviation}}Router.DELETE("delete{{.StructName}}", r.handler.Delete{{.StructName}}) // 删除{{.Description}}
{{.Abbreviation}}Router.DELETE("delete{{.StructName}}ByIds", r.handler.Delete{{.StructName}}ByIds) // 批量删除{{.Description}}
{{.Abbreviation}}Router.PUT("update{{.StructName}}", r.handler.Update{{.StructName}}) // 更新{{.Description}}
}
// ==================== 需要认证但不记录操作的路由 ====================
// 这些路由是只读操作,不需要记录操作日志
{
{{.Abbreviation}}RouterWithoutRecord.GET("find{{.StructName}}", r.handler.Find{{.StructName}}) // 根据ID获取{{.Description}}
{{.Abbreviation}}RouterWithoutRecord.GET("get{{.StructName}}List", r.handler.Get{{.StructName}}List) // 获取{{.Description}}列表
}
// ==================== 公开路由(不需要认证) ====================
// 这些路由可以被任何人访问,不需要登录
{
{{- if .HasDataSource}}
{{.Abbreviation}}RouterWithoutAuth.GET("get{{.StructName}}DataSource", r.handler.Get{{.StructName}}DataSource) // 获取{{.Description}}数据源
{{- end}}
{{.Abbreviation}}RouterWithoutAuth.GET("get{{.StructName}}Public", r.handler.Get{{.StructName}}Public) // {{.Description}}开放接口
}
{{- else}}
// ==================== 公开路由(不需要认证) ====================
{
{{- if .HasDataSource}}
{{.Abbreviation}}RouterWithoutAuth.GET("get{{.StructName}}DataSource", r.handler.Get{{.StructName}}DataSource) // 获取{{.Description}}数据源
{{- end}}
{{.Abbreviation}}RouterWithoutAuth.GET("get{{.StructName}}Public", r.handler.Get{{.StructName}}Public) // {{.Description}}开放接口
}
{{- end}}
}
@@ -0,0 +1,16 @@
{{- if .IsAdd }}
// 请在 {{.Package}} 包的 enter.go 文件中的 ProviderSet 添加以下内容:
// New{{.StructName}}Service,
{{- else }}
package {{ .Package }}
import "github.com/google/wire"
// ProviderSet is {{.Package}} service providers.
// 包含 {{.Description}} 相关的服务层实现
// Service 层负责:
// 1. 请求类型转换(Request -> Model)
// 2. 事务管理
// 3. 调用 Biz 层 Usecase 完成业务逻辑
var ProviderSet = wire.NewSet(New{{.StructName}}Service)
{{- end }}
@@ -0,0 +1,245 @@
{{- if .IsAdd}}
// Get{{.StructName}}InfoList 新增搜索语句
{{ GenerateSearchConditions .Fields }}
// Get{{.StructName}}InfoList 新增排序语句 请自行在搜索语句中添加orderMap内容
{{- range .Fields}}
{{- if .Sort}}
orderMap["{{.ColumnName}}"] = true
{{- end}}
{{- end}}
{{- if .HasDataSource }}
// Get{{.StructName}}DataSource()方法新增关联语句
{{range $key, $value := .DataSourceMap}}
{{$key}} := make([]map[string]any, 0)
s.data.DB().Table("{{$value.Table}}"){{- if $value.HasDeletedAt}}.Where("deleted_at IS NULL"){{ end }}.Select("{{$value.Label}} as label,{{$value.Value}} as value").Scan(&{{$key}})
res["{{$key}}"] = {{$key}}
{{- end }}
{{- end }}
{{- else}}
package {{.Package}}
import (
{{- if not .OnlyTemplate }}
"context"
"{{.Module}}/internal/biz/{{.Package}}"
model "{{.Module}}/internal/data/model/{{.Package}}"
{{- if not .IsTree}}
{{.Package}}Req "{{.Module}}/internal/service/types/{{.Package}}/request"
{{- end }}
"github.com/go-kratos/kratos/v2/log"
"gorm.io/gorm"
{{- end }}
)
// {{.StructName}}Service {{.Description}}服务层
// 负责处理请求类型转换、事务管理,并调用 Biz 层 Usecase 完成业务逻辑
type {{.StructName}}Service struct {
uc *{{.Package}}.{{.StructName}}Usecase
db *gorm.DB
log *log.Helper
}
// New{{.StructName}}Service 创建{{.Description}}服务
// @param uc Biz 层 Usecase,包含业务逻辑
// @param db 数据库连接,用于事务管理
// @param logger 日志记录器
func New{{.StructName}}Service(uc *{{.Package}}.{{.StructName}}Usecase, db *gorm.DB, logger log.Logger) *{{.StructName}}Service {
return &{{.StructName}}Service{
uc: uc,
db: db,
log: log.NewHelper(logger),
}
}
{{- if not .OnlyTemplate }}
// Create{{.StructName}} 创建{{.Description}}记录
// @param ctx 上下文
// @param req 创建请求,包含{{.Description}}信息
// @return error 创建失败时返回错误
func (s *{{.StructName}}Service) Create{{.StructName}}(ctx context.Context, req *{{.Package}}Req.{{.StructName}}Request) error {
s.log.WithContext(ctx).Infof("Service: 创建{{.Description}}")
// 请求类型转换:将 Request 转换为 Model
{{.Abbreviation}} := req.To{{.StructName}}()
return s.uc.Create(ctx, {{.Abbreviation}})
}
// Create{{.StructName}}WithModel 使用 Model 创建{{.Description}}记录(兼容 Handler 直接调用)
// @param ctx 上下文
// @param {{.Abbreviation}} {{.Description}}模型
// @return error 创建失败时返回错误
func (s *{{.StructName}}Service) Create{{.StructName}}WithModel(ctx context.Context, {{.Abbreviation}} *model.{{.StructName}}) error {
s.log.WithContext(ctx).Infof("Service: 创建{{.Description}}(Model)")
return s.uc.Create(ctx, {{.Abbreviation}})
}
// Delete{{.StructName}} 删除{{.Description}}记录
// @param ctx 上下文
// @param {{.PrimaryField.FieldJson}} 主键ID
{{- if .AutoCreateResource }}
// @param userID 操作用户ID
{{- end }}
// @return error 删除失败时返回错误
{{- if .AutoCreateResource }}
// 注意:当启用 AutoCreateResource 时,删除操作使用事务确保 deleted_by 字段更新和删除操作的原子性
{{- end }}
func (s *{{.StructName}}Service) Delete{{.StructName}}(ctx context.Context, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}{{- if .AutoCreateResource -}}, userID uint{{- end -}}) error {
s.log.WithContext(ctx).Infof("Service: 删除{{.Description}}, {{.PrimaryField.FieldJson}}: %v", {{.PrimaryField.FieldJson}})
{{- if .AutoCreateResource }}
// 使用事务确保 deleted_by 更新和删除操作的原子性
return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// 先更新 deleted_by 字段
if err := tx.Model(&model.{{.StructName}}{}).Where("{{.PrimaryField.ColumnName}} = ?", {{.PrimaryField.FieldJson}}).Update("deleted_by", userID).Error; err != nil {
s.log.WithContext(ctx).Errorf("更新 deleted_by 失败: %v", err)
return err
}
// 再执行删除
return s.uc.DeleteWithTx(ctx, tx, {{.PrimaryField.FieldJson}})
})
{{- else }}
return s.uc.Delete(ctx, {{.PrimaryField.FieldJson}})
{{- end }}
}
// Delete{{.StructName}}ByIds 批量删除{{.Description}}记录
// @param ctx 上下文
// @param {{.PrimaryField.FieldJson}}s 主键ID列表
{{- if .AutoCreateResource }}
// @param deletedBy 操作用户ID
{{- end }}
// @return error 删除失败时返回错误
{{- if .AutoCreateResource }}
// 注意:当启用 AutoCreateResource 时,批量删除操作使用事务确保 deleted_by 字段更新和删除操作的原子性
{{- end }}
func (s *{{.StructName}}Service) Delete{{.StructName}}ByIds(ctx context.Context, {{.PrimaryField.FieldJson}}s []{{.PrimaryField.FieldType}}{{- if .AutoCreateResource }}, deletedBy uint{{- end}}) error {
s.log.WithContext(ctx).Infof("Service: 批量删除{{.Description}}, 数量: %d", len({{.PrimaryField.FieldJson}}s))
{{- if .AutoCreateResource }}
// 使用事务确保 deleted_by 更新和删除操作的原子性
return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// 先批量更新 deleted_by 字段
if err := tx.Model(&model.{{.StructName}}{}).Where("{{.PrimaryField.ColumnName}} in ?", {{.PrimaryField.FieldJson}}s).Update("deleted_by", deletedBy).Error; err != nil {
s.log.WithContext(ctx).Errorf("批量更新 deleted_by 失败: %v", err)
return err
}
// 再执行批量删除
return s.uc.DeleteByIdsWithTx(ctx, tx, {{.PrimaryField.FieldJson}}s)
})
{{- else }}
return s.uc.DeleteByIds(ctx, {{.PrimaryField.FieldJson}}s)
{{- end }}
}
// Update{{.StructName}} 更新{{.Description}}记录
// @param ctx 上下文
// @param req 更新请求,包含{{.Description}}信息
// @return error 更新失败时返回错误
func (s *{{.StructName}}Service) Update{{.StructName}}(ctx context.Context, req *{{.Package}}Req.{{.StructName}}Request) error {
s.log.WithContext(ctx).Infof("Service: 更新{{.Description}}")
// 请求类型转换:将 Request 转换为 Model
{{.Abbreviation}} := req.To{{.StructName}}()
return s.uc.Update(ctx, {{.Abbreviation}})
}
// Update{{.StructName}}WithModel 使用 Model 更新{{.Description}}记录(兼容 Handler 直接调用)
// @param ctx 上下文
// @param {{.Abbreviation}} {{.Description}}模型
// @return error 更新失败时返回错误
func (s *{{.StructName}}Service) Update{{.StructName}}WithModel(ctx context.Context, {{.Abbreviation}} *model.{{.StructName}}) error {
s.log.WithContext(ctx).Infof("Service: 更新{{.Description}}(Model)")
return s.uc.Update(ctx, {{.Abbreviation}})
}
// Get{{.StructName}} 根据{{.PrimaryField.FieldJson}}获取{{.Description}}记录
// @param ctx 上下文
// @param {{.PrimaryField.FieldJson}} 主键ID
// @return *model.{{.StructName}} {{.Description}}记录
// @return error 查询失败时返回错误
func (s *{{.StructName}}Service) Get{{.StructName}}(ctx context.Context, {{.PrimaryField.FieldJson}} {{.PrimaryField.FieldType}}) (*model.{{.StructName}}, error) {
s.log.WithContext(ctx).Debugf("Service: 查询{{.Description}}, {{.PrimaryField.FieldJson}}: %v", {{.PrimaryField.FieldJson}})
return s.uc.FindByID(ctx, {{.PrimaryField.FieldJson}})
}
{{- if .IsTree }}
// Get{{.StructName}}InfoList 获取{{.Description}}列表(树形结构)
// @param ctx 上下文
// @return []*model.{{.StructName}} {{.Description}}列表
// @return error 查询失败时返回错误
func (s *{{.StructName}}Service) Get{{.StructName}}InfoList(ctx context.Context) ([]*model.{{.StructName}}, error) {
s.log.WithContext(ctx).Debug("Service: 获取{{.Description}}树形列表")
return s.uc.List(ctx)
}
{{- else }}
// Get{{.StructName}}InfoList 分页获取{{.Description}}列表
// @param ctx 上下文
// @param info 搜索条件,包含分页和筛选参数
// @return []*model.{{.StructName}} {{.Description}}列表
// @return int64 总记录数
// @return error 查询失败时返回错误
func (s *{{.StructName}}Service) Get{{.StructName}}InfoList(ctx context.Context, info *{{.Package}}Req.{{.StructName}}Search) ([]*model.{{.StructName}}, int64, error) {
s.log.WithContext(ctx).Debugf("Service: 获取{{.Description}}列表, 页码: %d, 每页: %d", info.Page, info.PageSize)
return s.uc.List(ctx, info)
}
{{- end }}
{{- if .HasDataSource }}
// Get{{.StructName}}DataSource 获取{{.StructName}}的数据源
// @param ctx 上下文
// @return map[string][]map[string]any 数据源映射
// @return error 查询失败时返回错误
func (s *{{.StructName}}Service) Get{{.StructName}}DataSource(ctx context.Context) (map[string][]map[string]any, error) {
s.log.WithContext(ctx).Debug("Service: 获取{{.Description}}数据源")
return s.uc.GetDataSource(ctx)
}
{{- end }}
// BatchCreate{{.StructName}} 批量创建{{.Description}}记录(带事务)
// @param ctx 上下文
// @param reqs 创建请求列表
// @return error 创建失败时返回错误,事务会自动回滚
func (s *{{.StructName}}Service) BatchCreate{{.StructName}}(ctx context.Context, reqs []*{{.Package}}Req.{{.StructName}}Request) error {
s.log.WithContext(ctx).Infof("Service: 批量创建{{.Description}}, 数量: %d", len(reqs))
return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
for _, req := range reqs {
{{.Abbreviation}} := req.To{{.StructName}}()
if err := s.uc.Create(ctx, {{.Abbreviation}}); err != nil {
s.log.WithContext(ctx).Errorf("批量创建{{.Description}}失败: %v", err)
return err
}
}
return nil
})
}
// BatchUpdate{{.StructName}} 批量更新{{.Description}}记录(带事务)
// @param ctx 上下文
// @param reqs 更新请求列表
// @return error 更新失败时返回错误,事务会自动回滚
func (s *{{.StructName}}Service) BatchUpdate{{.StructName}}(ctx context.Context, reqs []*{{.Package}}Req.{{.StructName}}Request) error {
s.log.WithContext(ctx).Infof("Service: 批量更新{{.Description}}, 数量: %d", len(reqs))
return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
for _, req := range reqs {
{{.Abbreviation}} := req.To{{.StructName}}()
if err := s.uc.Update(ctx, {{.Abbreviation}}); err != nil {
s.log.WithContext(ctx).Errorf("批量更新{{.Description}}失败: %v", err)
return err
}
}
return nil
})
}
{{- end }}
// Get{{.StructName}}Public 获取公开数据
// @param ctx 上下文
func (s *{{.StructName}}Service) Get{{.StructName}}Public(ctx context.Context) {
s.log.WithContext(ctx).Debug("Service: 获取{{.Description}}公开数据")
s.uc.GetPublic(ctx)
}
{{- end }}
@@ -0,0 +1,214 @@
{{- if .IsAdd}}
// 在 {{.StructName}}Search 结构体中新增如下字段
{{- range .Fields}}
{{- if .FieldSearchType}}
{{ GenerateSearchField . }}
{{- end}}
{{- end}}
// 在 {{.StructName}}ListRequest 结构体中新增如下字段
{{- range .Fields}}
{{- if .FieldSearchType}}
{{ GenerateSearchField . }}
{{- end}}
{{- end}}
// 在 {{.StructName}}Request 结构体中新增如下字段
{{- range .Fields}}
{{- if not .PrimaryKey}}
{{.FieldName}} {{.FieldType}} `json:"{{.FieldJson}}"{{if .Require}} binding:"required"{{end}}` // {{.FieldDesc}}
{{- end}}
{{- end}}
// 在 To{{.StructName}}() 方法中新增如下字段映射
{{- range .Fields}}
{{- if not .PrimaryKey}}
// {{.FieldName}}: r.{{.FieldName}},
{{- end}}
{{- end}}
// 在 From{{.StructName}}() 函数中新增如下字段映射
{{- range .Fields}}
{{- if not .PrimaryKey}}
// {{.FieldName}}: m.{{.FieldName}},
{{- end}}
{{- end}}
{{- else}}
package request
import (
{{- if .HasTimer }}
"time"
{{- end }}
{{- if .NeedJSON }}
"gorm.io/datatypes"
{{- end }}
model "{{.Module}}/internal/data/model/{{.Package}}"
"{{.Module}}/internal/service/types/common"
)
// {{.StructName}}Request {{.Description}}创建/更新请求
type {{.StructName}}Request struct {
{{- if .GvaModel }}
ID uint `json:"id"` // 主键ID
{{- else }}
{{.PrimaryField.FieldName}} {{.PrimaryField.FieldType}} `json:"{{.PrimaryField.FieldJson}}"` // {{.PrimaryField.FieldDesc}}
{{- end }}
{{- range .Fields}}
{{- if not .PrimaryKey}}
{{.FieldName}} {{.FieldType}} `json:"{{.FieldJson}}"{{if .Require}} binding:"required"{{end}}` // {{.FieldDesc}}
{{- end}}
{{- end}}
{{- if .AutoCreateResource }}
CreatedBy uint `json:"createdBy"` // 创建者
UpdatedBy uint `json:"updatedBy"` // 更新者
{{- end }}
}
// To{{.StructName}} 将请求转换为{{.Description}}模型
// 用于 Service 层进行请求类型转换
func (r *{{.StructName}}Request) To{{.StructName}}() *model.{{.StructName}} {
return &model.{{.StructName}}{
{{- if .GvaModel }}
KRA_MODEL: model.KRA_MODEL{ID: r.ID},
{{- else }}
{{.PrimaryField.FieldName}}: r.{{.PrimaryField.FieldName}},
{{- end }}
{{- range .Fields}}
{{- if not .PrimaryKey}}
{{.FieldName}}: r.{{.FieldName}},
{{- end}}
{{- end}}
{{- if .AutoCreateResource }}
CreatedBy: r.CreatedBy,
UpdatedBy: r.UpdatedBy,
{{- end }}
}
}
// From{{.StructName}} 从{{.Description}}模型创建请求
// 用于编辑场景,将数据库模型转换为请求格式
func From{{.StructName}}(m *model.{{.StructName}}) *{{.StructName}}Request {
if m == nil {
return nil
}
return &{{.StructName}}Request{
{{- if .GvaModel }}
ID: m.ID,
{{- else }}
{{.PrimaryField.FieldName}}: m.{{.PrimaryField.FieldName}},
{{- end }}
{{- range .Fields}}
{{- if not .PrimaryKey}}
{{.FieldName}}: m.{{.FieldName}},
{{- end}}
{{- end}}
{{- if .AutoCreateResource }}
CreatedBy: m.CreatedBy,
UpdatedBy: m.UpdatedBy,
{{- end }}
}
}
// {{.StructName}}IDRequest {{.Description}}ID请求
type {{.StructName}}IDRequest struct {
{{- if .GvaModel }}
ID int `json:"id" form:"id" binding:"required"` // 主键ID
{{- else }}
{{.PrimaryField.FieldName}} {{.PrimaryField.FieldType}} `json:"{{.PrimaryField.FieldJson}}" form:"{{.PrimaryField.FieldJson}}" binding:"required"` // {{.PrimaryField.FieldDesc}}
{{- end }}
}
// Uint 转换为uint类型
// 用于与数据库操作兼容
func (r *{{.StructName}}IDRequest) Uint() uint {
{{- if .GvaModel }}
return uint(r.ID)
{{- else }}
return uint(r.{{.PrimaryField.FieldName}})
{{- end }}
}
// {{.StructName}}IdsRequest {{.Description}}批量ID请求
type {{.StructName}}IdsRequest struct {
{{- if .GvaModel }}
Ids []int `json:"ids" form:"ids" binding:"required"` // 主键ID列表
{{- else }}
{{.PrimaryField.FieldName}}s []{{.PrimaryField.FieldType}} `json:"{{.PrimaryField.FieldJson}}s" form:"{{.PrimaryField.FieldJson}}s" binding:"required"` // {{.PrimaryField.FieldDesc}}列表
{{- end }}
}
// Uints 转换为[]uint类型
// 用于与数据库批量操作兼容
func (r *{{.StructName}}IdsRequest) Uints() []uint {
{{- if .GvaModel }}
result := make([]uint, len(r.Ids))
for i, id := range r.Ids {
result[i] = uint(id)
}
return result
{{- else }}
result := make([]uint, len(r.{{.PrimaryField.FieldName}}s))
for i, id := range r.{{.PrimaryField.FieldName}}s {
result[i] = uint(id)
}
return result
{{- end }}
}
// {{.StructName}}Search {{.Description}}搜索条件
// Deprecated: 请使用 {{.StructName}}ListRequest
type {{.StructName}}Search struct {
common.PageInfo
{{- if .GvaModel }}
CreatedAtRange []time.Time `json:"createdAtRange" form:"createdAtRange[]"` // 创建时间范围
{{- end }}
{{- range .Fields}}
{{- if .FieldSearchType}}
{{ GenerateSearchField . }}
{{- end}}
{{- end}}
{{- if .NeedSort}}
Sort string `json:"sort" form:"sort"` // 排序字段
Order string `json:"order" form:"order"` // 排序方式
{{- end}}
}
// {{.StructName}}ListRequest {{.Description}}列表请求(含分页)
type {{.StructName}}ListRequest struct {
common.PageInfo
{{- if .GvaModel }}
CreatedAtRange []time.Time `json:"createdAtRange" form:"createdAtRange[]"` // 创建时间范围
{{- end }}
{{- range .Fields}}
{{- if .FieldSearchType}}
{{ GenerateSearchField . }}
{{- end}}
{{- end}}
{{- if .NeedSort}}
Sort string `json:"sort" form:"sort"` // 排序字段
Order string `json:"order" form:"order"` // 排序方式
{{- end}}
}
// To{{.StructName}}Search 将列表请求转换为搜索条件
// 用于向后兼容
func (r *{{.StructName}}ListRequest) To{{.StructName}}Search() *{{.StructName}}Search {
return &{{.StructName}}Search{
PageInfo: r.PageInfo,
{{- if .GvaModel }}
CreatedAtRange: r.CreatedAtRange,
{{- end }}
{{- range .Fields}}
{{- if .FieldSearchType}}
{{.FieldName}}: r.{{.FieldName}},
{{- end}}
{{- end}}
{{- if .NeedSort}}
Sort: r.Sort,
Order: r.Order,
{{- end}}
}
}
{{- end }}
+130
View File
@@ -0,0 +1,130 @@
import service from '@/utils/request'
{{- if not .OnlyTemplate}}
// @Tags {{.StructName}}
// @Summary 创建{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "创建{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /{{.Abbreviation}}/create{{.StructName}} [post]
export const create{{.StructName}} = (data) => {
return service({
url: '/{{.Abbreviation}}/create{{.StructName}}',
method: 'post',
data
})
}
// @Tags {{.StructName}}
// @Summary 删除{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "删除{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete]
export const delete{{.StructName}} = (params) => {
return service({
url: '/{{.Abbreviation}}/delete{{.StructName}}',
method: 'delete',
params
})
}
// @Tags {{.StructName}}
// @Summary 批量删除{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete]
export const delete{{.StructName}}ByIds = (params) => {
return service({
url: '/{{.Abbreviation}}/delete{{.StructName}}ByIds',
method: 'delete',
params
})
}
// @Tags {{.StructName}}
// @Summary 更新{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "更新{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /{{.Abbreviation}}/update{{.StructName}} [put]
export const update{{.StructName}} = (data) => {
return service({
url: '/{{.Abbreviation}}/update{{.StructName}}',
method: 'put',
data
})
}
// @Tags {{.StructName}}
// @Summary 用id查询{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query model.{{.StructName}} true "用id查询{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /{{.Abbreviation}}/find{{.StructName}} [get]
export const find{{.StructName}} = (params) => {
return service({
url: '/{{.Abbreviation}}/find{{.StructName}}',
method: 'get',
params
})
}
// @Tags {{.StructName}}
// @Summary 分页获取{{.Description}}列表
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query request.PageInfo true "分页获取{{.Description}}列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
export const get{{.StructName}}List = (params) => {
return service({
url: '/{{.Abbreviation}}/get{{.StructName}}List',
method: 'get',
params
})
}
{{- if .HasDataSource}}
// @Tags {{.StructName}}
// @Summary 获取数据源
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /{{.Abbreviation}}/find{{.StructName}}DataSource [get]
export const get{{.StructName}}DataSource = () => {
return service({
url: '/{{.Abbreviation}}/get{{.StructName}}DataSource',
method: 'get',
})
}
{{- end}}
{{- end}}
// @Tags {{.StructName}}
// @Summary 不需要鉴权的{{.Description}}接口
// @Accept application/json
// @Produce application/json
// @Param data query {{.Package}}Req.{{.StructName}}Search true "分页获取{{.Description}}列表"
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
export const get{{.StructName}}Public = () => {
return service({
url: '/{{.Abbreviation}}/get{{.StructName}}Public',
method: 'get',
})
}
+200
View File
@@ -0,0 +1,200 @@
{{- $global := . }}
{{- if .IsAdd }}
// ============ 详情组件新增字段配置 ============
// 详情新增字段
{{- range .Fields}}
{{- if .Desc }}
{{ GenerateReactDescriptionItem . }}
{{- end }}
{{- end }}
{{- else }}
{{- if not .OnlyTemplate}}
/**
* KRA - {{.Description}}详情组件
* Auto-generated by KRA AutoCode
*/
import React, { useEffect, useState } from 'react';
import {
Drawer,
Descriptions,
Spin,
message,
Tag,
{{- if .HasPic }}
Image,
{{- end }}
{{- if .IsTree }}
TreeSelect,
{{- end }}
} from 'antd';
import { find{{.StructName}} } from '@/services/kratos/{{.PackageName}}';
import type { {{.StructName}} } from '@/services/kratos/{{.PackageName}}';
{{- if .DictTypes }}
import { useDictionary } from '@/hooks/useDictionary';
{{- end }}
{{- if .HasDataSource }}
import { get{{.StructName}}DataSource } from '@/services/kratos/{{.PackageName}}';
{{- end }}
import dayjs from 'dayjs';
interface {{.StructName}}DetailProps {
visible: boolean;
record?: {{.StructName}} | null;
onClose: () => void;
{{- if .IsTree }}
treeData?: {{.StructName}}[];
{{- end }}
}
const {{.StructName}}Detail: React.FC<{{.StructName}}DetailProps> = ({
visible,
record,
onClose,
{{- if .IsTree }}
treeData = [],
{{- end }}
}) => {
const [loading, setLoading] = useState(false);
const [currentRecord, setCurrentRecord] = useState<{{.StructName}} | null>(null);
{{- if .HasDataSource }}
const [dataSource, setDataSource] = useState<Record<string, Array<{ label: string; value: any }>>>({});
{{- end }}
{{- if .DictTypes }}
// 字典数据
{{- range $index, $element := .DictTypes}}
const { getLabel: get{{$element | toPascalCase}}Label } = useDictionary('{{$element}}');
{{- end }}
{{- end }}
{{- if .HasDataSource }}
// 获取数据源
const fetchDataSource = async () => {
try {
const res = await get{{.StructName}}DataSource();
if (res.code === 0) {
setDataSource(res.data || {});
}
} catch (error) {
console.error('获取数据源失败:', error);
}
};
{{- end }}
// 获取详情数据
const fetchDetail = async (id: {{ GenerateTSType .PrimaryField.FieldType }}) => {
setLoading(true);
try {
const res = await find{{.StructName}}({ {{.PrimaryField.FieldJson}}: id });
if (res.code === 0 && res.data) {
setCurrentRecord(res.data);
} else {
message.error(res.msg || '获取详情失败');
}
} catch (error) {
message.error('获取详情失败');
} finally {
setLoading(false);
}
};
useEffect(() => {
if (visible && record?.{{.PrimaryField.FieldJson}}) {
{{- if .HasDataSource }}
fetchDataSource();
{{- end }}
fetchDetail(record.{{.PrimaryField.FieldJson}});
}
}, [visible, record]);
// 关闭抽屉
const handleClose = () => {
setCurrentRecord(null);
onClose();
};
return (
<Drawer
title="{{.Description}}详情"
open={visible}
onClose={handleClose}
width={600}
destroyOnClose
>
<Spin spinning={loading}>
{currentRecord && (
<Descriptions column={1} bordered>
{{- if .IsTree }}
<Descriptions.Item label="父节点">
<TreeSelect
value={currentRecord.parentID}
treeData={[{ {{.PrimaryField.FieldJson}}: 0, {{.TreeJson}}: '根节点', children: treeData }]}
fieldNames={{ "{{" }} label: '{{.TreeJson}}', value: '{{.PrimaryField.FieldJson}}', children: 'children' {{ "}}" }}
disabled
style={{ "{{" }} width: '100%' {{ "}}" }}
placeholder="根节点"
/>
</Descriptions.Item>
{{- end }}
{{- range .Fields}}
{{- if .Desc }}
{{ GenerateReactDescriptionItem . }}
{{- end }}
{{- end }}
{{- if .GvaModel }}
<Descriptions.Item label="创建时间">
{currentRecord.CreatedAt ? dayjs(currentRecord.CreatedAt).format('YYYY-MM-DD HH:mm:ss') : '-'}
</Descriptions.Item>
<Descriptions.Item label="更新时间">
{currentRecord.UpdatedAt ? dayjs(currentRecord.UpdatedAt).format('YYYY-MM-DD HH:mm:ss') : '-'}
</Descriptions.Item>
{{- end }}
</Descriptions>
)}
</Spin>
</Drawer>
);
};
export default {{.StructName}}Detail;
{{- else}}
/**
* KRA - {{.Description}}详情组件
* Auto-generated by KRA AutoCode
*/
import React from 'react';
import { Drawer, Descriptions } from 'antd';
interface {{.StructName}}DetailProps {
visible: boolean;
record?: any;
onClose: () => void;
}
const {{.StructName}}Detail: React.FC<{{.StructName}}DetailProps> = ({
visible,
record,
onClose,
}) => {
return (
<Drawer
title="{{.Description}}详情"
open={visible}
onClose={onClose}
width={600}
destroyOnClose
>
{record && (
<Descriptions column={1} bordered>
{/* 详情字段 */}
</Descriptions>
)}
</Drawer>
);
};
export default {{.StructName}}Detail;
{{- end }}
{{- end }}
+254
View File
@@ -0,0 +1,254 @@
{{- $global := . }}
{{- if .IsAdd }}
// ============ 表单组件新增字段配置 ============
// 表单新增字段
{{- range .Fields}}
{{- if .Form}}
{{ GenerateReactFormItem . }}
{{- end }}
{{- end }}
{{- else }}
{{- if not .OnlyTemplate}}
/**
* KRA - {{.Description}}表单组件
* Auto-generated by KRA AutoCode
*/
import React, { useEffect, useState } from 'react';
import {
Modal,
Form,
Input,
message,
{{- if .HasTimer }}
DatePicker,
{{- end }}
{{- if or .DictTypes .HasDataSource }}
Select,
{{- end }}
{{- if .HasBool }}
Switch,
{{- end }}
{{- if .HasNumber }}
InputNumber,
{{- end }}
{{- if .IsTree }}
TreeSelect,
{{- end }}
} from 'antd';
import type { FormInstance } from 'antd/es/form';
import {
create{{.StructName}},
update{{.StructName}},
find{{.StructName}},
{{- if .HasDataSource }}
get{{.StructName}}DataSource,
{{- end }}
} from '@/services/kratos/{{.PackageName}}';
import type { {{.StructName}} } from '@/services/kratos/{{.PackageName}}';
{{- if .DictTypes }}
import { useDictionary } from '@/hooks/useDictionary';
{{- end }}
interface {{.StructName}}FormProps {
visible: boolean;
type: 'create' | 'edit';
record?: {{.StructName}} | null;
onClose: () => void;
onSuccess: () => void;
{{- if .IsTree }}
treeData?: {{.StructName}}[];
{{- end }}
}
const {{.StructName}}Form: React.FC<{{.StructName}}FormProps> = ({
visible,
type,
record,
onClose,
onSuccess,
{{- if .IsTree }}
treeData = [],
{{- end }}
}) => {
const [form] = Form.useForm<FormInstance>();
const [loading, setLoading] = useState(false);
const [detailLoading, setDetailLoading] = useState(false);
{{- if .HasDataSource }}
const [dataSource, setDataSource] = useState<Record<string, Array<{ label: string; value: any }>>>({});
{{- end }}
{{- if .DictTypes }}
// 字典数据
{{- range $index, $element := .DictTypes}}
const { options: {{$element}}Options } = useDictionary('{{$element}}');
{{- end }}
{{- end }}
{{- if .HasDataSource }}
// 获取数据源
const fetchDataSource = async () => {
try {
const res = await get{{.StructName}}DataSource();
if (res.code === 0) {
setDataSource(res.data || {});
}
} catch (error) {
console.error('获取数据源失败:', error);
}
};
{{- end }}
// 获取详情数据
const fetchDetail = async (id: {{ GenerateTSType .PrimaryField.FieldType }}) => {
setDetailLoading(true);
try {
const res = await find{{.StructName}}({ {{.PrimaryField.FieldJson}}: id });
if (res.code === 0 && res.data) {
form.setFieldsValue(res.data);
}
} catch (error) {
message.error('获取详情失败');
} finally {
setDetailLoading(false);
}
};
useEffect(() => {
if (visible) {
{{- if .HasDataSource }}
fetchDataSource();
{{- end }}
if (type === 'edit' && record?.{{.PrimaryField.FieldJson}}) {
fetchDetail(record.{{.PrimaryField.FieldJson}});
} else if (type === 'create') {
form.resetFields();
{{- if .IsTree }}
if (record?.parentID) {
form.setFieldsValue({ parentID: record.parentID });
}
{{- end }}
}
}
}, [visible, type, record]);
// 提交表单
const handleSubmit = async () => {
try {
const values = await form.validateFields();
setLoading(true);
const submitData = type === 'edit'
? { ...record, ...values }
: values;
const res = type === 'create'
? await create{{.StructName}}(submitData)
: await update{{.StructName}}(submitData);
if (res.code === 0) {
message.success(type === 'create' ? '创建成功' : '更新成功');
handleClose();
onSuccess();
} else {
message.error(res.msg || (type === 'create' ? '创建失败' : '更新失败'));
}
} catch (error) {
// 表单验证失败
} finally {
setLoading(false);
}
};
// 关闭弹窗
const handleClose = () => {
form.resetFields();
onClose();
};
return (
<Modal
title={type === 'create' ? '新增{{.Description}}' : '编辑{{.Description}}'}
open={visible}
onOk={handleSubmit}
onCancel={handleClose}
confirmLoading={loading}
destroyOnClose
width={600}
maskClosable={false}
>
<Form
form={form}
layout="vertical"
disabled={detailLoading}
>
{{- if .IsTree }}
<Form.Item name="parentID" label="父节点">
<TreeSelect
placeholder="请选择父节点"
allowClear
treeData={[{ {{.PrimaryField.FieldJson}}: 0, {{.TreeJson}}: '根节点', children: treeData }]}
fieldNames={{ "{{" }} label: '{{.TreeJson}}', value: '{{.PrimaryField.FieldJson}}', children: 'children' {{ "}}" }}
treeDefaultExpandAll
/>
</Form.Item>
{{- end }}
{{- range .Fields}}
{{- if .Form}}
{{ GenerateReactFormItem . }}
{{- end }}
{{- end }}
</Form>
</Modal>
);
};
export default {{.StructName}}Form;
{{- else}}
/**
* KRA - {{.Description}}表单组件
* Auto-generated by KRA AutoCode
*/
import React from 'react';
import { Modal, Form, Input } from 'antd';
interface {{.StructName}}FormProps {
visible: boolean;
type: 'create' | 'edit';
record?: any;
onClose: () => void;
onSuccess: () => void;
}
const {{.StructName}}Form: React.FC<{{.StructName}}FormProps> = ({
visible,
type,
onClose,
onSuccess,
}) => {
const [form] = Form.useForm();
return (
<Modal
title={type === 'create' ? '新增{{.Description}}' : '编辑{{.Description}}'}
open={visible}
onOk={() => {
form.validateFields().then(() => {
onSuccess();
onClose();
});
}}
onCancel={onClose}
destroyOnClose
>
<Form form={form} layout="vertical">
{/* 表单字段 */}
</Form>
</Modal>
);
};
export default {{.StructName}}Form;
{{- end }}
{{- end }}
+523
View File
@@ -0,0 +1,523 @@
{{- $global := . }}
{{- $templateID := printf "%s_%s" .Package .StructName }}
{{- if .IsAdd }}
// ============ 新增字段配置 ============
// 搜索表单新增字段
{{- range .Fields}}
{{- if .FieldSearchType}}
{{ GenerateReactSearchFormItem . }}
{{- end }}
{{- end }}
// 表格列新增配置
{{- range .Fields}}
{{- if .Table}}
{{ GenerateReactTableColumn . }}
{{- end }}
{{- end }}
// 表单新增字段
{{- range .Fields}}
{{- if .Form}}
{{ GenerateReactFormItem . }}
{{- end }}
{{- end }}
// 详情新增字段
{{- range .Fields}}
{{- if .Desc }}
{{ GenerateReactDescriptionItem . }}
{{- end }}
{{- end }}
{{- else }}
{{- if not .OnlyTemplate}}
/**
* KRA - {{.Description}}管理页面
* Auto-generated by KRA AutoCode
*/
import React, { useState, useRef, useEffect } from 'react';
import { PageContainer, ProTable } from '@ant-design/pro-components';
import type { ActionType, ProColumns } from '@ant-design/pro-components';
import {
Button,
Space,
Modal,
message,
Form,
Input,
Tag,
{{- if .HasTimer }}
DatePicker,
{{- end }}
{{- if or .DictTypes .HasDataSource }}
Select,
{{- end }}
Drawer,
Descriptions,
Popconfirm,
{{- if .HasPic }}
Image,
{{- end }}
{{- if .IsTree }}
TreeSelect,
{{- end }}
{{- if .HasRichText }}
Typography,
{{- end }}
} from 'antd';
import type { FormInstance } from 'antd/es/form';
import {
PlusOutlined,
DeleteOutlined,
EditOutlined,
EyeOutlined,
{{- if .IsTree }}
PlusCircleOutlined,
{{- end }}
} from '@ant-design/icons';
import {
create{{.StructName}},
delete{{.StructName}},
delete{{.StructName}}ByIds,
update{{.StructName}},
find{{.StructName}},
get{{.StructName}}List,
{{- if .HasDataSource }}
get{{.StructName}}DataSource,
{{- end }}
} from '@/services/kratos/{{.PackageName}}';
import type { {{.StructName}} } from '@/services/kratos/{{.PackageName}}';
{{- if .DictTypes }}
import { useDictionary } from '@/hooks/useDictionary';
{{- end }}
import dayjs from 'dayjs';
const {{.StructName}}Page: React.FC = () => {
// 表格操作引用
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>(null);
// 状态定义
const [drawerVisible, setDrawerVisible] = useState(false);
const [drawerType, setDrawerType] = useState<'create' | 'edit'>('create');
const [detailVisible, setDetailVisible] = useState(false);
const [currentRecord, setCurrentRecord] = useState<{{.StructName}} | null>(null);
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [btnLoading, setBtnLoading] = useState(false);
{{- if .HasDataSource }}
const [dataSource, setDataSource] = useState<Record<string, Array<{ label: string; value: any }>>>({});
{{- end }}
{{- if .IsTree }}
const [treeData, setTreeData] = useState<{{.StructName}}[]>([]);
{{- end }}
{{- if .DictTypes }}
// 字典数据
{{- range $index, $element := .DictTypes}}
const { options: {{$element}}Options, getLabel: get{{$element | toPascalCase}}Label } = useDictionary('{{$element}}');
{{- end }}
{{- end }}
{{- if .HasDataSource }}
// 获取数据源
const fetchDataSource = async () => {
try {
const res = await get{{.StructName}}DataSource();
if (res.code === 0) {
setDataSource(res.data || {});
}
} catch (error) {
console.error('获取数据源失败:', error);
}
};
useEffect(() => {
fetchDataSource();
}, []);
{{- end }}
// 新增
const handleAdd = ({{- if .IsTree -}}parentRecord?: {{.StructName}}{{- end -}}) => {
setDrawerType('create');
setCurrentRecord({{- if .IsTree -}}parentRecord ? { parentID: parentRecord.{{.PrimaryField.FieldJson}} } as {{.StructName}} : {{- end -}}null);
setDrawerVisible(true);
};
// 编辑
const handleEdit = async (record: {{.StructName}}) => {
try {
const res = await find{{.StructName}}({ {{.PrimaryField.FieldJson}}: record.{{.PrimaryField.FieldJson}}! });
if (res.code === 0) {
setDrawerType('edit');
setCurrentRecord(res.data);
setDrawerVisible(true);
}
} catch (error) {
message.error('获取详情失败');
}
};
// 查看详情
const handleDetail = async (record: {{.StructName}}) => {
try {
const res = await find{{.StructName}}({ {{.PrimaryField.FieldJson}}: record.{{.PrimaryField.FieldJson}}! });
if (res.code === 0) {
setCurrentRecord(res.data);
setDetailVisible(true);
}
} catch (error) {
message.error('获取详情失败');
}
};
// 删除
const handleDelete = async (record: {{.StructName}}) => {
try {
const res = await delete{{.StructName}}({ {{.PrimaryField.FieldJson}}: record.{{.PrimaryField.FieldJson}}! });
if (res.code === 0) {
message.success('删除成功');
actionRef.current?.reload();
} else {
message.error(res.msg || '删除失败');
}
} catch (error) {
message.error('删除失败');
}
};
// 批量删除
const handleBatchDelete = async () => {
if (selectedRowKeys.length === 0) {
message.warning('请选择要删除的数据');
return;
}
Modal.confirm({
title: '确认删除',
content: `确定要删除选中的 ${selectedRowKeys.length} 条数据吗?`,
onOk: async () => {
try {
const res = await delete{{.StructName}}ByIds({ {{.PrimaryField.FieldJson}}s: selectedRowKeys as {{ GenerateTSType .PrimaryField.FieldType }}[] });
if (res.code === 0) {
message.success('删除成功');
setSelectedRowKeys([]);
actionRef.current?.reload();
} else {
message.error(res.msg || '删除失败');
}
} catch (error) {
message.error('删除失败');
}
},
});
};
// 关闭抽屉
const handleDrawerClose = () => {
setDrawerVisible(false);
setCurrentRecord(null);
formRef.current?.resetFields();
};
// 提交表单
const handleSubmit = async () => {
try {
const values = await formRef.current?.validateFields();
setBtnLoading(true);
const submitData = { ...currentRecord, ...values };
const res = drawerType === 'create'
? await create{{.StructName}}(submitData)
: await update{{.StructName}}(submitData);
if (res.code === 0) {
message.success(drawerType === 'create' ? '创建成功' : '更新成功');
handleDrawerClose();
actionRef.current?.reload();
} else {
message.error(res.msg || (drawerType === 'create' ? '创建失败' : '更新失败'));
}
} catch (error) {
// 表单验证失败
} finally {
setBtnLoading(false);
}
};
// 表格列定义
const columns: ProColumns<{{.StructName}}>[] = [
{{- if .GvaModel }}
{
title: '创建时间',
dataIndex: 'CreatedAt',
valueType: 'dateTime',
width: 180,
sorter: true,
hideInSearch: true,
},
{{- end }}
{{- range .Fields}}
{{- if .Table}}
{{ GenerateReactProTableColumn . }}
{{- end }}
{{- end }}
{
title: '操作',
valueType: 'option',
fixed: 'right',
width: {{- if .IsTree -}}280{{- else -}}200{{- end }},
render: (_, record) => [
{{- if .IsTree }}
<Button
key="addChild"
type="link"
size="small"
icon={<PlusCircleOutlined />}
onClick={() => handleAdd(record)}
>
新增子节点
</Button>,
{{- end }}
<Button
key="detail"
type="link"
size="small"
icon={<EyeOutlined />}
onClick={() => handleDetail(record)}
>
查看
</Button>,
<Button
key="edit"
type="link"
size="small"
icon={<EditOutlined />}
onClick={() => handleEdit(record)}
>
编辑
</Button>,
{{- if .IsTree }}
!record.children?.length && (
{{- end }}
<Popconfirm
key="delete"
title="确定删除吗?"
onConfirm={() => handleDelete(record)}
okText="确定"
cancelText="取消"
>
<Button type="link" size="small" danger icon={<DeleteOutlined />}>
删除
</Button>
</Popconfirm>
{{- if .IsTree }}
)
{{- end }},
],
},
];
return (
<PageContainer>
<ProTable<{{.StructName}}>
actionRef={actionRef}
columns={columns}
rowKey="{{.PrimaryField.FieldJson}}"
scroll={{ "{{" }} x: 'max-content' {{ "}}" }}
rowSelection={{
selectedRowKeys,
onChange: (keys) => setSelectedRowKeys(keys),
}}
request={async (params, sort) => {
// 处理排序
const sortKey = Object.keys(sort || {})[0];
let orderKey = '';
if (sortKey) {
// 排序字段映射
const sortMap: Record<string, string> = {
CreatedAt: 'created_at',
ID: 'id',
{{- range .Fields}}
{{- if .Table}}
{{- if .Sort}}
{{- if .ColumnName}}
{{.FieldJson}}: '{{.ColumnName}}',
{{- end}}
{{- end}}
{{- end}}
{{- end}}
};
orderKey = sortMap[sortKey] || sortKey.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
}
try {
const res = await get{{.StructName}}List({
page: params.current || 1,
pageSize: params.pageSize || 10,
{{- range .Fields}}
{{- if .FieldSearchType}}
{{- if eq .FieldSearchType "BETWEEN"}}
start{{.FieldName}}: params.start{{.FieldName}},
end{{.FieldName}}: params.end{{.FieldName}},
{{- else}}
{{.FieldJson}}: params.{{.FieldJson}},
{{- end}}
{{- end }}
{{- end }}
{{- if .GvaModel }}
startCreatedAt: params.startCreatedAt,
endCreatedAt: params.endCreatedAt,
{{- end }}
orderKey: orderKey,
desc: sort?.[sortKey] === 'descend',
});
{{- if .IsTree }}
if (res.code === 0) {
setTreeData(res.data || []);
}
return {
data: res.data || [],
success: res.code === 0,
};
{{- else }}
return {
data: res.data?.list || [],
total: res.data?.total || 0,
success: res.code === 0,
};
{{- end }}
} catch (error) {
return {
data: [],
total: 0,
success: false,
};
}
}}
pagination={{- if .IsTree -}}={false}{{- else -}}={{
defaultPageSize: 10,
showSizeChanger: true,
pageSizeOptions: ['10', '30', '50', '100'],
showTotal: (total) => `共 ${total} 条`,
}}{{- end }}
search={{
labelWidth: 'auto',
collapsed: true,
collapseRender: (collapsed) => (collapsed ? '展开' : '收起'),
defaultCollapsed: true,
span: {{- if .GvaModel -}}6{{- else -}}8{{- end }},
}}
toolBarRender={() => [
<Button
key="add"
type="primary"
icon={<PlusOutlined />}
onClick={() => handleAdd()}
>
新增
</Button>,
<Button
key="delete"
danger
icon={<DeleteOutlined />}
disabled={selectedRowKeys.length === 0}
onClick={handleBatchDelete}
>
批量删除
</Button>,
]}
/>
{/* 新增/编辑抽屉 */}
<Drawer
title={drawerType === 'create' ? '新增{{.Description}}' : '编辑{{.Description}}'}
open={drawerVisible}
onClose={handleDrawerClose}
width={600}
destroyOnClose
extra={
<Space>
<Button onClick={handleDrawerClose}>取消</Button>
<Button type="primary" loading={btnLoading} onClick={handleSubmit}>
确定
</Button>
</Space>
}
>
<Form
ref={formRef}
layout="vertical"
initialValues={currentRecord || {}}
>
{{- if .IsTree }}
<Form.Item name="parentID" label="父节点">
<TreeSelect
placeholder="请选择父节点"
allowClear
treeData={[{ {{.PrimaryField.FieldJson}}: 0, {{.TreeJson}}: '根节点', children: treeData }]}
fieldNames={{ "{{" }} label: '{{.TreeJson}}', value: '{{.PrimaryField.FieldJson}}', children: 'children' {{ "}}" }}
treeDefaultExpandAll
/>
</Form.Item>
{{- end }}
{{- range .Fields}}
{{- if .Form}}
{{ GenerateReactFormItem . }}
{{- end }}
{{- end }}
</Form>
</Drawer>
{/* 详情抽屉 */}
<Drawer
title="{{.Description}}详情"
open={detailVisible}
onClose={() => {
setDetailVisible(false);
setCurrentRecord(null);
}}
width={600}
>
{currentRecord && (
<Descriptions column={1} bordered>
{{- if .IsTree }}
<Descriptions.Item label="父节点">{currentRecord.parentID || '根节点'}</Descriptions.Item>
{{- end }}
{{- range .Fields}}
{{- if .Desc }}
{{ GenerateReactDescriptionItem . }}
{{- end }}
{{- end }}
{{- if .GvaModel }}
<Descriptions.Item label="创建时间">
{currentRecord.CreatedAt ? dayjs(currentRecord.CreatedAt).format('YYYY-MM-DD HH:mm:ss') : '-'}
</Descriptions.Item>
<Descriptions.Item label="更新时间">
{currentRecord.UpdatedAt ? dayjs(currentRecord.UpdatedAt).format('YYYY-MM-DD HH:mm:ss') : '-'}
</Descriptions.Item>
{{- end }}
</Descriptions>
)}
</Drawer>
</PageContainer>
);
};
export default {{.StructName}}Page;
{{- else}}
/**
* KRA - {{.Description}}页面
* Auto-generated by KRA AutoCode
*/
import React from 'react';
import { PageContainer } from '@ant-design/pro-components';
const {{.StructName}}Page: React.FC = () => {
return (
<PageContainer>
<div>{{.Description}}页面</div>
</PageContainer>
);
};
export default {{.StructName}}Page;
{{- end }}
{{- end }}
+131
View File
@@ -0,0 +1,131 @@
import { request } from '@umijs/max';
import type { ApiResponse, PageResult } from '@/types/api';
{{- if not .OnlyTemplate}}
// {{.StructName}} {{.Description}}类型
export interface {{.StructName}} {
{{- if .GvaModel }}
ID?: number;
CreatedAt?: string;
UpdatedAt?: string;
{{- end }}
{{- range .Fields}}
{{.FieldJson}}{{if not .Require}}?{{end}}: {{ GenerateTSType .FieldType }}; // {{.FieldDesc}}
{{- end }}
{{- if .AutoCreateResource }}
createdBy?: number;
updatedBy?: number;
deletedBy?: number;
{{- end }}
{{- if .IsTree }}
children?: {{.StructName}}[];
parentID?: number;
{{- end }}
}
// {{.StructName}}Search {{.Description}}搜索条件
export interface {{.StructName}}Search {
page: number;
pageSize: number;
{{- if .GvaModel }}
createdAtRange?: string[];
{{- end }}
{{- range .Fields}}
{{- if .FieldSearchType}}
{{.FieldJson}}?: {{ GenerateTSType .FieldType }};
{{- end}}
{{- end}}
{{- if .NeedSort}}
sort?: string;
order?: string;
{{- end}}
}
/**
* 创建{{.Description}}
* @param data {{.Description}}数据
*/
export const create{{.StructName}} = (data: {{.StructName}}) => {
return request<ApiResponse<null>>('/{{.Abbreviation}}/create{{.StructName}}', {
method: 'POST',
data,
});
};
/**
* 删除{{.Description}}
* @param params 包含{{.PrimaryField.FieldJson}}的参数
*/
export const delete{{.StructName}} = (params: { {{.PrimaryField.FieldJson}}: {{ GenerateTSType .PrimaryField.FieldType }} }) => {
return request<ApiResponse<null>>('/{{.Abbreviation}}/delete{{.StructName}}', {
method: 'DELETE',
params,
});
};
/**
* 批量删除{{.Description}}
* @param params 包含{{.PrimaryField.FieldJson}}s数组的参数
*/
export const delete{{.StructName}}ByIds = (params: { {{.PrimaryField.FieldJson}}s: {{ GenerateTSType .PrimaryField.FieldType }}[] }) => {
return request<ApiResponse<null>>('/{{.Abbreviation}}/delete{{.StructName}}ByIds', {
method: 'DELETE',
params,
});
};
/**
* 更新{{.Description}}
* @param data {{.Description}}数据
*/
export const update{{.StructName}} = (data: {{.StructName}}) => {
return request<ApiResponse<null>>('/{{.Abbreviation}}/update{{.StructName}}', {
method: 'PUT',
data,
});
};
/**
* 根据ID获取{{.Description}}
* @param params 包含{{.PrimaryField.FieldJson}}的参数
*/
export const find{{.StructName}} = (params: { {{.PrimaryField.FieldJson}}: {{ GenerateTSType .PrimaryField.FieldType }} }) => {
return request<ApiResponse<{{.StructName}}>>('/{{.Abbreviation}}/find{{.StructName}}', {
method: 'GET',
params,
});
};
/**
* 获取{{.Description}}列表
* @param params 搜索条件
*/
export const get{{.StructName}}List = (params: {{.StructName}}Search) => {
return request<ApiResponse<PageResult<{{.StructName}}>>>('/{{.Abbreviation}}/get{{.StructName}}List', {
method: 'GET',
params,
});
};
{{- if .HasDataSource}}
/**
* 获取{{.Description}}数据源
*/
export const get{{.StructName}}DataSource = () => {
return request<ApiResponse<Record<string, Array<{ label: string; value: any }>>>>('/{{.Abbreviation}}/get{{.StructName}}DataSource', {
method: 'GET',
});
};
{{- end}}
{{- end}}
/**
* 获取{{.Description}}公开数据(无需鉴权)
*/
export const get{{.StructName}}Public = () => {
return request<ApiResponse<any>>('/{{.Abbreviation}}/get{{.StructName}}Public', {
method: 'GET',
});
};
+183
View File
@@ -0,0 +1,183 @@
{{- $global := . }}
{{- if not .OnlyTemplate}}
/**
* KRA - {{.Description}}类型定义
* Auto-generated by KRA AutoCode
*/
/**
* {{.StructName}} {{.Description}}实体类型
*/
export interface {{.StructName}} {
{{- if .GvaModel }}
/** 主键ID */
ID?: number;
/** 创建时间 */
CreatedAt?: string;
/** 更新时间 */
UpdatedAt?: string;
/** 删除时间 */
DeletedAt?: string | null;
{{- end }}
{{- range .Fields}}
/** {{.FieldDesc}} */
{{.FieldJson}}{{if not .Require}}?{{end}}: {{ GenerateTSType .FieldType }};
{{- end }}
{{- if .AutoCreateResource }}
/** 创建者ID */
createdBy?: number;
/** 更新者ID */
updatedBy?: number;
/** 删除者ID */
deletedBy?: number;
{{- end }}
{{- if .IsTree }}
/** 子节点 */
children?: {{.StructName}}[];
/** 父节点ID */
parentID?: number;
{{- end }}
}
/**
* {{.StructName}}ListReq {{.Description}}列表请求参数
*/
export interface {{.StructName}}ListReq {
/** 页码 */
page: number;
/** 每页数量 */
pageSize: number;
{{- if .GvaModel }}
/** 创建时间范围 */
createdAtRange?: string[];
/** 创建时间开始 */
startCreatedAt?: string;
/** 创建时间结束 */
endCreatedAt?: string;
{{- end }}
{{- range .Fields}}
{{- if .FieldSearchType}}
{{- if eq .FieldSearchType "BETWEEN"}}
/** {{.FieldDesc}}开始值 */
start{{.FieldName}}?: {{ GenerateTSType .FieldType }};
/** {{.FieldDesc}}结束值 */
end{{.FieldName}}?: {{ GenerateTSType .FieldType }};
{{- else}}
/** {{.FieldDesc}} */
{{.FieldJson}}?: {{ GenerateTSType .FieldType }};
{{- end}}
{{- end}}
{{- end}}
{{- if .NeedSort}}
/** 排序字段 */
orderKey?: string;
/** 是否降序 */
desc?: boolean;
{{- end}}
}
/**
* {{.StructName}}Search {{.Description}}搜索条件
* @description 与 {{.StructName}}ListReq 相同,用于API服务层
*/
export type {{.StructName}}Search = {{.StructName}}ListReq;
/**
* {{.StructName}}ListRes {{.Description}}列表响应
*/
export interface {{.StructName}}ListRes {
/** 数据列表 */
list: {{.StructName}}[];
/** 总数 */
total: number;
/** 当前页码 */
page: number;
/** 每页数量 */
pageSize: number;
}
/**
* {{.StructName}}IdReq {{.Description}}ID请求参数
*/
export interface {{.StructName}}IdReq {
/** {{.PrimaryField.FieldDesc}} */
{{.PrimaryField.FieldJson}}: {{ GenerateTSType .PrimaryField.FieldType }};
}
/**
* {{.StructName}}IdsReq {{.Description}}批量ID请求参数
*/
export interface {{.StructName}}IdsReq {
/** {{.PrimaryField.FieldDesc}}列表 */
{{.PrimaryField.FieldJson}}s: {{ GenerateTSType .PrimaryField.FieldType }}[];
}
{{- if .HasDataSource }}
/**
* {{.StructName}}DataSource {{.Description}}数据源类型
*/
export interface {{.StructName}}DataSource {
{{- range .Fields}}
{{- if .CheckDataSource}}
/** {{.FieldDesc}}数据源 */
{{.FieldJson}}?: Array<{ label: string; value: any }>;
{{- end}}
{{- end}}
}
{{- end }}
{{- if .DictTypes }}
/**
* 字典选项类型
*/
export interface DictOption {
/** 显示标签 */
label: string;
/** 值 */
value: number | string;
/** 状态 */
status?: boolean;
}
/**
* {{.StructName}}相关字典类型
*/
export interface {{.StructName}}DictTypes {
{{- range $index, $element := .DictTypes}}
/** {{$element}}字典选项 */
{{$element}}: DictOption[];
{{- end }}
}
{{- end }}
{{- else}}
/**
* KRA - {{.Description}}类型定义
* Auto-generated by KRA AutoCode (Template Only)
*/
// 仅模板模式,请根据实际需求定义类型
export interface {{.StructName}} {
// TODO: 添加字段定义
}
export interface {{.StructName}}ListReq {
page: number;
pageSize: number;
}
/**
* {{.StructName}}Search {{.Description}}搜索条件
* @description 与 {{.StructName}}ListReq 相同,用于API服务层
*/
export type {{.StructName}}Search = {{.StructName}}ListReq;
export interface {{.StructName}}ListRes {
list: {{.StructName}}[];
total: number;
page: number;
pageSize: number;
}
{{- end }}