feat: 代码生成
This commit is contained in:
@@ -0,0 +1,81 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sundynix-go/model/codegen"
|
||||||
|
"sundynix-go/model/commom/response"
|
||||||
|
"sundynix-go/service"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CodegenApi struct{}
|
||||||
|
|
||||||
|
var codegenService = service.ServiceGroupApp.CodegenServiceGroup.CodegenService
|
||||||
|
|
||||||
|
// TestConnection
|
||||||
|
// @Tags 代码生成
|
||||||
|
// @Summary 测试数据库连接
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body codegen.TestConnectionReq true "数据库连接配置"
|
||||||
|
// @Success 200 {object} response.Response "连接成功"
|
||||||
|
// @Router /api/codegen/testConnection [post]
|
||||||
|
func (a *CodegenApi) TestConnection(c *gin.Context) {
|
||||||
|
var req codegen.TestConnectionReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := codegenService.TestConnection(req.DbConfig); err != nil {
|
||||||
|
response.FailWithMsg("连接失败:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("连接成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preview
|
||||||
|
// @Tags 代码生成
|
||||||
|
// @Summary 预览生成代码(不写文件)
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body codegen.PreviewReq true "代码生成配置"
|
||||||
|
// @Success 200 {object} response.Response{data=[]codegen.PreviewFile} "预览成功"
|
||||||
|
// @Router /api/codegen/preview [post]
|
||||||
|
func (a *CodegenApi) Preview(c *gin.Context) {
|
||||||
|
var req codegen.PreviewReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
files, err := codegenService.Preview(req.GenConfig)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg("预览失败:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(files, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate
|
||||||
|
// @Tags 代码生成
|
||||||
|
// @Summary 生成并写入代码文件
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body codegen.GenConfig true "代码生成配置(含 outputDir)"
|
||||||
|
// @Success 200 {object} response.Response{data=codegen.GenResult} "生成成功"
|
||||||
|
// @Router /api/codegen/generate [post]
|
||||||
|
func (a *CodegenApi) Generate(c *gin.Context) {
|
||||||
|
var req codegen.GenConfig
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result, err := codegenService.Generate(req)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg("生成失败:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(result, c)
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
type ApiGroup struct {
|
||||||
|
CodegenApi
|
||||||
|
}
|
||||||
+8
-2
@@ -1,10 +1,16 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import "sundynix-go/api/v1/system"
|
import (
|
||||||
|
"sundynix-go/api/v1/codegen"
|
||||||
|
"sundynix-go/api/v1/order"
|
||||||
|
"sundynix-go/api/v1/system"
|
||||||
|
)
|
||||||
|
|
||||||
var ApiGroupApp = new(ApiGroup)
|
var ApiGroupApp = new(ApiGroup)
|
||||||
|
|
||||||
// ApiGroup 路由组
|
// ApiGroup 路由组
|
||||||
type ApiGroup struct {
|
type ApiGroup struct {
|
||||||
SystemApiGroup system.ApiGroup
|
SystemApiGroup system.ApiGroup
|
||||||
|
CodegenApiGroup codegen.ApiGroup
|
||||||
|
OrderApiGroup order.ApiGroup
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
type ApiGroup struct {
|
||||||
|
OrderApi
|
||||||
|
RefundApi
|
||||||
|
StockApi
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
|
"sundynix-go/model/commom/response"
|
||||||
|
req "sundynix-go/model/order/request"
|
||||||
|
"sundynix-go/service"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrderApi struct{}
|
||||||
|
|
||||||
|
var orderService = service.ServiceGroupApp.OrderServiceGroup.OrderService
|
||||||
|
|
||||||
|
// Save
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 新增
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.SaveOrderReq true "新增参数"
|
||||||
|
// @Success 200 {object} response.Response "新增成功"
|
||||||
|
// @Router /order/order/save [post]
|
||||||
|
func (a *OrderApi) Save(c *gin.Context) {
|
||||||
|
var r req.SaveOrderReq
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := orderService.Save(r); err != nil {
|
||||||
|
global.Logger.Error("新增失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("新增成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 更新
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.UpdateOrderReq true "更新参数"
|
||||||
|
// @Success 200 {object} response.Response "更新成功"
|
||||||
|
// @Router /order/order/update [post]
|
||||||
|
func (a *OrderApi) Update(c *gin.Context) {
|
||||||
|
var r req.UpdateOrderReq
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := orderService.Update(r); err != nil {
|
||||||
|
global.Logger.Error("更新失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("更新成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 删除(支持批量)
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body object{ids=[]string} true "id列表"
|
||||||
|
// @Success 200 {object} response.Response "删除成功"
|
||||||
|
// @Router /order/order/delete [post]
|
||||||
|
func (a *OrderApi) Delete(c *gin.Context) {
|
||||||
|
var req struct {
|
||||||
|
Ids []string `json:"ids" binding:"required,min=1"`
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := orderService.Delete(req.Ids); err != nil {
|
||||||
|
global.Logger.Error("删除失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("删除成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detail
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 获取详情
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @Produce json
|
||||||
|
// @Param id query string true "ID"
|
||||||
|
// @Success 200 {object} response.Response "获取详情成功"
|
||||||
|
// @Router /order/order/detail [get]
|
||||||
|
func (a *OrderApi) Detail(c *gin.Context) {
|
||||||
|
id := c.Query("id")
|
||||||
|
data, err := orderService.Detail(id)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取详情失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(data, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 分页获取列表
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.ListOrderReq true "分页参数"
|
||||||
|
// @Success 200 {object} response.Response{data=response.PageResult} "获取列表成功"
|
||||||
|
// @Router /order/order/list [post]
|
||||||
|
func (a *OrderApi) List(c *gin.Context) {
|
||||||
|
var r req.ListOrderReq
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list, total, err := orderService.List(r)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取列表失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(response.PageResult{
|
||||||
|
List: list,
|
||||||
|
Total: total,
|
||||||
|
Page: r.Current,
|
||||||
|
PageSize: r.PageSize,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
|
"sundynix-go/model/commom/response"
|
||||||
|
req "sundynix-go/model/order/request"
|
||||||
|
"sundynix-go/service"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RefundApi struct{}
|
||||||
|
|
||||||
|
var refundService = service.ServiceGroupApp.OrderServiceGroup.RefundService
|
||||||
|
|
||||||
|
// Save
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 新增
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.SaveRefundReq true "新增参数"
|
||||||
|
// @Success 200 {object} response.Response "新增成功"
|
||||||
|
// @Router /order/refund/save [post]
|
||||||
|
func (a *RefundApi) Save(c *gin.Context) {
|
||||||
|
var r req.SaveRefundReq
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := refundService.Save(r); err != nil {
|
||||||
|
global.Logger.Error("新增失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("新增成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 更新
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.UpdateRefundReq true "更新参数"
|
||||||
|
// @Success 200 {object} response.Response "更新成功"
|
||||||
|
// @Router /order/refund/update [post]
|
||||||
|
func (a *RefundApi) Update(c *gin.Context) {
|
||||||
|
var r req.UpdateRefundReq
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := refundService.Update(r); err != nil {
|
||||||
|
global.Logger.Error("更新失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("更新成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 删除(支持批量)
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body object{ids=[]string} true "id列表"
|
||||||
|
// @Success 200 {object} response.Response "删除成功"
|
||||||
|
// @Router /order/refund/delete [post]
|
||||||
|
func (a *RefundApi) Delete(c *gin.Context) {
|
||||||
|
var req struct {
|
||||||
|
Ids []string `json:"ids" binding:"required,min=1"`
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := refundService.Delete(req.Ids); err != nil {
|
||||||
|
global.Logger.Error("删除失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("删除成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detail
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 获取详情
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @Produce json
|
||||||
|
// @Param id query string true "ID"
|
||||||
|
// @Success 200 {object} response.Response "获取详情成功"
|
||||||
|
// @Router /order/refund/detail [get]
|
||||||
|
func (a *RefundApi) Detail(c *gin.Context) {
|
||||||
|
id := c.Query("id")
|
||||||
|
data, err := refundService.Detail(id)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取详情失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(data, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 分页获取列表
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.ListRefundReq true "分页参数"
|
||||||
|
// @Success 200 {object} response.Response{data=response.PageResult} "获取列表成功"
|
||||||
|
// @Router /order/refund/list [post]
|
||||||
|
func (a *RefundApi) List(c *gin.Context) {
|
||||||
|
var r req.ListRefundReq
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list, total, err := refundService.List(r)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取列表失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(response.PageResult{
|
||||||
|
List: list,
|
||||||
|
Total: total,
|
||||||
|
Page: r.Current,
|
||||||
|
PageSize: r.PageSize,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
|
"sundynix-go/model/commom/response"
|
||||||
|
req "sundynix-go/model/order/request"
|
||||||
|
"sundynix-go/service"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StockApi struct{}
|
||||||
|
|
||||||
|
var stockService = service.ServiceGroupApp.OrderServiceGroup.StockService
|
||||||
|
|
||||||
|
// Save
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 新增
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.SaveStockReq true "新增参数"
|
||||||
|
// @Success 200 {object} response.Response "新增成功"
|
||||||
|
// @Router /order/stock/save [post]
|
||||||
|
func (a *StockApi) Save(c *gin.Context) {
|
||||||
|
var r req.SaveStockReq
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := stockService.Save(r); err != nil {
|
||||||
|
global.Logger.Error("新增失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("新增成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 更新
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.UpdateStockReq true "更新参数"
|
||||||
|
// @Success 200 {object} response.Response "更新成功"
|
||||||
|
// @Router /order/stock/update [post]
|
||||||
|
func (a *StockApi) Update(c *gin.Context) {
|
||||||
|
var r req.UpdateStockReq
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := stockService.Update(r); err != nil {
|
||||||
|
global.Logger.Error("更新失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("更新成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 删除(支持批量)
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body object{ids=[]string} true "id列表"
|
||||||
|
// @Success 200 {object} response.Response "删除成功"
|
||||||
|
// @Router /order/stock/delete [post]
|
||||||
|
func (a *StockApi) Delete(c *gin.Context) {
|
||||||
|
var req struct {
|
||||||
|
Ids []string `json:"ids" binding:"required,min=1"`
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := stockService.Delete(req.Ids); err != nil {
|
||||||
|
global.Logger.Error("删除失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("删除成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detail
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 获取详情
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @Produce json
|
||||||
|
// @Param id query string true "ID"
|
||||||
|
// @Success 200 {object} response.Response "获取详情成功"
|
||||||
|
// @Router /order/stock/detail [get]
|
||||||
|
func (a *StockApi) Detail(c *gin.Context) {
|
||||||
|
id := c.Query("id")
|
||||||
|
data, err := stockService.Detail(id)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取详情失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(data, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List
|
||||||
|
// @Tags 管理
|
||||||
|
// @Summary 分页获取列表
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.ListStockReq true "分页参数"
|
||||||
|
// @Success 200 {object} response.Response{data=response.PageResult} "获取列表成功"
|
||||||
|
// @Router /order/stock/list [post]
|
||||||
|
func (a *StockApi) List(c *gin.Context) {
|
||||||
|
var r req.ListStockReq
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list, total, err := stockService.List(r)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取列表失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(response.PageResult{
|
||||||
|
List: list,
|
||||||
|
Total: total,
|
||||||
|
Page: r.Current,
|
||||||
|
PageSize: r.PageSize,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
+17
-11
@@ -32,24 +32,30 @@ func (a *AuthApi) Login(c *gin.Context) {
|
|||||||
response.FailWithMsg(err.Error(), c)
|
response.FailWithMsg(err.Error(), c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if l.CaptchaId != "" && l.Captcha != "" && store.Verify(l.CaptchaId, l.Captcha, true) {
|
|
||||||
u := &system.User{Account: l.Account, Password: l.Password}
|
// 验证码校验:enable-captcha=0 时跳过
|
||||||
user, err := userService.Login(u)
|
captchaOk := global.Config.System.EnableCaptcha == 0 ||
|
||||||
if err != nil {
|
(l.CaptchaId != "" && l.Captcha != "" && store.Verify(l.CaptchaId, l.Captcha, true))
|
||||||
global.Logger.Error("登录失败! 用户名不存在或者密码错误!", zap.Error(err))
|
|
||||||
response.FailWithMsg("用户名不存在或者密码错误", c)
|
if !captchaOk {
|
||||||
return
|
response.FailWithMsg("验证码错误", c)
|
||||||
}
|
|
||||||
a.GetToken(c, *user)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.FailWithMsg("验证码错误", c)
|
|
||||||
|
u := &system.User{Account: l.Account, Password: l.Password}
|
||||||
|
user, err := userService.Login(u)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("登录失败! 用户名不存在或者密码错误!", zap.Error(err))
|
||||||
|
response.FailWithMsg("用户名不存在或者密码错误", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a.GetToken(c, *user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logout
|
// Logout
|
||||||
// @Tags 登录相关
|
// @Tags 登录相关
|
||||||
// @Summary pc登出
|
// @Summary pc登出
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Success 200 {object} response.Response{msg=string} "登出成功"
|
// @Success 200 {object} response.Response{msg=string} "登出成功"
|
||||||
// @Router /api/auth/logout [get]
|
// @Router /api/auth/logout [get]
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ type OssApi struct {
|
|||||||
// UploadFile
|
// UploadFile
|
||||||
// @tags 文件相关
|
// @tags 文件相关
|
||||||
// @Summary 文件上传
|
// @Summary 文件上传
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept multipart/form-data
|
// @accept multipart/form-data
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param file formData file true "上传文件"
|
// @Param file formData file true "上传文件"
|
||||||
@@ -44,7 +44,7 @@ func (o *OssApi) UploadFile(c *gin.Context) {
|
|||||||
// DeleteFile
|
// DeleteFile
|
||||||
// @tags 文件相关
|
// @tags 文件相关
|
||||||
// @Summary 删除文件
|
// @Summary 删除文件
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body request.IdsReq true "批量删除文件"
|
// @Param data body request.IdsReq true "批量删除文件"
|
||||||
@@ -69,7 +69,7 @@ func (o *OssApi) DeleteFile(c *gin.Context) {
|
|||||||
// GetFileList
|
// GetFileList
|
||||||
// @tags 文件相关
|
// @tags 文件相关
|
||||||
// @Summary 文件列表
|
// @Summary 文件列表
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Accept application/json
|
// @Accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body sysReq.GetOssFileList true "文件列表"
|
// @Param data body sysReq.GetOssFileList true "文件列表"
|
||||||
@@ -99,7 +99,7 @@ func (o *OssApi) GetFileList(c *gin.Context) {
|
|||||||
// Detail
|
// Detail
|
||||||
// @tags 文件相关
|
// @tags 文件相关
|
||||||
// @Summary 文件详情
|
// @Summary 文件详情
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param id query string true "文件id"
|
// @Param id query string true "文件id"
|
||||||
// @Success 200 {object} response.Response{data=string} "文件详情"
|
// @Success 200 {object} response.Response{data=string} "文件详情"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ type ClientApi struct {
|
|||||||
// SaveClient
|
// SaveClient
|
||||||
// @Tags 客户端管理
|
// @Tags 客户端管理
|
||||||
// @Summary 创建client
|
// @Summary 创建client
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body system.Client true "client"
|
// @Param data body system.Client true "client"
|
||||||
@@ -42,7 +42,7 @@ func (s *ClientApi) SaveClient(c *gin.Context) {
|
|||||||
// UpdateClient
|
// UpdateClient
|
||||||
// @Tags 客户端管理
|
// @Tags 客户端管理
|
||||||
// @Summary 更新client
|
// @Summary 更新client
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body system.Client true "client"
|
// @Param data body system.Client true "client"
|
||||||
@@ -67,7 +67,7 @@ func (s *ClientApi) UpdateClient(c *gin.Context) {
|
|||||||
// GetClientList
|
// GetClientList
|
||||||
// @Tags 客户端管理
|
// @Tags 客户端管理
|
||||||
// @Summary 获取client列表
|
// @Summary 获取client列表
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body systemReq.GetClientList true "client"
|
// @Param data body systemReq.GetClientList true "client"
|
||||||
@@ -97,7 +97,7 @@ func (s *ClientApi) GetClientList(c *gin.Context) {
|
|||||||
// Delete
|
// Delete
|
||||||
// @Tags 客户端管理
|
// @Tags 客户端管理
|
||||||
// @Summary 删除client
|
// @Summary 删除client
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body request.IdsReq true "ids"
|
// @Param data body request.IdsReq true "ids"
|
||||||
@@ -123,7 +123,7 @@ func (s *ClientApi) Delete(c *gin.Context) {
|
|||||||
// @Tags 客户端管理
|
// @Tags 客户端管理
|
||||||
// @Summary 获取client详情
|
// @Summary 获取client详情
|
||||||
// @Description id获取详情
|
// @Description id获取详情
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param id query string true "id"
|
// @Param id query string true "id"
|
||||||
// @Success 200 {object} response.Response{data=system.Client,msg=string} "获取client详情"
|
// @Success 200 {object} response.Response{data=system.Client,msg=string} "获取client详情"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ type MenuApi struct {
|
|||||||
// SaveMenu
|
// SaveMenu
|
||||||
// @Tags 菜单管理
|
// @Tags 菜单管理
|
||||||
// @Summary 新增菜单
|
// @Summary 新增菜单
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body system.Menu false "menu"
|
// @Param data body system.Menu false "menu"
|
||||||
@@ -42,7 +42,7 @@ func (m *MenuApi) SaveMenu(c *gin.Context) {
|
|||||||
// UpdateMenu
|
// UpdateMenu
|
||||||
// @Tags 菜单管理
|
// @Tags 菜单管理
|
||||||
// @Summary 更新菜单
|
// @Summary 更新菜单
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body system.Menu false "menu"
|
// @Param data body system.Menu false "menu"
|
||||||
@@ -68,7 +68,7 @@ func (m *MenuApi) UpdateMenu(c *gin.Context) {
|
|||||||
// @Tags 菜单管理
|
// @Tags 菜单管理
|
||||||
// @Summary 删除menu
|
// @Summary 删除menu
|
||||||
// @Description 删除menu
|
// @Description 删除menu
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param id query string true "id"
|
// @Param id query string true "id"
|
||||||
// @Success 200 {object} response.Response{msg=string} "详情"
|
// @Success 200 {object} response.Response{msg=string} "详情"
|
||||||
@@ -88,7 +88,7 @@ func (m *MenuApi) DeleteMenu(c *gin.Context) {
|
|||||||
// @Tags 菜单管理
|
// @Tags 菜单管理
|
||||||
// @Summary 获取menu详情
|
// @Summary 获取menu详情
|
||||||
// @Description id获取详情
|
// @Description id获取详情
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param id query string true "id"
|
// @Param id query string true "id"
|
||||||
// @Success 200 {object} response.Response{data=system.Menu,msg=string} "详情"
|
// @Success 200 {object} response.Response{data=system.Menu,msg=string} "详情"
|
||||||
@@ -107,7 +107,7 @@ func (m *MenuApi) Detail(c *gin.Context) {
|
|||||||
// GetAllMenuTree
|
// GetAllMenuTree
|
||||||
// @Tags 菜单管理
|
// @Tags 菜单管理
|
||||||
// @Summary 获取所有菜单树
|
// @Summary 获取所有菜单树
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param data body systemReq.GetMenuTree true "菜单信息"
|
// @Param data body systemReq.GetMenuTree true "菜单信息"
|
||||||
@@ -132,7 +132,7 @@ func (m *MenuApi) GetAllMenuTree(c *gin.Context) {
|
|||||||
// GetUserMenuTree
|
// GetUserMenuTree
|
||||||
// @Tags 菜单管理
|
// @Tags 菜单管理
|
||||||
// @Summary 用户菜单数据
|
// @Summary 用户菜单数据
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response{data=[]system.Menu,msg=string} "用户菜单数据"
|
// @Success 200 {object} response.Response{data=[]system.Menu,msg=string} "用户菜单数据"
|
||||||
// @Router /api/menu/getUserMenuTree [get]
|
// @Router /api/menu/getUserMenuTree [get]
|
||||||
@@ -143,7 +143,7 @@ func (m *MenuApi) GetUserMenuTree(c *gin.Context) {
|
|||||||
// Route
|
// Route
|
||||||
// @Tags 菜单管理
|
// @Tags 菜单管理
|
||||||
// @Summary 用户路由
|
// @Summary 用户路由
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response{data=[]system.Menu,msg=string} "用户route"
|
// @Success 200 {object} response.Response{data=[]system.Menu,msg=string} "用户route"
|
||||||
// @Router /api/menu/route [get]
|
// @Router /api/menu/route [get]
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ type RoleApi struct {
|
|||||||
// SaveRole
|
// SaveRole
|
||||||
// @tags 角色管理
|
// @tags 角色管理
|
||||||
// @Summary 创建角色
|
// @Summary 创建角色
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept json
|
// @accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param data body system.Role true "角色信息"
|
// @Param data body system.Role true "角色信息"
|
||||||
@@ -42,7 +42,7 @@ func (a *RoleApi) SaveRole(context *gin.Context) {
|
|||||||
// UpdateRole
|
// UpdateRole
|
||||||
// @tags 角色管理
|
// @tags 角色管理
|
||||||
// @Summary 修改角色
|
// @Summary 修改角色
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body system.Role true "角色ID"
|
// @Param data body system.Role true "角色ID"
|
||||||
@@ -121,7 +121,7 @@ func (a *RoleApi) Delete(context *gin.Context) {
|
|||||||
// Detail
|
// Detail
|
||||||
// @Tags 角色管理
|
// @Tags 角色管理
|
||||||
// @Summary 角色详情
|
// @Summary 角色详情
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param id query string true "id"
|
// @Param id query string true "id"
|
||||||
// @Success 200 {object} response.Response{data=system.Role} "角色详情"
|
// @Success 200 {object} response.Response{data=system.Role} "角色详情"
|
||||||
@@ -140,7 +140,7 @@ func (a *RoleApi) Detail(context *gin.Context) {
|
|||||||
// GrantMenu
|
// GrantMenu
|
||||||
// @tags 角色管理
|
// @tags 角色管理
|
||||||
// @Summary 授权菜单给角色
|
// @Summary 授权菜单给角色
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body systemreq.GrantMenu true "授权菜单给角色"
|
// @Param data body systemreq.GrantMenu true "授权菜单给角色"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ type UserApi struct {
|
|||||||
// SaveUser
|
// SaveUser
|
||||||
// @tags 用户管理
|
// @tags 用户管理
|
||||||
// @Summary 新增用户
|
// @Summary 新增用户
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept json
|
// @accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param data body system.User true "用户信息"
|
// @Param data body system.User true "用户信息"
|
||||||
@@ -41,7 +41,7 @@ func (u *UserApi) SaveUser(c *gin.Context) {
|
|||||||
// UpdateUser
|
// UpdateUser
|
||||||
// @tags 用户管理
|
// @tags 用户管理
|
||||||
// @Summary 更新用户
|
// @Summary 更新用户
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body system.User true "用户ID,用户信息"
|
// @Param data body system.User true "用户ID,用户信息"
|
||||||
@@ -65,7 +65,7 @@ func (u *UserApi) UpdateUser(c *gin.Context) {
|
|||||||
// GetUserList
|
// GetUserList
|
||||||
// @tags 用户管理
|
// @tags 用户管理
|
||||||
// @Summary 获取用户列表
|
// @Summary 获取用户列表
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body systemReq.GetUserList true "页码, 每页大小, 搜索条件"
|
// @Param data body systemReq.GetUserList true "页码, 每页大小, 搜索条件"
|
||||||
@@ -95,7 +95,7 @@ func (u *UserApi) GetUserList(c *gin.Context) {
|
|||||||
// Delete
|
// Delete
|
||||||
// @Tags 用户管理
|
// @Tags 用户管理
|
||||||
// @Summary 删除用户
|
// @Summary 删除用户
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body request.IdsReq true "批量删除用户"
|
// @Param data body request.IdsReq true "批量删除用户"
|
||||||
@@ -120,7 +120,7 @@ func (u *UserApi) Delete(c *gin.Context) {
|
|||||||
// Detail
|
// Detail
|
||||||
// @Tags 用户管理
|
// @Tags 用户管理
|
||||||
// @Summary 获取用户详情
|
// @Summary 获取用户详情
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param id query string true "id"
|
// @Param id query string true "id"
|
||||||
// @Success 200 {object} response.Response{data=system.User} "获取用户详情成功"
|
// @Success 200 {object} response.Response{data=system.User} "获取用户详情成功"
|
||||||
@@ -139,7 +139,7 @@ func (u *UserApi) Detail(c *gin.Context) {
|
|||||||
// ChangePassword
|
// ChangePassword
|
||||||
// @Tags 用户管理
|
// @Tags 用户管理
|
||||||
// @Summary 修改密码
|
// @Summary 修改密码
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @Description 修改密码
|
// @Description 修改密码
|
||||||
// @accept json
|
// @accept json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
@@ -165,7 +165,7 @@ func (u *UserApi) ChangePassword(c *gin.Context) {
|
|||||||
// GrantRole
|
// GrantRole
|
||||||
// @Tags 用户管理
|
// @Tags 用户管理
|
||||||
// @Summary 给用户分配角色
|
// @Summary 给用户分配角色
|
||||||
// @Security ApiKeyAuth
|
// @Security BasicAuth
|
||||||
// @accept application/json
|
// @accept application/json
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Param data body systemReq.GrantRole true "用户ID, 角色ID"
|
// @Param data body systemReq.GrantRole true "用户ID, 角色ID"
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"sundynix-go/global"
|
"sundynix-go/global"
|
||||||
"sundynix-go/model/system"
|
"sundynix-go/model/system"
|
||||||
|
|
||||||
|
"sundynix-go/model/order"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@@ -37,6 +39,12 @@ func MigrateTable() {
|
|||||||
system.Menu{},
|
system.Menu{},
|
||||||
system.SysOperationRecord{},
|
system.SysOperationRecord{},
|
||||||
system.Oss{},
|
system.Oss{},
|
||||||
|
|
||||||
|
order.Order{},
|
||||||
|
|
||||||
|
order.Refund{},
|
||||||
|
|
||||||
|
order.Stock{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Logger.Error("Migrate table failed,err:", zap.Error(err))
|
global.Logger.Error("Migrate table failed,err:", zap.Error(err))
|
||||||
|
|||||||
+12
-4
@@ -26,6 +26,9 @@ func Routers() {
|
|||||||
|
|
||||||
// 系统组路由
|
// 系统组路由
|
||||||
systemRouter := router.GroupApp.System
|
systemRouter := router.GroupApp.System
|
||||||
|
codegenRouter := router.GroupApp.Codegen
|
||||||
|
|
||||||
|
orderRouter := router.GroupApp.Order
|
||||||
|
|
||||||
NeedAuthGroup := Router.Group(global.Config.System.RouterPrefix)
|
NeedAuthGroup := Router.Group(global.Config.System.RouterPrefix)
|
||||||
PublicGroup := Router.Group(global.Config.System.RouterPrefix)
|
PublicGroup := Router.Group(global.Config.System.RouterPrefix)
|
||||||
@@ -40,10 +43,15 @@ func Routers() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
//需要鉴权的路由
|
//需要鉴权的路由
|
||||||
systemRouter.InitUserRouter(NeedAuthGroup) //用户相关
|
systemRouter.InitUserRouter(NeedAuthGroup) //用户相关
|
||||||
systemRouter.InitClientRouter(NeedAuthGroup) //客户端相关
|
systemRouter.InitClientRouter(NeedAuthGroup) //客户端相关
|
||||||
systemRouter.InitRoleRouter(NeedAuthGroup) //角色相关
|
systemRouter.InitRoleRouter(NeedAuthGroup) //角色相关
|
||||||
systemRouter.InitMenuRouter(NeedAuthGroup) //菜单相关
|
systemRouter.InitMenuRouter(NeedAuthGroup) //菜单相关
|
||||||
|
codegenRouter.InitCodegenRouter(NeedAuthGroup) //代码生成
|
||||||
|
orderRouter.InitOrderRouter(NeedAuthGroup)
|
||||||
|
orderRouter.InitRefundRouter(NeedAuthGroup)
|
||||||
|
orderRouter.InitStockRouter(NeedAuthGroup)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
address := fmt.Sprintf(":%d", global.Config.System.Addr)
|
address := fmt.Sprintf(":%d", global.Config.System.Addr)
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ import (
|
|||||||
// @title RBAC Swagger API接口文档
|
// @title RBAC Swagger API接口文档
|
||||||
// @version v1.0.0
|
// @version v1.0.0
|
||||||
// @description 使用gin+gorm进行极速开发的全栈开发基础平台
|
// @description 使用gin+gorm进行极速开发的全栈开发基础平台
|
||||||
// @securityDefinitions.apikey ApiKeyAuth
|
// @securityDefinitions.basic BasicAuth
|
||||||
// @in header
|
|
||||||
// @name Authorization
|
|
||||||
// @BasePath /
|
// @BasePath /
|
||||||
func main() {
|
func main() {
|
||||||
//初始化viper
|
//初始化viper
|
||||||
@@ -28,7 +26,9 @@ func main() {
|
|||||||
global.DB = initialize.Gorm()
|
global.DB = initialize.Gorm()
|
||||||
//redis连接
|
//redis连接
|
||||||
initialize.Redis()
|
initialize.Redis()
|
||||||
global.Redis.Set(context.Background(), "test", 0, -1)
|
if global.Redis != nil {
|
||||||
|
global.Redis.Set(context.Background(), "test", 0, -1)
|
||||||
|
}
|
||||||
|
|
||||||
//迁移数据库
|
//迁移数据库
|
||||||
if global.DB != nil {
|
if global.DB != nil {
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
// GenConfig 代码生成完整配置
|
||||||
|
type GenConfig struct {
|
||||||
|
DbConfig DbConfig `json:"dbConfig"`
|
||||||
|
OutputDir string `json:"outputDir"` // 后端输出目录,绝对路径,为空则输出到项目根目录
|
||||||
|
FrontendOutputDir string `json:"frontendOutputDir"` // 前端输出目录,绝对路径,为空则跳过前端生成
|
||||||
|
Overwrite bool `json:"overwrite"` // true=覆盖已有文件 false=增量模式(跳过已存在文件)
|
||||||
|
Modules []Module `json:"modules"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DbConfig 目标数据库连接配置
|
||||||
|
type DbConfig struct {
|
||||||
|
Host string `json:"host"`
|
||||||
|
Port string `json:"port"`
|
||||||
|
User string `json:"user"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
DbName string `json:"dbName"`
|
||||||
|
DbType string `json:"dbType"` // mysql / postgres / sqlite
|
||||||
|
}
|
||||||
|
|
||||||
|
// Module 模块定义(对应一组功能)
|
||||||
|
type Module struct {
|
||||||
|
Name string `json:"name"` // 模块名(PascalCase),如 "Order"
|
||||||
|
PackageName string `json:"packageName"` // 包名(lowercase),如 "order"
|
||||||
|
Description string `json:"description"`
|
||||||
|
Features []Feature `json:"features"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feature 功能单元(对应一张表 / 一个实体)
|
||||||
|
type Feature struct {
|
||||||
|
Name string `json:"name"` // 实体名(PascalCase),如 "Product"
|
||||||
|
TableName string `json:"tableName"` // 数据库表名,如 "product"
|
||||||
|
Comment string `json:"comment"`
|
||||||
|
Fields []Field `json:"fields"`
|
||||||
|
Relations []Relation `json:"relations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field 字段定义
|
||||||
|
type Field struct {
|
||||||
|
Name string `json:"name"` // Go 字段名(PascalCase),如 "OrderNo"
|
||||||
|
ColumnName string `json:"columnName"` // 数据库列名(snake_case),如 "order_no"
|
||||||
|
Type string `json:"type"` // Go 类型,如 string / int / float64 / bool / time.Time
|
||||||
|
GormTag string `json:"gormTag"` // gorm tag 附加内容,如 "size:100;not null"
|
||||||
|
JsonTag string `json:"jsonTag"` // json tag,如 "orderNo"
|
||||||
|
Comment string `json:"comment"` // 字段注释
|
||||||
|
Required bool `json:"required"` // 是否必填(影响 not null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relation 表关系定义
|
||||||
|
type Relation struct {
|
||||||
|
Type string `json:"type"` // OneToOne / OneToMany / ManyToMany
|
||||||
|
TargetFeature string `json:"targetFeature"` // 目标实体名(PascalCase)
|
||||||
|
ForeignKey string `json:"foreignKey"` // 外键字段名,如 "UserId"
|
||||||
|
JoinTable string `json:"joinTable"` // ManyToMany 中间表名
|
||||||
|
FieldName string `json:"fieldName"` // Go 中关联字段名,如 "Tags"
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestConnectionReq 测试连接请求
|
||||||
|
type TestConnectionReq struct {
|
||||||
|
DbConfig DbConfig `json:"dbConfig"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreviewReq 预览代码请求
|
||||||
|
type PreviewReq struct {
|
||||||
|
GenConfig
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
// PreviewFile 预览的单个文件
|
||||||
|
type PreviewFile struct {
|
||||||
|
FilePath string `json:"filePath"` // 相对于输出目录的路径
|
||||||
|
Content string `json:"content"` // 文件内容
|
||||||
|
AlwaysOverwrite bool `json:"alwaysOverwrite,omitempty"` // 聚合文件(如 enter.go),始终覆盖
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenResult 代码生成结果
|
||||||
|
type GenResult struct {
|
||||||
|
OutputDir string `json:"outputDir"` // 实际输出目录
|
||||||
|
Files []PreviewFile `json:"files"` // 生成的文件列表
|
||||||
|
Message string `json:"message"` // 生成结果说明
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import "sundynix-go/global"
|
||||||
|
|
||||||
|
// Order
|
||||||
|
type Order struct {
|
||||||
|
global.BaseModel
|
||||||
|
UserId string `gorm:"column:user_id;size:50" json:"userId"` //
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Order) TableName() string {
|
||||||
|
return "sundynix_order"
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import "sundynix-go/global"
|
||||||
|
|
||||||
|
// Refund
|
||||||
|
type Refund struct {
|
||||||
|
global.BaseModel
|
||||||
|
UserId string `gorm:"column:user_id;size:50" json:"userId"` //
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Refund) TableName() string {
|
||||||
|
return "sundynix_refund"
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
// ---- ----
|
||||||
|
|
||||||
|
// SaveRefundReq 新增请求
|
||||||
|
type SaveRefundReq struct {
|
||||||
|
UserId string `json:"userId" form:"userId"` //
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRefundReq 更新请求
|
||||||
|
type UpdateRefundReq struct {
|
||||||
|
Id string `json:"id" binding:"required"` // ID
|
||||||
|
UserId string `json:"userId" form:"userId"` //
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRefundReq 分页查询请求
|
||||||
|
type ListRefundReq struct {
|
||||||
|
Current int `json:"current" form:"current"` // 页码
|
||||||
|
PageSize int `json:"pageSize" form:"pageSize"` // 每页大小
|
||||||
|
Keyword string `json:"keyword" form:"keyword"` // 关键字搜索
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- ----
|
||||||
|
|
||||||
|
// SaveStockReq 新增请求
|
||||||
|
type SaveStockReq struct {
|
||||||
|
Amount int64 `json:"amount" form:"amount"` //
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateStockReq 更新请求
|
||||||
|
type UpdateStockReq struct {
|
||||||
|
Id string `json:"id" binding:"required"` // ID
|
||||||
|
Amount int64 `json:"amount" form:"amount"` //
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListStockReq 分页查询请求
|
||||||
|
type ListStockReq struct {
|
||||||
|
Current int `json:"current" form:"current"` // 页码
|
||||||
|
PageSize int `json:"pageSize" form:"pageSize"` // 每页大小
|
||||||
|
Keyword string `json:"keyword" form:"keyword"` // 关键字搜索
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import "sundynix-go/global"
|
||||||
|
|
||||||
|
// Stock
|
||||||
|
type Stock struct {
|
||||||
|
global.BaseModel
|
||||||
|
Amount int64 `gorm:"column:amount" json:"amount"` //
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Stock) TableName() string {
|
||||||
|
return "sundynix_stock"
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
type CodegenRouter struct{}
|
||||||
|
|
||||||
|
func (r *CodegenRouter) InitCodegenRouter(Router *gin.RouterGroup) {
|
||||||
|
codegenRouter := Router.Group("codegen")
|
||||||
|
{
|
||||||
|
codegenRouter.POST("testConnection", codegenApi.TestConnection)
|
||||||
|
codegenRouter.POST("preview", codegenApi.Preview)
|
||||||
|
codegenRouter.POST("generate", codegenApi.Generate)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
import v1 "sundynix-go/api/v1"
|
||||||
|
|
||||||
|
type RouterGroup struct {
|
||||||
|
CodegenRouter
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
codegenApi = v1.ApiGroupApp.CodegenApiGroup.CodegenApi
|
||||||
|
)
|
||||||
+5
-1
@@ -1,6 +1,8 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sundynix-go/router/codegen"
|
||||||
|
"sundynix-go/router/order"
|
||||||
"sundynix-go/router/system"
|
"sundynix-go/router/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -8,5 +10,7 @@ var GroupApp = new(Group)
|
|||||||
|
|
||||||
// Group 路由组
|
// Group 路由组
|
||||||
type Group struct {
|
type Group struct {
|
||||||
System system.RouterGroup
|
System system.RouterGroup
|
||||||
|
Codegen codegen.RouterGroup
|
||||||
|
Order order.RouterGroup
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import v1 "sundynix-go/api/v1"
|
||||||
|
|
||||||
|
type RouterGroup struct {
|
||||||
|
OrderRouter
|
||||||
|
RefundRouter
|
||||||
|
StockRouter
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
orderApi = v1.ApiGroupApp.OrderApiGroup.OrderApi
|
||||||
|
refundApi = v1.ApiGroupApp.OrderApiGroup.RefundApi
|
||||||
|
stockApi = v1.ApiGroupApp.OrderApiGroup.StockApi
|
||||||
|
)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
type OrderRouter struct{}
|
||||||
|
|
||||||
|
func (r *OrderRouter) InitOrderRouter(Router *gin.RouterGroup) {
|
||||||
|
orderRouter := Router.Group("order")
|
||||||
|
{
|
||||||
|
orderRouter.POST("save", orderApi.Save)
|
||||||
|
orderRouter.POST("update", orderApi.Update)
|
||||||
|
orderRouter.POST("delete", orderApi.Delete)
|
||||||
|
orderRouter.GET("detail", orderApi.Detail)
|
||||||
|
orderRouter.POST("list", orderApi.List)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
type RefundRouter struct{}
|
||||||
|
|
||||||
|
func (r *RefundRouter) InitRefundRouter(Router *gin.RouterGroup) {
|
||||||
|
refundRouter := Router.Group("refund")
|
||||||
|
{
|
||||||
|
refundRouter.POST("save", refundApi.Save)
|
||||||
|
refundRouter.POST("update", refundApi.Update)
|
||||||
|
refundRouter.POST("delete", refundApi.Delete)
|
||||||
|
refundRouter.GET("detail", refundApi.Detail)
|
||||||
|
refundRouter.POST("list", refundApi.List)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
type StockRouter struct{}
|
||||||
|
|
||||||
|
func (r *StockRouter) InitStockRouter(Router *gin.RouterGroup) {
|
||||||
|
stockRouter := Router.Group("stock")
|
||||||
|
{
|
||||||
|
stockRouter.POST("save", stockApi.Save)
|
||||||
|
stockRouter.POST("update", stockApi.Update)
|
||||||
|
stockRouter.POST("delete", stockApi.Delete)
|
||||||
|
stockRouter.GET("detail", stockApi.Detail)
|
||||||
|
stockRouter.POST("list", stockApi.List)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
codegenModel "sundynix-go/model/codegen"
|
||||||
|
)
|
||||||
|
|
||||||
|
// autoRegister 在代码生成后自动修改项目的注册文件
|
||||||
|
// 包括:initialize/gorm.go, initialize/router.go, api/v1/enter.go, router/enter.go, service/enter.go
|
||||||
|
// 以及子模块的 enter.go 文件(增量追加新 feature)
|
||||||
|
func (s *CodegenService) autoRegister(outputDir string, config codegenModel.GenConfig) error {
|
||||||
|
for _, module := range config.Modules {
|
||||||
|
if strings.TrimSpace(module.PackageName) == "" || strings.TrimSpace(module.Name) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg := module.PackageName
|
||||||
|
pascalModule := module.Name
|
||||||
|
|
||||||
|
// 判断是否新模块:检查 router/{pkg}/enter.go 是否已存在
|
||||||
|
routerEnterPath := filepath.Join(outputDir, "router", pkg, "enter.go")
|
||||||
|
isNewModule := !fileExistsOnDisk(routerEnterPath)
|
||||||
|
|
||||||
|
if isNewModule {
|
||||||
|
// 新模块:注册到 5 个顶级文件
|
||||||
|
if err := s.registerGorm(outputDir, module); err != nil {
|
||||||
|
return fmt.Errorf("注册 gorm 迁移失败: %w", err)
|
||||||
|
}
|
||||||
|
if err := s.registerTopEnter(outputDir, pkg, pascalModule); err != nil {
|
||||||
|
return fmt.Errorf("注册顶级 enter 失败: %w", err)
|
||||||
|
}
|
||||||
|
if err := s.registerRouter(outputDir, pkg, pascalModule, module.Features); err != nil {
|
||||||
|
return fmt.Errorf("注册路由初始化失败: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 已有模块:增量注册新 feature
|
||||||
|
if err := s.registerGormIncremental(outputDir, module); err != nil {
|
||||||
|
return fmt.Errorf("增量注册 gorm 迁移失败: %w", err)
|
||||||
|
}
|
||||||
|
if err := s.registerRouterIncremental(outputDir, pkg, pascalModule, module.Features); err != nil {
|
||||||
|
return fmt.Errorf("增量注册路由失败: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerGorm 向 initialize/gorm.go 的 AutoMigrate 中追加所有 feature
|
||||||
|
func (s *CodegenService) registerGorm(outputDir string, module codegenModel.Module) error {
|
||||||
|
gormPath := filepath.Join(outputDir, "initialize", "gorm.go")
|
||||||
|
content, err := os.ReadFile(gormPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("读取 %s 失败: %w", gormPath, err)
|
||||||
|
}
|
||||||
|
text := string(content)
|
||||||
|
pkg := module.PackageName
|
||||||
|
|
||||||
|
// 1. 添加 import
|
||||||
|
importLine := fmt.Sprintf("\t\"sundynix-go/model/%s\"", pkg)
|
||||||
|
if !strings.Contains(text, importLine) {
|
||||||
|
text = strings.Replace(text, "\"go.uber.org/zap\"", importLine+"\n\n\t\"go.uber.org/zap\"", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 在 AutoMigrate 闭合 ) 前插入 model
|
||||||
|
for _, feature := range module.Features {
|
||||||
|
if strings.TrimSpace(feature.Name) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
modelEntry := fmt.Sprintf("\t\t%s.%s{},", pkg, feature.Name)
|
||||||
|
if !strings.Contains(text, modelEntry) {
|
||||||
|
// 找最后一个 ) 之前的位置(AutoMigrate 结束)
|
||||||
|
closeIdx := strings.LastIndex(text, "\t)")
|
||||||
|
if closeIdx > 0 {
|
||||||
|
text = text[:closeIdx] + "\n" + modelEntry + "\n" + text[closeIdx:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.WriteFile(gormPath, []byte(text), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerGormIncremental 增量模式:只追加新 feature 到 AutoMigrate
|
||||||
|
func (s *CodegenService) registerGormIncremental(outputDir string, module codegenModel.Module) error {
|
||||||
|
return s.registerGorm(outputDir, module) // 逻辑相同,Contains 检查保证幂等
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerTopEnter 向 api/v1/enter.go、router/enter.go、service/enter.go 追加新模块
|
||||||
|
func (s *CodegenService) registerTopEnter(outputDir string, pkg, pascalModule string) error {
|
||||||
|
// --- api/v1/enter.go ---
|
||||||
|
apiEnterPath := filepath.Join(outputDir, "api", "v1", "enter.go")
|
||||||
|
if err := appendToEnterFile(apiEnterPath,
|
||||||
|
fmt.Sprintf("\t\"sundynix-go/api/v1/%s\"", pkg),
|
||||||
|
fmt.Sprintf("\t%sApiGroup %s.ApiGroup", pascalModule, pkg),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- router/enter.go ---
|
||||||
|
routerEnterPath := filepath.Join(outputDir, "router", "enter.go")
|
||||||
|
if err := appendToEnterFile(routerEnterPath,
|
||||||
|
fmt.Sprintf("\t\"sundynix-go/router/%s\"", pkg),
|
||||||
|
fmt.Sprintf("\t%s %s.RouterGroup", pascalModule, pkg),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- service/enter.go ---
|
||||||
|
svcEnterPath := filepath.Join(outputDir, "service", "enter.go")
|
||||||
|
if err := appendToEnterFile(svcEnterPath,
|
||||||
|
fmt.Sprintf("\t\"sundynix-go/service/%s\"", pkg),
|
||||||
|
fmt.Sprintf("\t%sServiceGroup %s.ServiceGroup", pascalModule, pkg),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendToEnterFile 向 enter.go 文件追加 import 和 struct 字段
|
||||||
|
func appendToEnterFile(filePath, importLine, structField string) error {
|
||||||
|
content, err := os.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("读取 %s 失败: %w", filePath, err)
|
||||||
|
}
|
||||||
|
text := string(content)
|
||||||
|
|
||||||
|
// 添加 import(如果不存在)
|
||||||
|
if !strings.Contains(text, importLine) {
|
||||||
|
// 在最后一个 import 之前插入
|
||||||
|
lastImportIdx := strings.LastIndex(text, "\t\"")
|
||||||
|
if lastImportIdx > 0 {
|
||||||
|
// 找这行的换行符
|
||||||
|
nlIdx := strings.Index(text[lastImportIdx:], "\n")
|
||||||
|
if nlIdx > 0 {
|
||||||
|
insertPos := lastImportIdx + nlIdx + 1
|
||||||
|
text = text[:insertPos] + importLine + "\n" + text[insertPos:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加 struct 字段(如果不存在)
|
||||||
|
if !strings.Contains(text, structField) {
|
||||||
|
// 在 struct 的 } 之前插入
|
||||||
|
closeBrace := strings.Index(text, "\n}")
|
||||||
|
if closeBrace > 0 {
|
||||||
|
text = text[:closeBrace] + "\n" + structField + text[closeBrace:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.WriteFile(filePath, []byte(text), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerRouter 向 initialize/router.go 追加路由注册代码
|
||||||
|
func (s *CodegenService) registerRouter(outputDir, pkg, pascalModule string, features []codegenModel.Feature) error {
|
||||||
|
routerPath := filepath.Join(outputDir, "initialize", "router.go")
|
||||||
|
content, err := os.ReadFile(routerPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("读取 %s 失败: %w", routerPath, err)
|
||||||
|
}
|
||||||
|
text := string(content)
|
||||||
|
|
||||||
|
// 1. 添加变量声明:xxxRouter := router.GroupApp.Xxx
|
||||||
|
varLine := fmt.Sprintf("\t%sRouter := router.GroupApp.%s", lowerFirst(pkg), pascalModule)
|
||||||
|
if !strings.Contains(text, varLine) {
|
||||||
|
// 在 NeedAuthGroup 行之前插入
|
||||||
|
needAuthIdx := strings.Index(text, "NeedAuthGroup := Router.Group")
|
||||||
|
if needAuthIdx > 0 {
|
||||||
|
text = text[:needAuthIdx] + varLine + "\n\n\t" + text[needAuthIdx:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 添加路由注册:xxxRouter.InitXxxRouter(NeedAuthGroup)
|
||||||
|
for _, feature := range features {
|
||||||
|
if strings.TrimSpace(feature.Name) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
routerCall := fmt.Sprintf("\t\t%sRouter.Init%sRouter(NeedAuthGroup)", lowerFirst(pkg), feature.Name)
|
||||||
|
if !strings.Contains(text, routerCall) {
|
||||||
|
// 在最后一个 Init...Router 行之后插入
|
||||||
|
lastInitIdx := strings.LastIndex(text, "Router(NeedAuthGroup)")
|
||||||
|
if lastInitIdx > 0 {
|
||||||
|
nlIdx := strings.Index(text[lastInitIdx:], "\n")
|
||||||
|
if nlIdx > 0 {
|
||||||
|
insertPos := lastInitIdx + nlIdx
|
||||||
|
comment := fmt.Sprintf(" //%s", feature.Comment)
|
||||||
|
if feature.Comment == "" {
|
||||||
|
comment = ""
|
||||||
|
}
|
||||||
|
text = text[:insertPos] + "\n" + routerCall + comment + text[insertPos:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.WriteFile(routerPath, []byte(text), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerRouterIncremental 增量模式:只追加新 feature 的路由注册
|
||||||
|
func (s *CodegenService) registerRouterIncremental(outputDir, pkg, pascalModule string, features []codegenModel.Feature) error {
|
||||||
|
return s.registerRouter(outputDir, pkg, pascalModule, features) // Contains 检查保证幂等
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileExistsOnDisk 检查文件是否已存在
|
||||||
|
func fileExistsOnDisk(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,979 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
codegenModel "sundynix-go/model/codegen"
|
||||||
|
|
||||||
|
"github.com/glebarez/sqlite"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CodegenService struct{}
|
||||||
|
|
||||||
|
var CodegenServiceApp = new(CodegenService)
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 模板:model 实体(继承 global.BaseModel)
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const modelTmpl = `package {{.PackageName}}
|
||||||
|
|
||||||
|
import "sundynix-go/global"
|
||||||
|
{{if .HasTimeField}}import "time"
|
||||||
|
{{end}}
|
||||||
|
// {{.Feature.Name}} {{.Feature.Comment}}
|
||||||
|
type {{.Feature.Name}} struct {
|
||||||
|
global.BaseModel
|
||||||
|
{{- range .Feature.Fields}}
|
||||||
|
{{.Name}} {{.Type}} ` + "`" + `gorm:"column:{{.ColumnName}}{{if .GormTag}};{{.GormTag}}{{end}}" json:"{{.JsonTag}}"` + "`" + ` // {{.Comment}}
|
||||||
|
{{- end}}
|
||||||
|
{{- range .Feature.Relations}}
|
||||||
|
{{- if eq .Type "OneToOne"}}
|
||||||
|
{{.FieldName}} *{{.TargetFeature}} ` + "`" + `gorm:"foreignKey:{{.ForeignKey}}" json:"{{lowerFirst .FieldName}}"` + "`" + `
|
||||||
|
{{- else if eq .Type "OneToMany"}}
|
||||||
|
{{.FieldName}} []{{.TargetFeature}} ` + "`" + `gorm:"foreignKey:{{.ForeignKey}}" json:"{{lowerFirst .FieldName}}"` + "`" + `
|
||||||
|
{{- else if eq .Type "ManyToMany"}}
|
||||||
|
{{.FieldName}} []{{.TargetFeature}} ` + "`" + `gorm:"many2many:{{.JoinTable}};" json:"{{lowerFirst .FieldName}}"` + "`" + `
|
||||||
|
{{- end}}
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ({{.Feature.Name}}) TableName() string {
|
||||||
|
return "{{.Feature.TableName}}"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 模板:request 结构体(每个模块一个文件,包含所有实体的请求结构体)
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const requestTmpl = `package request
|
||||||
|
{{range .Features}}
|
||||||
|
// ---- {{.Comment}} ----
|
||||||
|
|
||||||
|
// Save{{.Name}}Req 新增{{.Comment}}请求
|
||||||
|
type Save{{.Name}}Req struct {
|
||||||
|
{{- range .Fields}}
|
||||||
|
{{.Name}} {{.Type}} ` + "`" + `json:"{{.JsonTag}}" form:"{{.JsonTag}}"{{if .Required}} binding:"required"{{end}}` + "`" + ` // {{.Comment}}
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update{{.Name}}Req 更新{{.Comment}}请求
|
||||||
|
type Update{{.Name}}Req struct {
|
||||||
|
Id string ` + "`" + `json:"id" binding:"required"` + "`" + ` // ID
|
||||||
|
{{- range .Fields}}
|
||||||
|
{{.Name}} {{.Type}} ` + "`" + `json:"{{.JsonTag}}" form:"{{.JsonTag}}"` + "`" + ` // {{.Comment}}
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List{{.Name}}Req 分页查询{{.Comment}}请求
|
||||||
|
type List{{.Name}}Req struct {
|
||||||
|
Current int ` + "`" + `json:"current" form:"current"` + "`" + ` // 页码
|
||||||
|
PageSize int ` + "`" + `json:"pageSize" form:"pageSize"` + "`" + ` // 每页大小
|
||||||
|
Keyword string ` + "`" + `json:"keyword" form:"keyword"` + "`" + ` // 关键字搜索
|
||||||
|
}
|
||||||
|
{{end}}`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 模板:service 层(使用 request 包的结构体)
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const serviceTmpl = `package {{.PackageName}}
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
|
model "sundynix-go/model/{{.PackageName}}"
|
||||||
|
req "sundynix-go/model/{{.PackageName}}/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
type {{.Feature.Name}}Service struct{}
|
||||||
|
|
||||||
|
var {{.Feature.Name}}ServiceApp = new({{.Feature.Name}}Service)
|
||||||
|
|
||||||
|
func (s *{{.Feature.Name}}Service) Save(r req.Save{{.Feature.Name}}Req) error {
|
||||||
|
data := model.{{.Feature.Name}}{
|
||||||
|
{{- range .Feature.Fields}}
|
||||||
|
{{.Name}}: r.{{.Name}},
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
return global.DB.Create(&data).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *{{.Feature.Name}}Service) Update(r req.Update{{.Feature.Name}}Req) error {
|
||||||
|
updates := map[string]any{
|
||||||
|
{{- range .Feature.Fields}}
|
||||||
|
"{{.ColumnName}}": r.{{.Name}},
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
return global.DB.Model(&model.{{.Feature.Name}}{}).Where("id = ?", r.Id).Updates(updates).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *{{.Feature.Name}}Service) Delete(ids []string) error {
|
||||||
|
return global.DB.Where("id IN ?", ids).Delete(&model.{{.Feature.Name}}{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *{{.Feature.Name}}Service) Detail(id string) (data *model.{{.Feature.Name}}, err error) {
|
||||||
|
var record model.{{.Feature.Name}}
|
||||||
|
err = global.DB.Where("id = ?", id).First(&record).Error
|
||||||
|
return &record, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *{{.Feature.Name}}Service) List(r req.List{{.Feature.Name}}Req) (list []model.{{.Feature.Name}}, total int64, err error) {
|
||||||
|
if r.PageSize <= 0 {
|
||||||
|
r.PageSize = 10
|
||||||
|
}
|
||||||
|
if r.Current <= 0 {
|
||||||
|
r.Current = 1
|
||||||
|
}
|
||||||
|
db := global.DB.Model(&model.{{.Feature.Name}}{})
|
||||||
|
if r.Keyword != "" {
|
||||||
|
db = db.Where("id LIKE ?", "%"+r.Keyword+"%")
|
||||||
|
}
|
||||||
|
if err = db.Count(&total).Error; err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = db.Limit(r.PageSize).Offset(r.PageSize * (r.Current - 1)).Find(&list).Error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 模板:service enter.go
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const serviceEnterTmpl = `package {{.PackageName}}
|
||||||
|
|
||||||
|
type ServiceGroup struct {
|
||||||
|
{{- range .Features}}
|
||||||
|
{{.Name}}Service
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 模板:api handler 层(使用 request 包的结构体)
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const apiTmpl = `package {{.PackageName}}
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
|
"sundynix-go/model/commom/response"
|
||||||
|
req "sundynix-go/model/{{.PackageName}}/request"
|
||||||
|
"sundynix-go/service"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type {{.Feature.Name}}Api struct{}
|
||||||
|
|
||||||
|
var {{.LowerName}}Service = service.ServiceGroupApp.{{.PascalModuleName}}ServiceGroup.{{.Feature.Name}}Service
|
||||||
|
|
||||||
|
// Save
|
||||||
|
// @Tags {{.Feature.Comment}}管理
|
||||||
|
// @Summary 新增{{.Feature.Comment}}
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.Save{{.Feature.Name}}Req true "新增{{.Feature.Comment}}参数"
|
||||||
|
// @Success 200 {object} response.Response "新增成功"
|
||||||
|
// @Router /{{.RouterPrefix}}/save [post]
|
||||||
|
func (a *{{.Feature.Name}}Api) Save(c *gin.Context) {
|
||||||
|
var r req.Save{{.Feature.Name}}Req
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := {{.LowerName}}Service.Save(r); err != nil {
|
||||||
|
global.Logger.Error("新增{{.Feature.Comment}}失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("新增成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update
|
||||||
|
// @Tags {{.Feature.Comment}}管理
|
||||||
|
// @Summary 更新{{.Feature.Comment}}
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.Update{{.Feature.Name}}Req true "更新{{.Feature.Comment}}参数"
|
||||||
|
// @Success 200 {object} response.Response "更新成功"
|
||||||
|
// @Router /{{.RouterPrefix}}/update [post]
|
||||||
|
func (a *{{.Feature.Name}}Api) Update(c *gin.Context) {
|
||||||
|
var r req.Update{{.Feature.Name}}Req
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := {{.LowerName}}Service.Update(r); err != nil {
|
||||||
|
global.Logger.Error("更新{{.Feature.Comment}}失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("更新成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
// @Tags {{.Feature.Comment}}管理
|
||||||
|
// @Summary 删除{{.Feature.Comment}}(支持批量)
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body object{ids=[]string} true "id列表"
|
||||||
|
// @Success 200 {object} response.Response "删除成功"
|
||||||
|
// @Router /{{.RouterPrefix}}/delete [post]
|
||||||
|
func (a *{{.Feature.Name}}Api) Delete(c *gin.Context) {
|
||||||
|
var req struct {
|
||||||
|
Ids []string ` + "`" + `json:"ids" binding:"required,min=1"` + "`" + `
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := {{.LowerName}}Service.Delete(req.Ids); err != nil {
|
||||||
|
global.Logger.Error("删除{{.Feature.Comment}}失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("删除成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detail
|
||||||
|
// @Tags {{.Feature.Comment}}管理
|
||||||
|
// @Summary 获取{{.Feature.Comment}}详情
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @Produce json
|
||||||
|
// @Param id query string true "ID"
|
||||||
|
// @Success 200 {object} response.Response "获取详情成功"
|
||||||
|
// @Router /{{.RouterPrefix}}/detail [get]
|
||||||
|
func (a *{{.Feature.Name}}Api) Detail(c *gin.Context) {
|
||||||
|
id := c.Query("id")
|
||||||
|
data, err := {{.LowerName}}Service.Detail(id)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取{{.Feature.Comment}}详情失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(data, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List
|
||||||
|
// @Tags {{.Feature.Comment}}管理
|
||||||
|
// @Summary 分页获取{{.Feature.Comment}}列表
|
||||||
|
// @Security BasicAuth
|
||||||
|
// @accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body req.List{{.Feature.Name}}Req true "分页参数"
|
||||||
|
// @Success 200 {object} response.Response{data=response.PageResult} "获取列表成功"
|
||||||
|
// @Router /{{.RouterPrefix}}/list [post]
|
||||||
|
func (a *{{.Feature.Name}}Api) List(c *gin.Context) {
|
||||||
|
var r req.List{{.Feature.Name}}Req
|
||||||
|
if err := c.ShouldBindJSON(&r); err != nil {
|
||||||
|
response.FailWithMsg("参数错误:"+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list, total, err := {{.LowerName}}Service.List(r)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取{{.Feature.Comment}}列表失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(response.PageResult{
|
||||||
|
List: list,
|
||||||
|
Total: total,
|
||||||
|
Page: r.Current,
|
||||||
|
PageSize: r.PageSize,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 模板:api enter.go
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const apiEnterTmpl = `package {{.PackageName}}
|
||||||
|
|
||||||
|
type ApiGroup struct {
|
||||||
|
{{- range .Features}}
|
||||||
|
{{.Name}}Api
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 模板:router
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const routerTmpl = `package {{.PackageName}}
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
type {{.Feature.Name}}Router struct{}
|
||||||
|
|
||||||
|
func (r *{{.Feature.Name}}Router) Init{{.Feature.Name}}Router(Router *gin.RouterGroup) {
|
||||||
|
{{.LowerName}}Router := Router.Group("{{.RouterGroup}}")
|
||||||
|
{
|
||||||
|
{{.LowerName}}Router.POST("save", {{.LowerName}}Api.Save)
|
||||||
|
{{.LowerName}}Router.POST("update", {{.LowerName}}Api.Update)
|
||||||
|
{{.LowerName}}Router.POST("delete", {{.LowerName}}Api.Delete)
|
||||||
|
{{.LowerName}}Router.GET("detail", {{.LowerName}}Api.Detail)
|
||||||
|
{{.LowerName}}Router.POST("list", {{.LowerName}}Api.List)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 模板:router enter.go
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const routerEnterTmpl = `package {{.PackageName}}
|
||||||
|
|
||||||
|
import v1 "sundynix-go/api/v1"
|
||||||
|
|
||||||
|
type RouterGroup struct {
|
||||||
|
{{- range .Features}}
|
||||||
|
{{.Name}}Router
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
{{- range .Features}}
|
||||||
|
{{lowerFirst .Name}}Api = v1.ApiGroupApp.{{.PascalModuleName}}ApiGroup.{{.Name}}Api
|
||||||
|
{{- end}}
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 前端模板:TypeScript 类型定义
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const feTsTypeTmpl = `// {{.Module.Name}} 模块类型定义(自动生成,请勿手动修改)
|
||||||
|
import type { BaseModel } from '@/types'
|
||||||
|
{{range .Features}}
|
||||||
|
// ---- {{.Comment}} ----
|
||||||
|
|
||||||
|
/** {{.Comment}}实体 */
|
||||||
|
export interface {{.Name}} extends BaseModel {
|
||||||
|
{{- range .Fields}}
|
||||||
|
{{.JsonTag}}: {{goTypeToTs .Type}} // {{.Comment}}
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 新增{{.Comment}}请求 */
|
||||||
|
export interface Save{{.Name}}Req {
|
||||||
|
{{- range .Fields}}
|
||||||
|
{{.JsonTag}}{{if not .Required}}?{{end}}: {{goTypeToTs .Type}} // {{.Comment}}
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新{{.Comment}}请求 */
|
||||||
|
export interface Update{{.Name}}Req {
|
||||||
|
id: string
|
||||||
|
{{- range .Fields}}
|
||||||
|
{{.JsonTag}}?: {{goTypeToTs .Type}} // {{.Comment}}
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分页查询{{.Comment}}请求 */
|
||||||
|
export interface List{{.Name}}Req {
|
||||||
|
current?: number
|
||||||
|
pageSize?: number
|
||||||
|
keyword?: string
|
||||||
|
}
|
||||||
|
{{end}}`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 前端模板:API service (Axios)
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const feApiTmpl = `import { get, post } from '@/lib/request'
|
||||||
|
import type {
|
||||||
|
{{.Feature.Name}},
|
||||||
|
Save{{.Feature.Name}}Req,
|
||||||
|
Update{{.Feature.Name}}Req,
|
||||||
|
List{{.Feature.Name}}Req,
|
||||||
|
} from '@/types/{{.Module.PackageName}}'
|
||||||
|
import type { PageResult } from '@/types'
|
||||||
|
|
||||||
|
const BASE = '/{{.Module.PackageName}}/{{.SnakeName}}'
|
||||||
|
|
||||||
|
export const {{lowerFirst .Feature.Name}}Api = {
|
||||||
|
save: (data: Save{{.Feature.Name}}Req) =>
|
||||||
|
post<void>(` + "`" + `${BASE}/save` + "`" + `, data),
|
||||||
|
|
||||||
|
update: (data: Update{{.Feature.Name}}Req) =>
|
||||||
|
post<void>(` + "`" + `${BASE}/update` + "`" + `, data),
|
||||||
|
|
||||||
|
delete: (ids: string[]) =>
|
||||||
|
post<void>(` + "`" + `${BASE}/delete` + "`" + `, { ids }),
|
||||||
|
|
||||||
|
detail: (id: string) =>
|
||||||
|
get<{{.Feature.Name}}>(` + "`" + `${BASE}/detail` + "`" + `, { id }),
|
||||||
|
|
||||||
|
list: (params: List{{.Feature.Name}}Req) =>
|
||||||
|
post<PageResult<{{.Feature.Name}}>>(` + "`" + `${BASE}/list` + "`" + `, params),
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 前端模板:React 管理页面
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
const fePageTmpl = `import { useState, useEffect } from 'react'
|
||||||
|
import { {{lowerFirst .Feature.Name}}Api } from '@/api/{{.Module.PackageName}}/{{.SnakeName}}'
|
||||||
|
import type { {{.Feature.Name}}, List{{.Feature.Name}}Req } from '@/types/{{.Module.PackageName}}'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { Input } from '@/components/ui/input'
|
||||||
|
import { Card, CardContent } from '@/components/ui/card'
|
||||||
|
import { toast } from 'sonner'
|
||||||
|
import { Plus, Pencil, Trash2, Search, RefreshCw } from 'lucide-react'
|
||||||
|
|
||||||
|
export default function {{.Feature.Name}}Page() {
|
||||||
|
const [list, setList] = useState<{{.Feature.Name}}[]>([])
|
||||||
|
const [total, setTotal] = useState(0)
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [params, setParams] = useState<List{{.Feature.Name}}Req>({ current: 1, pageSize: 10, keyword: '' })
|
||||||
|
|
||||||
|
const load = async () => {
|
||||||
|
setLoading(true)
|
||||||
|
try {
|
||||||
|
const res = await {{lowerFirst .Feature.Name}}Api.list(params)
|
||||||
|
setList(res.list)
|
||||||
|
setTotal(res.total)
|
||||||
|
} catch {}
|
||||||
|
finally { setLoading(false) }
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => { load() }, [params.current])
|
||||||
|
|
||||||
|
const handleDelete = async (id: string) => {
|
||||||
|
if (!confirm('确认删除?')) return
|
||||||
|
try {
|
||||||
|
await {{lowerFirst .Feature.Name}}Api.delete([id])
|
||||||
|
toast.success('删除成功')
|
||||||
|
load()
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(total / (params.pageSize ?? 10))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-xl font-semibold">{{.Feature.Comment}}管理</h2>
|
||||||
|
<p className="text-sm text-muted-foreground">共 {total} 条记录</p>
|
||||||
|
</div>
|
||||||
|
<Button size="sm" className="gap-1"><Plus className="h-4 w-4" /> 新增</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardContent className="pt-4">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Input
|
||||||
|
placeholder="关键字搜索"
|
||||||
|
value={params.keyword}
|
||||||
|
onChange={e => setParams(p => ({ ...p, keyword: e.target.value, current: 1 }))}
|
||||||
|
className="max-w-60"
|
||||||
|
/>
|
||||||
|
<Button variant="outline" size="sm" onClick={load}><Search className="h-4 w-4 mr-1" />搜索</Button>
|
||||||
|
<Button variant="ghost" size="sm" onClick={() => setParams(p => ({ ...p, keyword: '', current: 1 }))}>
|
||||||
|
<RefreshCw className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardContent className="p-0">
|
||||||
|
<table className="w-full text-sm">
|
||||||
|
<thead className="border-b bg-muted/40">
|
||||||
|
<tr>
|
||||||
|
{{- range .Feature.Fields}}{{if .Comment}}
|
||||||
|
<th className="px-4 py-3 text-left font-medium text-muted-foreground">{{.Comment}}</th>
|
||||||
|
{{- end}}{{end}}
|
||||||
|
<th className="px-4 py-3 text-left font-medium text-muted-foreground">创建时间</th>
|
||||||
|
<th className="px-4 py-3 text-left font-medium text-muted-foreground">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{loading ? (
|
||||||
|
<tr><td colSpan={ {{- .ColCount -}} } className="py-12 text-center text-muted-foreground">加载中…</td></tr>
|
||||||
|
) : list.length === 0 ? (
|
||||||
|
<tr><td colSpan={ {{- .ColCount -}} } className="py-12 text-center text-muted-foreground">暂无数据</td></tr>
|
||||||
|
) : list.map(item => (
|
||||||
|
<tr key={item.id} className="border-b last:border-b-0 hover:bg-muted/30 transition-colors">
|
||||||
|
{{- range .Feature.Fields}}{{if .JsonTag}}<td className="px-4 py-3">{String(item.{{.JsonTag}} ?? '—')}</td>{{end}}{{end}}
|
||||||
|
<td className="px-4 py-3 text-xs text-muted-foreground">{new Date(item.createdAt).toLocaleString()}</td>
|
||||||
|
<td className="px-4 py-3">
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<Button variant="ghost" size="icon" className="h-7 w-7"><Pencil className="h-3.5 w-3.5" /></Button>
|
||||||
|
<Button variant="ghost" size="icon" className="h-7 w-7 text-destructive" onClick={() => handleDelete(item.id)}>
|
||||||
|
<Trash2 className="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="flex items-center justify-between border-t px-4 py-3">
|
||||||
|
<span className="text-xs text-muted-foreground">第 {params.current} / {totalPages} 页</span>
|
||||||
|
<div className="flex gap-1">
|
||||||
|
<Button variant="outline" size="sm" disabled={(params.current ?? 1) <= 1}
|
||||||
|
onClick={() => setParams(p => ({ ...p, current: (p.current ?? 1) - 1 }))}>上一页</Button>
|
||||||
|
<Button variant="outline" size="sm" disabled={(params.current ?? 1) >= totalPages}
|
||||||
|
onClick={() => setParams(p => ({ ...p, current: (p.current ?? 1) + 1 }))}>下一页</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 辅助函数
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
func lowerFirst(s string) string {
|
||||||
|
if s == "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return strings.ToLower(s[:1]) + s[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasTimeField(feature codegenModel.Feature) bool {
|
||||||
|
for _, f := range feature.Fields {
|
||||||
|
if f.Type == "time.Time" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// goTypeToTs 将 Go 类型映射为 TypeScript 类型
|
||||||
|
func goTypeToTs(goType string) string {
|
||||||
|
switch goType {
|
||||||
|
case "int", "int8", "int16", "int32", "int64",
|
||||||
|
"uint", "uint8", "uint16", "uint32", "uint64",
|
||||||
|
"float32", "float64":
|
||||||
|
return "number"
|
||||||
|
case "bool":
|
||||||
|
return "boolean"
|
||||||
|
case "time.Time":
|
||||||
|
return "string"
|
||||||
|
default:
|
||||||
|
return "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// TestConnection 测试数据库连接
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
func (s *CodegenService) TestConnection(cfg codegenModel.DbConfig) error {
|
||||||
|
_, err := openDB(cfg)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func openDB(cfg codegenModel.DbConfig) (*gorm.DB, error) {
|
||||||
|
switch strings.ToLower(cfg.DbType) {
|
||||||
|
case "mysql":
|
||||||
|
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||||
|
cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.DbName)
|
||||||
|
return gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
case "postgres", "postgresql":
|
||||||
|
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
|
||||||
|
cfg.Host, cfg.User, cfg.Password, cfg.DbName, cfg.Port)
|
||||||
|
return gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||||
|
case "sqlite":
|
||||||
|
return gorm.Open(sqlite.Open(cfg.DbName), &gorm.Config{})
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("不支持的数据库类型: %s", cfg.DbType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Preview 预览生成代码
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
func (s *CodegenService) Preview(config codegenModel.GenConfig) ([]codegenModel.PreviewFile, error) {
|
||||||
|
backendFiles, err := s.renderAll(config, config.OutputDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if config.FrontendOutputDir != "" {
|
||||||
|
feFiles, err := s.renderFrontend(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
backendFiles = append(backendFiles, feFiles...)
|
||||||
|
}
|
||||||
|
return backendFiles, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Generate 生成并写入文件
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
func (s *CodegenService) Generate(config codegenModel.GenConfig) (*codegenModel.GenResult, error) {
|
||||||
|
outputDir := config.OutputDir
|
||||||
|
if outputDir == "" {
|
||||||
|
cwd, _ := os.Getwd()
|
||||||
|
outputDir = cwd
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 渲染后端文件
|
||||||
|
backendFiles, err := s.renderAll(config, outputDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 自动注册(必须在写入文件之前,否则 enter.go 已存在导致误判为已有模块)
|
||||||
|
regMsg := ""
|
||||||
|
if err := s.autoRegister(outputDir, config); err != nil {
|
||||||
|
regMsg = fmt.Sprintf("⚠️ 自动注册失败: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
regMsg = "✅ 自动注册成功(gorm/router/enter)"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 写入后端文件(增量模式下跳过已存在文件)
|
||||||
|
written, skipped := writeFilesIncremental(outputDir, backendFiles, config.Overwrite)
|
||||||
|
|
||||||
|
allFiles := backendFiles
|
||||||
|
|
||||||
|
// 4. 生成前端文件(如果配置了前端输出目录)
|
||||||
|
if config.FrontendOutputDir != "" {
|
||||||
|
feFiles, err := s.renderFrontend(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
w, sk := writeFilesIncremental(config.FrontendOutputDir, feFiles, config.Overwrite)
|
||||||
|
written += w
|
||||||
|
skipped += sk
|
||||||
|
allFiles = append(allFiles, feFiles...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &codegenModel.GenResult{
|
||||||
|
OutputDir: outputDir,
|
||||||
|
Files: allFiles,
|
||||||
|
Message: fmt.Sprintf("写入 %d 个文件,跳过 %d 个已存在文件。%s", written, skipped, regMsg),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeFilesIncremental 写入文件,支持增量模式
|
||||||
|
// overwrite=false 时,已存在的文件会被跳过
|
||||||
|
// 返回 (写入数, 跳过数)
|
||||||
|
func writeFilesIncremental(baseDir string, files []codegenModel.PreviewFile, overwrite bool) (written int, skipped int) {
|
||||||
|
for _, f := range files {
|
||||||
|
fullPath := filepath.Join(baseDir, f.FilePath)
|
||||||
|
// 增量模式下跳过已存在文件(但 AlwaysOverwrite 的聚合文件始终覆盖)
|
||||||
|
if !overwrite && !f.AlwaysOverwrite {
|
||||||
|
if _, err := os.Stat(fullPath); err == nil {
|
||||||
|
skipped++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(fullPath, []byte(f.Content), 0644); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
written++
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderFrontend 渲染前端 TypeScript / React 文件
|
||||||
|
func (s *CodegenService) renderFrontend(config codegenModel.GenConfig) ([]codegenModel.PreviewFile, error) {
|
||||||
|
var result []codegenModel.PreviewFile
|
||||||
|
|
||||||
|
funcMap := template.FuncMap{
|
||||||
|
"lowerFirst": lowerFirst,
|
||||||
|
"goTypeToTs": goTypeToTs,
|
||||||
|
"not": func(b bool) bool { return !b },
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, module := range config.Modules {
|
||||||
|
// 跳过未填写包名的模块
|
||||||
|
if strings.TrimSpace(module.PackageName) == "" || strings.TrimSpace(module.Name) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// ---- TypeScript 类型(模块级,所有实体合并到 index.ts)----
|
||||||
|
tsData := struct {
|
||||||
|
Module codegenModel.Module
|
||||||
|
Features []codegenModel.Feature
|
||||||
|
}{module, module.Features}
|
||||||
|
tsContent, err := renderTmpl("fe_ts_type", feTsTypeTmpl, funcMap, tsData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("src", "types", module.PackageName, "index.ts"),
|
||||||
|
Content: tsContent,
|
||||||
|
AlwaysOverwrite: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, feature := range module.Features {
|
||||||
|
// 跳过未命名的实体
|
||||||
|
if strings.TrimSpace(feature.Name) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
snakeName := toSnake(feature.Name)
|
||||||
|
|
||||||
|
feData := struct {
|
||||||
|
Module codegenModel.Module
|
||||||
|
Feature codegenModel.Feature
|
||||||
|
SnakeName string
|
||||||
|
ColCount int
|
||||||
|
}{module, feature, snakeName, len(feature.Fields) + 2}
|
||||||
|
|
||||||
|
// API service
|
||||||
|
apiContent, err := renderTmpl("fe_api", feApiTmpl, funcMap, feData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("src", "api", module.PackageName, snakeName+".ts"),
|
||||||
|
Content: apiContent,
|
||||||
|
})
|
||||||
|
|
||||||
|
// React page
|
||||||
|
pageContent, err := renderTmpl("fe_page", fePageTmpl, funcMap, feData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("src", "pages", module.PackageName, feature.Name+"Page.tsx"),
|
||||||
|
Content: pageContent,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// renderAll 渲染所有模块的所有文件
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
func (s *CodegenService) renderAll(config codegenModel.GenConfig, outputDir string) ([]codegenModel.PreviewFile, error) {
|
||||||
|
var result []codegenModel.PreviewFile
|
||||||
|
|
||||||
|
funcMap := template.FuncMap{
|
||||||
|
"lowerFirst": lowerFirst,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, module := range config.Modules {
|
||||||
|
// 跳过未填写包名的模块
|
||||||
|
if strings.TrimSpace(module.PackageName) == "" || strings.TrimSpace(module.Name) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pkg := module.PackageName
|
||||||
|
pascalModule := module.Name
|
||||||
|
|
||||||
|
type featureEntry struct {
|
||||||
|
Name string
|
||||||
|
PascalModuleName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发现已存在的 feature(扫描 service/{pkg}/ 下的 *_service.go 文件)
|
||||||
|
existingFeatures := discoverExistingFeatures(outputDir, pkg)
|
||||||
|
|
||||||
|
// 合并:已有 feature + 当前配置中的 feature(去重)
|
||||||
|
featureSet := make(map[string]bool)
|
||||||
|
var allFeatureEntries []featureEntry
|
||||||
|
for _, name := range existingFeatures {
|
||||||
|
if !featureSet[name] {
|
||||||
|
featureSet[name] = true
|
||||||
|
allFeatureEntries = append(allFeatureEntries, featureEntry{name, pascalModule})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, f := range module.Features {
|
||||||
|
if strings.TrimSpace(f.Name) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !featureSet[f.Name] {
|
||||||
|
featureSet[f.Name] = true
|
||||||
|
allFeatureEntries = append(allFeatureEntries, featureEntry{f.Name, pascalModule})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enterData := struct {
|
||||||
|
PackageName string
|
||||||
|
Features []featureEntry
|
||||||
|
}{pkg, allFeatureEntries}
|
||||||
|
|
||||||
|
// service/enter.go(始终覆盖,包含所有已有+新增 feature)
|
||||||
|
svcEnter, err := renderTmpl("service_enter", serviceEnterTmpl, funcMap, enterData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("service", pkg, "enter.go"),
|
||||||
|
Content: svcEnter,
|
||||||
|
AlwaysOverwrite: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// api/v1/enter.go
|
||||||
|
apiEnter, err := renderTmpl("api_enter", apiEnterTmpl, funcMap, enterData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("api", "v1", pkg, "enter.go"),
|
||||||
|
Content: apiEnter,
|
||||||
|
AlwaysOverwrite: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// router/enter.go
|
||||||
|
routerEnter, err := renderTmpl("router_enter", routerEnterTmpl, funcMap, enterData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("router", pkg, "enter.go"),
|
||||||
|
Content: routerEnter,
|
||||||
|
AlwaysOverwrite: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ---- request 结构体(按 feature 分文件,增量安全)----
|
||||||
|
for _, feature := range module.Features {
|
||||||
|
if strings.TrimSpace(feature.Name) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
reqData := struct {
|
||||||
|
PackageName string
|
||||||
|
Features []codegenModel.Feature
|
||||||
|
}{pkg, []codegenModel.Feature{feature}}
|
||||||
|
reqContent, err := renderTmpl("request", requestTmpl, funcMap, reqData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("model", pkg, "request", toSnake(feature.Name)+"_request.go"),
|
||||||
|
Content: reqContent,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每个 Feature 生成:model / service / api / router
|
||||||
|
for _, feature := range module.Features {
|
||||||
|
// 跳过未命名的实体
|
||||||
|
if strings.TrimSpace(feature.Name) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lower := lowerFirst(feature.Name)
|
||||||
|
snakeName := toSnake(feature.Name)
|
||||||
|
routerGroup := snakeName
|
||||||
|
routerPrefix := pkg + "/" + snakeName
|
||||||
|
|
||||||
|
// ---- model ----
|
||||||
|
modelData := struct {
|
||||||
|
PackageName string
|
||||||
|
Feature codegenModel.Feature
|
||||||
|
HasTimeField bool
|
||||||
|
}{pkg, feature, hasTimeField(feature)}
|
||||||
|
modelContent, err := renderTmpl("model", modelTmpl, funcMap, modelData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("model", pkg, snakeName+".go"),
|
||||||
|
Content: modelContent,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ---- service ----
|
||||||
|
svcData := struct {
|
||||||
|
PackageName string
|
||||||
|
Feature codegenModel.Feature
|
||||||
|
}{pkg, feature}
|
||||||
|
svcContent, err := renderTmpl("service", serviceTmpl, funcMap, svcData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("service", pkg, snakeName+"_service.go"),
|
||||||
|
Content: svcContent,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ---- api handler ----
|
||||||
|
apiData := struct {
|
||||||
|
PackageName string
|
||||||
|
Feature codegenModel.Feature
|
||||||
|
LowerName string
|
||||||
|
RouterPrefix string
|
||||||
|
PascalModuleName string
|
||||||
|
}{pkg, feature, lower, routerPrefix, pascalModule}
|
||||||
|
apiContent, err := renderTmpl("api", apiTmpl, funcMap, apiData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("api", "v1", pkg, snakeName+".go"),
|
||||||
|
Content: apiContent,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ---- router ----
|
||||||
|
routerData := struct {
|
||||||
|
PackageName string
|
||||||
|
Feature codegenModel.Feature
|
||||||
|
LowerName string
|
||||||
|
RouterGroup string
|
||||||
|
}{pkg, feature, lower, routerGroup}
|
||||||
|
routerContent, err := renderTmpl("router", routerTmpl, funcMap, routerData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, codegenModel.PreviewFile{
|
||||||
|
FilePath: filepath.Join("router", pkg, snakeName+"_router.go"),
|
||||||
|
Content: routerContent,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderTmpl(name, tmplStr string, funcMap template.FuncMap, data any) (string, error) {
|
||||||
|
t, err := template.New(name).Funcs(funcMap).Parse(tmplStr)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("解析模板 [%s] 失败: %w", name, err)
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err = t.Execute(&buf, data); err != nil {
|
||||||
|
return "", fmt.Errorf("渲染模板 [%s] 失败: %w", name, err)
|
||||||
|
}
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// toSnake 将 PascalCase 转为 snake_case
|
||||||
|
func toSnake(s string) string {
|
||||||
|
var result []rune
|
||||||
|
for i, r := range s {
|
||||||
|
if r >= 'A' && r <= 'Z' {
|
||||||
|
if i > 0 {
|
||||||
|
result = append(result, '_')
|
||||||
|
}
|
||||||
|
result = append(result, r+32)
|
||||||
|
} else {
|
||||||
|
result = append(result, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(result)
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
type ServiceGroup struct {
|
||||||
|
CodegenService
|
||||||
|
}
|
||||||
+8
-2
@@ -1,9 +1,15 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import "sundynix-go/service/system"
|
import (
|
||||||
|
"sundynix-go/service/codegen"
|
||||||
|
"sundynix-go/service/order"
|
||||||
|
"sundynix-go/service/system"
|
||||||
|
)
|
||||||
|
|
||||||
var ServiceGroupApp = new(ServiceGroup)
|
var ServiceGroupApp = new(ServiceGroup)
|
||||||
|
|
||||||
type ServiceGroup struct {
|
type ServiceGroup struct {
|
||||||
SystemServiceGroup system.ServiceGroup
|
SystemServiceGroup system.ServiceGroup
|
||||||
|
CodegenServiceGroup codegen.ServiceGroup
|
||||||
|
OrderServiceGroup order.ServiceGroup
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
type ServiceGroup struct {
|
||||||
|
OrderService
|
||||||
|
RefundService
|
||||||
|
StockService
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
|
model "sundynix-go/model/order"
|
||||||
|
req "sundynix-go/model/order/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrderService struct{}
|
||||||
|
|
||||||
|
var OrderServiceApp = new(OrderService)
|
||||||
|
|
||||||
|
func (s *OrderService) Save(r req.SaveOrderReq) error {
|
||||||
|
data := model.Order{
|
||||||
|
UserId: r.UserId,
|
||||||
|
}
|
||||||
|
return global.DB.Create(&data).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OrderService) Update(r req.UpdateOrderReq) error {
|
||||||
|
updates := map[string]any{
|
||||||
|
"user_id": r.UserId,
|
||||||
|
}
|
||||||
|
return global.DB.Model(&model.Order{}).Where("id = ?", r.Id).Updates(updates).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OrderService) Delete(ids []string) error {
|
||||||
|
return global.DB.Where("id IN ?", ids).Delete(&model.Order{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OrderService) Detail(id string) (data *model.Order, err error) {
|
||||||
|
var record model.Order
|
||||||
|
err = global.DB.Where("id = ?", id).First(&record).Error
|
||||||
|
return &record, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OrderService) List(r req.ListOrderReq) (list []model.Order, total int64, err error) {
|
||||||
|
if r.PageSize <= 0 {
|
||||||
|
r.PageSize = 10
|
||||||
|
}
|
||||||
|
if r.Current <= 0 {
|
||||||
|
r.Current = 1
|
||||||
|
}
|
||||||
|
db := global.DB.Model(&model.Order{})
|
||||||
|
if r.Keyword != "" {
|
||||||
|
db = db.Where("id LIKE ?", "%"+r.Keyword+"%")
|
||||||
|
}
|
||||||
|
if err = db.Count(&total).Error; err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = db.Limit(r.PageSize).Offset(r.PageSize * (r.Current - 1)).Find(&list).Error
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
|
model "sundynix-go/model/order"
|
||||||
|
req "sundynix-go/model/order/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RefundService struct{}
|
||||||
|
|
||||||
|
var RefundServiceApp = new(RefundService)
|
||||||
|
|
||||||
|
func (s *RefundService) Save(r req.SaveRefundReq) error {
|
||||||
|
data := model.Refund{
|
||||||
|
UserId: r.UserId,
|
||||||
|
}
|
||||||
|
return global.DB.Create(&data).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RefundService) Update(r req.UpdateRefundReq) error {
|
||||||
|
updates := map[string]any{
|
||||||
|
"user_id": r.UserId,
|
||||||
|
}
|
||||||
|
return global.DB.Model(&model.Refund{}).Where("id = ?", r.Id).Updates(updates).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RefundService) Delete(ids []string) error {
|
||||||
|
return global.DB.Where("id IN ?", ids).Delete(&model.Refund{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RefundService) Detail(id string) (data *model.Refund, err error) {
|
||||||
|
var record model.Refund
|
||||||
|
err = global.DB.Where("id = ?", id).First(&record).Error
|
||||||
|
return &record, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RefundService) List(r req.ListRefundReq) (list []model.Refund, total int64, err error) {
|
||||||
|
if r.PageSize <= 0 {
|
||||||
|
r.PageSize = 10
|
||||||
|
}
|
||||||
|
if r.Current <= 0 {
|
||||||
|
r.Current = 1
|
||||||
|
}
|
||||||
|
db := global.DB.Model(&model.Refund{})
|
||||||
|
if r.Keyword != "" {
|
||||||
|
db = db.Where("id LIKE ?", "%"+r.Keyword+"%")
|
||||||
|
}
|
||||||
|
if err = db.Count(&total).Error; err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = db.Limit(r.PageSize).Offset(r.PageSize * (r.Current - 1)).Find(&list).Error
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package order
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
|
model "sundynix-go/model/order"
|
||||||
|
req "sundynix-go/model/order/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StockService struct{}
|
||||||
|
|
||||||
|
var StockServiceApp = new(StockService)
|
||||||
|
|
||||||
|
func (s *StockService) Save(r req.SaveStockReq) error {
|
||||||
|
data := model.Stock{
|
||||||
|
Amount: r.Amount,
|
||||||
|
}
|
||||||
|
return global.DB.Create(&data).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StockService) Update(r req.UpdateStockReq) error {
|
||||||
|
updates := map[string]any{
|
||||||
|
"amount": r.Amount,
|
||||||
|
}
|
||||||
|
return global.DB.Model(&model.Stock{}).Where("id = ?", r.Id).Updates(updates).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StockService) Delete(ids []string) error {
|
||||||
|
return global.DB.Where("id IN ?", ids).Delete(&model.Stock{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StockService) Detail(id string) (data *model.Stock, err error) {
|
||||||
|
var record model.Stock
|
||||||
|
err = global.DB.Where("id = ?", id).First(&record).Error
|
||||||
|
return &record, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StockService) List(r req.ListStockReq) (list []model.Stock, total int64, err error) {
|
||||||
|
if r.PageSize <= 0 {
|
||||||
|
r.PageSize = 10
|
||||||
|
}
|
||||||
|
if r.Current <= 0 {
|
||||||
|
r.Current = 1
|
||||||
|
}
|
||||||
|
db := global.DB.Model(&model.Stock{})
|
||||||
|
if r.Keyword != "" {
|
||||||
|
db = db.Where("id LIKE ?", "%"+r.Keyword+"%")
|
||||||
|
}
|
||||||
|
if err = db.Count(&total).Error; err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = db.Limit(r.PageSize).Offset(r.PageSize * (r.Current - 1)).Find(&list).Error
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// This file is ONLY used as a template reference for the codegen service.
|
||||||
|
// The actual templates are embedded as string constants in the service.
|
||||||
Reference in New Issue
Block a user