public: 发布2.8.0版本 (#1998)

* feat:修改token获取优先级,优先从header获取

* feat: 增加业务ctx的传递

* fix文件选择问题,
有公共函数onDownloadFile,去掉downloadFile

* 没问题

* feat: 增加context引入

* fix: 修复图片多选的情况下点击确定抽屉无法收起的bug

* feat: 提高header的token优先级,优化导出表格逻辑,不再依赖于cookie鉴权

---------

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: task <121913992@qq.com>
This commit is contained in:
PiexlMax(奇淼
2025-03-15 13:31:33 +08:00
committed by GitHub
parent f776a061ce
commit ab75bc7f59
29 changed files with 416 additions and 100 deletions

View File

@@ -3,6 +3,9 @@ package system
import (
"fmt"
"net/http"
"net/url"
"sync"
"time"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
@@ -15,6 +18,33 @@ import (
"go.uber.org/zap"
)
// 用于token一次性存储
var (
exportTokenCache = make(map[string]interface{})
exportTokenExpiration = make(map[string]time.Time)
tokenMutex sync.RWMutex
)
// 五分钟检测窗口过期
func cleanupExpiredTokens() {
for {
time.Sleep(5 * time.Minute)
tokenMutex.Lock()
now := time.Now()
for token, expiry := range exportTokenExpiration {
if now.After(expiry) {
delete(exportTokenCache, token)
delete(exportTokenExpiration, token)
}
}
tokenMutex.Unlock()
}
}
func init() {
go cleanupExpiredTokens()
}
type SysExportTemplateApi struct {
}
@@ -183,7 +213,7 @@ func (sysExportTemplateApi *SysExportTemplateApi) GetSysExportTemplateList(c *gi
}
}
// ExportExcel 导出表格
// ExportExcel 导出表格token
// @Tags SysExportTemplate
// @Summary 导出表格
// @Security ApiKeyAuth
@@ -192,16 +222,83 @@ func (sysExportTemplateApi *SysExportTemplateApi) GetSysExportTemplateList(c *gi
// @Router /sysExportTemplate/exportExcel [get]
func (sysExportTemplateApi *SysExportTemplateApi) ExportExcel(c *gin.Context) {
templateID := c.Query("templateID")
queryParams := c.Request.URL.Query()
if templateID == "" {
response.FailWithMessage("模板ID不能为空", c)
return
}
queryParams := c.Request.URL.Query()
//创造一次性token
token := utils.RandomString(32) // 随机32位
// 记录本次请求参数
exportParams := map[string]interface{}{
"templateID": templateID,
"queryParams": queryParams,
}
// 参数保留记录完成鉴权
tokenMutex.Lock()
exportTokenCache[token] = exportParams
exportTokenExpiration[token] = time.Now().Add(30 * time.Minute)
tokenMutex.Unlock()
// 生成一次性链接
exportUrl := fmt.Sprintf("/sysExportTemplate/exportExcelByToken?token=%s", token)
response.OkWithData(exportUrl, c)
}
// ExportExcelByToken 导出表格
// @Tags ExportExcelByToken
// @Summary 导出表格
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/exportExcelByToken [get]
func (sysExportTemplateApi *SysExportTemplateApi) ExportExcelByToken(c *gin.Context) {
token := c.Query("token")
if token == "" {
response.FailWithMessage("导出token不能为空", c)
return
}
// 获取token并且从缓存中剔除
tokenMutex.RLock()
exportParamsRaw, exists := exportTokenCache[token]
expiry, _ := exportTokenExpiration[token]
tokenMutex.RUnlock()
if !exists || time.Now().After(expiry) {
global.GVA_LOG.Error("导出token无效或已过期!")
response.FailWithMessage("导出token无效或已过期", c)
return
}
// 从token获取参数
exportParams, ok := exportParamsRaw.(map[string]interface{})
if !ok {
global.GVA_LOG.Error("解析导出参数失败!")
response.FailWithMessage("解析导出参数失败", c)
return
}
// 获取导出参数
templateID := exportParams["templateID"].(string)
queryParams := exportParams["queryParams"].(url.Values)
// 清理一次性token
tokenMutex.Lock()
delete(exportTokenCache, token)
delete(exportTokenExpiration, token)
tokenMutex.Unlock()
// 导出
if file, name, err := sysExportTemplateService.ExportExcel(templateID, queryParams); err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name+utils.RandomString(6)+".xlsx")) // 对下载的文件重命名
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name+utils.RandomString(6)+".xlsx"))
c.Header("success", "true")
c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", file.Bytes())
}
@@ -213,18 +310,91 @@ func (sysExportTemplateApi *SysExportTemplateApi) ExportExcel(c *gin.Context) {
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/ExportTemplate [get]
// @Router /sysExportTemplate/exportTemplate [get]
func (sysExportTemplateApi *SysExportTemplateApi) ExportTemplate(c *gin.Context) {
templateID := c.Query("templateID")
if templateID == "" {
response.FailWithMessage("模板ID不能为空", c)
return
}
// 创造一次性token
token := utils.RandomString(32) // 随机32位
// 记录本次请求参数
exportParams := map[string]interface{}{
"templateID": templateID,
"isTemplate": true,
}
// 参数保留记录完成鉴权
tokenMutex.Lock()
exportTokenCache[token] = exportParams
exportTokenExpiration[token] = time.Now().Add(30 * time.Minute)
tokenMutex.Unlock()
// 生成一次性链接
exportUrl := fmt.Sprintf("/sysExportTemplate/exportTemplateByToken?token=%s", token)
response.OkWithData(exportUrl, c)
}
// ExportTemplateByToken 通过token导出表格模板
// @Tags ExportTemplateByToken
// @Summary 通过token导出表格模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/exportTemplateByToken [get]
func (sysExportTemplateApi *SysExportTemplateApi) ExportTemplateByToken(c *gin.Context) {
token := c.Query("token")
if token == "" {
response.FailWithMessage("导出token不能为空", c)
return
}
// 获取token并且从缓存中剔除
tokenMutex.RLock()
exportParamsRaw, exists := exportTokenCache[token]
expiry, _ := exportTokenExpiration[token]
tokenMutex.RUnlock()
if !exists || time.Now().After(expiry) {
global.GVA_LOG.Error("导出token无效或已过期!")
response.FailWithMessage("导出token无效或已过期", c)
return
}
// 从token获取参数
exportParams, ok := exportParamsRaw.(map[string]interface{})
if !ok {
global.GVA_LOG.Error("解析导出参数失败!")
response.FailWithMessage("解析导出参数失败", c)
return
}
// 检查是否为模板导出
isTemplate, _ := exportParams["isTemplate"].(bool)
if !isTemplate {
global.GVA_LOG.Error("token类型错误!")
response.FailWithMessage("token类型错误", c)
return
}
// 获取导出参数
templateID := exportParams["templateID"].(string)
// 清理一次性token
tokenMutex.Lock()
delete(exportTokenCache, token)
delete(exportTokenExpiration, token)
tokenMutex.Unlock()
// 导出模板
if file, name, err := sysExportTemplateService.ExportTemplate(templateID); err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name+"模板.xlsx")) // 对下载的文件重命名
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name+"模板.xlsx"))
c.Header("success", "true")
c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", file.Bytes())
}

View File

@@ -39,7 +39,7 @@ func RunWindowsServer() {
fmt.Printf(`
欢迎使用 gin-vue-admin
当前版本:v2.7.9
当前版本:v2.8.0
加群方式:微信号shouzi_1994 QQ群470239250
项目地址https://github.com/flipped-aurora/gin-vue-admin
插件市场:https://plugin.gin-vue-admin.com

View File

@@ -9296,7 +9296,7 @@ const docTemplate = `{
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
Version: "v2.7.9",
Version: "v2.8.0",
Host: "",
BasePath: "",
Schemes: []string{},

View File

@@ -77,24 +77,24 @@ func Routers() *gin.Engine {
}
{
systemRouter.InitApiRouter(PrivateGroup, PublicGroup) // 注册功能api路由
systemRouter.InitJwtRouter(PrivateGroup) // jwt相关路由
systemRouter.InitUserRouter(PrivateGroup) // 注册用户路由
systemRouter.InitMenuRouter(PrivateGroup) // 注册menu路由
systemRouter.InitSystemRouter(PrivateGroup) // system相关路由
systemRouter.InitCasbinRouter(PrivateGroup) // 权限相关路由
systemRouter.InitAutoCodeRouter(PrivateGroup, PublicGroup) // 创建自动化代码
systemRouter.InitAuthorityRouter(PrivateGroup) // 注册角色路由
systemRouter.InitSysDictionaryRouter(PrivateGroup) // 字典管理
systemRouter.InitAutoCodeHistoryRouter(PrivateGroup) // 自动化代码历史
systemRouter.InitSysOperationRecordRouter(PrivateGroup) // 操作记录
systemRouter.InitSysDictionaryDetailRouter(PrivateGroup) // 字典详情管理
systemRouter.InitAuthorityBtnRouterRouter(PrivateGroup) // 按钮权限管理
systemRouter.InitSysExportTemplateRouter(PrivateGroup) // 导出模板
systemRouter.InitSysParamsRouter(PrivateGroup, PublicGroup) // 参数管理
exampleRouter.InitCustomerRouter(PrivateGroup) // 客户路由
exampleRouter.InitFileUploadAndDownloadRouter(PrivateGroup) // 文件上传下载功能路由
exampleRouter.InitAttachmentCategoryRouterRouter(PrivateGroup) // 文件上传下载分类
systemRouter.InitApiRouter(PrivateGroup, PublicGroup) // 注册功能api路由
systemRouter.InitJwtRouter(PrivateGroup) // jwt相关路由
systemRouter.InitUserRouter(PrivateGroup) // 注册用户路由
systemRouter.InitMenuRouter(PrivateGroup) // 注册menu路由
systemRouter.InitSystemRouter(PrivateGroup) // system相关路由
systemRouter.InitCasbinRouter(PrivateGroup) // 权限相关路由
systemRouter.InitAutoCodeRouter(PrivateGroup, PublicGroup) // 创建自动化代码
systemRouter.InitAuthorityRouter(PrivateGroup) // 注册角色路由
systemRouter.InitSysDictionaryRouter(PrivateGroup) // 字典管理
systemRouter.InitAutoCodeHistoryRouter(PrivateGroup) // 自动化代码历史
systemRouter.InitSysOperationRecordRouter(PrivateGroup) // 操作记录
systemRouter.InitSysDictionaryDetailRouter(PrivateGroup) // 字典详情管理
systemRouter.InitAuthorityBtnRouterRouter(PrivateGroup) // 按钮权限管理
systemRouter.InitSysExportTemplateRouter(PrivateGroup, PublicGroup) // 导出模板
systemRouter.InitSysParamsRouter(PrivateGroup, PublicGroup) // 参数管理
exampleRouter.InitCustomerRouter(PrivateGroup) // 客户路由
exampleRouter.InitFileUploadAndDownloadRouter(PrivateGroup) // 文件上传下载功能路由
exampleRouter.InitAttachmentCategoryRouterRouter(PrivateGroup) // 文件上传下载分类
}

View File

@@ -21,7 +21,7 @@ import (
// @Tag.Description 用户
// @title Gin-Vue-Admin Swagger API接口文档
// @version v2.7.9
// @version v2.8.0
// @description 使用gin+vue进行极速开发的全栈开发基础平台
// @securityDefinitions.apikey ApiKeyAuth
// @in header

View File

@@ -7,8 +7,10 @@
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/{{.Router}} [{{.Method}}]
func (a *{{.Abbreviation}}) {{.FuncName}}(c *gin.Context) {
// Context
ctx := c.Request.Context()
//
err := service{{ .StructName }}.{{.FuncName}}()
err := service{{ .StructName }}.{{.FuncName}}(ctx)
if err != nil {
global.GVA_LOG.Error("失败!", zap.Error(err))
response.FailWithMessage("失败", c)
@@ -28,8 +30,10 @@ func (a *{{.Abbreviation}}) {{.FuncName}}(c *gin.Context) {
// @Success 200 {object} response.Response{data=object,msg=string} "成功"
// @Router /{{.Abbreviation}}/{{.Router}} [{{.Method}}]
func ({{.Abbreviation}}Api *{{.StructName}}Api){{.FuncName}}(c *gin.Context) {
// Context
ctx := c.Request.Context()
//
err := {{.Abbreviation}}Service.{{.FuncName}}()
err := {{.Abbreviation}}Service.{{.FuncName}}(ctx)
if err != nil {
global.GVA_LOG.Error("失败!", zap.Error(err))
response.FailWithMessage("失败", c)

View File

@@ -8,7 +8,7 @@
// {{.FuncName}} {{.FuncDesc}}
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) {{.FuncName}}() (err error) {
func (s *{{.Abbreviation}}) {{.FuncName}}(ctx context.Context) (err error) {
db := {{$db}}.Model(&model.{{.StructName}}{})
return db.Error
}
@@ -17,9 +17,9 @@ func (s *{{.Abbreviation}}) {{.FuncName}}() (err error) {
// {{.FuncName}} {{.FuncDesc}}
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service){{.FuncName}}() (err error) {
func ({{.Abbreviation}}Service *{{.StructName}}Service){{.FuncName}}(ctx context.Context) (err error) {
//
db := {{$db}}.Model(&{{.Package}}.{{.StructName}}{})
return db.Error
}
{{end}}
{{end}}

View File

@@ -33,6 +33,9 @@ type {{.StructName}}Api struct {}
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /{{.Abbreviation}}/create{{.StructName}} [post]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Create{{.StructName}}(c *gin.Context) {
// Context
ctx := c.Request.Context()
var {{.Abbreviation}} {{.Package}}.{{.StructName}}
err := c.ShouldBindJSON(&{{.Abbreviation}})
if err != nil {
@@ -42,7 +45,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Create{{.StructName}}(c *gin.Con
{{- if .AutoCreateResource }}
{{.Abbreviation}}.CreatedBy = utils.GetUserID(c)
{{- end }}
err = {{.Abbreviation}}Service.Create{{.StructName}}(&{{.Abbreviation}})
err = {{.Abbreviation}}Service.Create{{.StructName}}(ctx,&{{.Abbreviation}})
if err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败:" + err.Error(), c)
@@ -61,11 +64,14 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Create{{.StructName}}(c *gin.Con
// @Success 200 {object} response.Response{msg=string} "删除成功"
// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}(c *gin.Context) {
// Context
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}} := c.Query("{{.PrimaryField.FieldJson}}")
{{- if .AutoCreateResource }}
userID := utils.GetUserID(c)
{{- end }}
err := {{.Abbreviation}}Service.Delete{{.StructName}}({{.PrimaryField.FieldJson}} {{- if .AutoCreateResource -}},userID{{- end -}})
err := {{.Abbreviation}}Service.Delete{{.StructName}}(ctx,{{.PrimaryField.FieldJson}} {{- if .AutoCreateResource -}},userID{{- end -}})
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败:" + err.Error(), c)
@@ -83,11 +89,14 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}(c *gin.Con
// @Success 200 {object} response.Response{msg=string} "批量删除成功"
// @Router /{{.Abbreviation}}/delete{{.StructName}}ByIds [delete]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}ByIds(c *gin.Context) {
// Context
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}}s := c.QueryArray("{{.PrimaryField.FieldJson}}s[]")
{{- if .AutoCreateResource }}
userID := utils.GetUserID(c)
{{- end }}
err := {{.Abbreviation}}Service.Delete{{.StructName}}ByIds({{.PrimaryField.FieldJson}}s{{- if .AutoCreateResource }},userID{{- end }})
err := {{.Abbreviation}}Service.Delete{{.StructName}}ByIds(ctx,{{.PrimaryField.FieldJson}}s{{- if .AutoCreateResource }},userID{{- end }})
if err != nil {
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
response.FailWithMessage("批量删除失败:" + err.Error(), c)
@@ -106,6 +115,9 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}ByIds(c *gi
// @Success 200 {object} response.Response{msg=string} "更新成功"
// @Router /{{.Abbreviation}}/update{{.StructName}} [put]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Update{{.StructName}}(c *gin.Context) {
// ctx获取标准context进行业务行为
ctx := c.Request.Context()
var {{.Abbreviation}} {{.Package}}.{{.StructName}}
err := c.ShouldBindJSON(&{{.Abbreviation}})
if err != nil {
@@ -115,7 +127,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Update{{.StructName}}(c *gin.Con
{{- if .AutoCreateResource }}
{{.Abbreviation}}.UpdatedBy = utils.GetUserID(c)
{{- end }}
err = {{.Abbreviation}}Service.Update{{.StructName}}({{.Abbreviation}})
err = {{.Abbreviation}}Service.Update{{.StructName}}(ctx,{{.Abbreviation}})
if err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败:" + err.Error(), c)
@@ -134,8 +146,11 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Update{{.StructName}}(c *gin.Con
// @Success 200 {object} response.Response{data={{.Package}}.{{.StructName}},msg=string} "查询成功"
// @Router /{{.Abbreviation}}/find{{.StructName}} [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Find{{.StructName}}(c *gin.Context) {
// Context
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}} := c.Query("{{.PrimaryField.FieldJson}}")
re{{.Abbreviation}}, err := {{.Abbreviation}}Service.Get{{.StructName}}({{.PrimaryField.FieldJson}})
re{{.Abbreviation}}, err := {{.Abbreviation}}Service.Get{{.StructName}}(ctx,{{.PrimaryField.FieldJson}})
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败:" + err.Error(), c)
@@ -154,7 +169,10 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Find{{.StructName}}(c *gin.Conte
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}List(c *gin.Context) {
list, err := {{.Abbreviation}}Service.Get{{.StructName}}InfoList()
// Context
ctx := c.Request.Context()
list, err := {{.Abbreviation}}Service.Get{{.StructName}}InfoList(ctx)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败:" + err.Error(), c)
@@ -173,13 +191,16 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}List(c *gin.Co
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}List(c *gin.Context) {
// Context
ctx := c.Request.Context()
var pageInfo {{.Package}}Req.{{.StructName}}Search
err := c.ShouldBindQuery(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := {{.Abbreviation}}Service.Get{{.StructName}}InfoList(pageInfo)
list, total, err := {{.Abbreviation}}Service.Get{{.StructName}}InfoList(ctx,pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败:" + err.Error(), c)
@@ -203,8 +224,11 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}List(c *gin.Co
// @Success 200 {object} response.Response{data=object,msg=string} "查询成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}DataSource [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}DataSource(c *gin.Context) {
// Context
ctx := c.Request.Context()
//
dataSource, err := {{.Abbreviation}}Service.Get{{.StructName}}DataSource()
dataSource, err := {{.Abbreviation}}Service.Get{{.StructName}}DataSource(ctx)
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败:" + err.Error(), c)
@@ -224,9 +248,12 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}DataSource(c *
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}Public(c *gin.Context) {
// Context
ctx := c.Request.Context()
//
// C端服务
{{.Abbreviation}}Service.Get{{.StructName}}Public()
{{.Abbreviation}}Service.Get{{.StructName}}Public(ctx)
response.OkWithDetailed(gin.H{
"info": "不需要鉴权的{{.Description}}接口信息",
}, "获取成功", c)

View File

@@ -58,6 +58,7 @@ package {{.Package}}
import (
{{- if not .OnlyTemplate }}
"context"
"{{.Module}}/global"
"{{.Module}}/model/{{.Package}}"
{{- if not .IsTree}}
@@ -77,14 +78,14 @@ type {{.StructName}}Service struct {}
{{- if not .OnlyTemplate }}
// Create{{.StructName}} 创建{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service) Create{{.StructName}}({{.Abbreviation}} *{{.Package}}.{{.StructName}}) (err error) {
func ({{.Abbreviation}}Service *{{.StructName}}Service) Create{{.StructName}}(ctx context.Context, {{.Abbreviation}} *{{.Package}}.{{.StructName}}) (err error) {
err = {{$db}}.Create({{.Abbreviation}}).Error
return err
}
// Delete{{.StructName}} 删除{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}({{.PrimaryField.FieldJson}} string{{- if .AutoCreateResource -}},userID uint{{- end -}}) (err error) {
func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}(ctx context.Context, {{.PrimaryField.FieldJson}} string{{- if .AutoCreateResource -}},userID uint{{- end -}}) (err error) {
{{- if .IsTree }}
var count int64
err = {{$db}}.Find(&{{.Package}}.{{.StructName}}{},"parent_id = ?",{{.PrimaryField.FieldJson}}).Count(&count).Error
@@ -114,7 +115,7 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}({{.
// Delete{{.StructName}}ByIds 批量删除{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}ByIds({{.PrimaryField.FieldJson}}s []string {{- if .AutoCreateResource }},deleted_by uint{{- end}}) (err error) {
func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}ByIds(ctx context.Context, {{.PrimaryField.FieldJson}}s []string {{- if .AutoCreateResource }},deleted_by uint{{- end}}) (err error) {
{{- if .AutoCreateResource }}
err = {{$db}}.Transaction(func(tx *gorm.DB) error {
if err := tx.Model(&{{.Package}}.{{.StructName}}{}).Where("{{.PrimaryField.ColumnName}} in ?", {{.PrimaryField.FieldJson}}s).Update("deleted_by", deleted_by).Error; err != nil {
@@ -133,14 +134,14 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}ById
// Update{{.StructName}} 更新{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service)Update{{.StructName}}({{.Abbreviation}} {{.Package}}.{{.StructName}}) (err error) {
func ({{.Abbreviation}}Service *{{.StructName}}Service)Update{{.StructName}}(ctx context.Context, {{.Abbreviation}} {{.Package}}.{{.StructName}}) (err error) {
err = {{$db}}.Model(&{{.Package}}.{{.StructName}}{}).Where("{{.PrimaryField.ColumnName}} = ?",{{.Abbreviation}}.{{.PrimaryField.FieldName}}).Updates(&{{.Abbreviation}}).Error
return err
}
// Get{{.StructName}} 根据{{.PrimaryField.FieldJson}}获取{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}({{.PrimaryField.FieldJson}} string) ({{.Abbreviation}} {{.Package}}.{{.StructName}}, err error) {
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}(ctx context.Context, {{.PrimaryField.FieldJson}} string) ({{.Abbreviation}} {{.Package}}.{{.StructName}}, err error) {
err = {{$db}}.Where("{{.PrimaryField.ColumnName}} = ?", {{.PrimaryField.FieldJson}}).First(&{{.Abbreviation}}).Error
return
}
@@ -149,7 +150,7 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}({{.Pri
{{- if .IsTree }}
// Get{{.StructName}}InfoList 分页获取{{.Description}}记录,Tree模式下不添加分页和搜索
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoList() (list []*{{.Package}}.{{.StructName}},err error) {
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoList(ctx context.Context) (list []*{{.Package}}.{{.StructName}},err error) {
// db
db := {{$db}}.Model(&{{.Package}}.{{.StructName}}{})
var {{.Abbreviation}}s []*{{.Package}}.{{.StructName}}
@@ -161,7 +162,7 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoLis
{{- else }}
// Get{{.StructName}}InfoList 分页获取{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoList(info {{.Package}}Req.{{.StructName}}Search) (list []{{.Package}}.{{.StructName}}, total int64, err error) {
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoList(ctx context.Context, info {{.Package}}Req.{{.StructName}}Search) (list []{{.Package}}.{{.StructName}}, total int64, err error) {
limit := info.PageSize
offset := info.PageSize * (info.Page - 1)
// db
@@ -226,7 +227,7 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoLis
{{- end }}
{{- if .HasDataSource }}
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}DataSource() (res map[string][]map[string]any, err error) {
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}DataSource(ctx context.Context) (res map[string][]map[string]any, err error) {
res = make(map[string][]map[string]any)
{{range $key, $value := .DataSourceMap}}
{{$key}} := make([]map[string]any, 0)
@@ -243,7 +244,7 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}DataSou
}
{{- end }}
{{- end }}
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}Public() {
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}Public(ctx context.Context) {
//
//
}

View File

@@ -131,7 +131,7 @@
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
<div class="file-list">
<el-tag v-for="file in scope.row.{{.FieldJson}}" :key="file.uid" @click="downloadFile(file.url)">{{"{{"}}file.name{{"}}"}}</el-tag>
<el-tag v-for="file in scope.row.{{.FieldJson}}" :key="file.uid" @click="onDownloadFile(file.url)">{{"{{"}}file.name{{"}}"}}</el-tag>
</div>
</template>
</el-table-column>
@@ -607,7 +607,7 @@ getDataSourceFunc()
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
<div class="file-list">
<el-tag v-for="file in scope.row.{{.FieldJson}}" :key="file.uid" @click="downloadFile(file.url)">{{"{{"}}file.name{{"}}"}}</el-tag>
<el-tag v-for="file in scope.row.{{.FieldJson}}" :key="file.uid" @click="onDownloadFile(file.url)">{{"{{"}}file.name{{"}}"}}</el-tag>
</div>
</template>
</el-table-column>
@@ -1297,11 +1297,6 @@ const enterDialog = async () => {
}
})
}
{{if .HasFile }}
const downloadFile = (url) => {
window.open(getUrl(url), '_blank')
}
{{end}}
const detailFrom = ref({})

View File

@@ -33,6 +33,9 @@ type {{.Abbreviation}} struct {}
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /{{.Abbreviation}}/create{{.StructName}} [post]
func (a *{{.Abbreviation}}) Create{{.StructName}}(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
var info model.{{.StructName}}
err := c.ShouldBindJSON(&info)
if err != nil {
@@ -42,7 +45,7 @@ func (a *{{.Abbreviation}}) Create{{.StructName}}(c *gin.Context) {
{{- if .AutoCreateResource }}
info.CreatedBy = utils.GetUserID(c)
{{- end }}
err = service{{ .StructName }}.Create{{.StructName}}(&info)
err = service{{ .StructName }}.Create{{.StructName}}(ctx,&info)
if err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败:" + err.Error(), c)
@@ -61,11 +64,14 @@ func (a *{{.Abbreviation}}) Create{{.StructName}}(c *gin.Context) {
// @Success 200 {object} response.Response{msg=string} "删除成功"
// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete]
func (a *{{.Abbreviation}}) Delete{{.StructName}}(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}} := c.Query("{{.PrimaryField.FieldJson}}")
{{- if .AutoCreateResource }}
userID := utils.GetUserID(c)
{{- end }}
err := service{{ .StructName }}.Delete{{.StructName}}({{.PrimaryField.FieldJson}} {{- if .AutoCreateResource -}},userID{{- end -}})
err := service{{ .StructName }}.Delete{{.StructName}}(ctx,{{.PrimaryField.FieldJson}} {{- if .AutoCreateResource -}},userID{{- end -}})
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败:" + err.Error(), c)
@@ -83,11 +89,14 @@ func (a *{{.Abbreviation}}) Delete{{.StructName}}(c *gin.Context) {
// @Success 200 {object} response.Response{msg=string} "批量删除成功"
// @Router /{{.Abbreviation}}/delete{{.StructName}}ByIds [delete]
func (a *{{.Abbreviation}}) Delete{{.StructName}}ByIds(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}}s := c.QueryArray("{{.PrimaryField.FieldJson}}s[]")
{{- if .AutoCreateResource }}
userID := utils.GetUserID(c)
{{- end }}
err := service{{ .StructName }}.Delete{{.StructName}}ByIds({{.PrimaryField.FieldJson}}s{{- if .AutoCreateResource }},userID{{- end }})
err := service{{ .StructName }}.Delete{{.StructName}}ByIds(ctx,{{.PrimaryField.FieldJson}}s{{- if .AutoCreateResource }},userID{{- end }})
if err != nil {
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
response.FailWithMessage("批量删除失败:" + err.Error(), c)
@@ -106,6 +115,9 @@ func (a *{{.Abbreviation}}) Delete{{.StructName}}ByIds(c *gin.Context) {
// @Success 200 {object} response.Response{msg=string} "更新成功"
// @Router /{{.Abbreviation}}/update{{.StructName}} [put]
func (a *{{.Abbreviation}}) Update{{.StructName}}(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
var info model.{{.StructName}}
err := c.ShouldBindJSON(&info)
if err != nil {
@@ -115,7 +127,7 @@ func (a *{{.Abbreviation}}) Update{{.StructName}}(c *gin.Context) {
{{- if .AutoCreateResource }}
info.UpdatedBy = utils.GetUserID(c)
{{- end }}
err = service{{ .StructName }}.Update{{.StructName}}(info)
err = service{{ .StructName }}.Update{{.StructName}}(ctx,info)
if err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败:" + err.Error(), c)
@@ -134,8 +146,11 @@ func (a *{{.Abbreviation}}) Update{{.StructName}}(c *gin.Context) {
// @Success 200 {object} response.Response{data=model.{{.StructName}},msg=string} "查询成功"
// @Router /{{.Abbreviation}}/find{{.StructName}} [get]
func (a *{{.Abbreviation}}) Find{{.StructName}}(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
{{.PrimaryField.FieldJson}} := c.Query("{{.PrimaryField.FieldJson}}")
re{{.Abbreviation}}, err := service{{ .StructName }}.Get{{.StructName}}({{.PrimaryField.FieldJson}})
re{{.Abbreviation}}, err := service{{ .StructName }}.Get{{.StructName}}(ctx,{{.PrimaryField.FieldJson}})
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败:" + err.Error(), c)
@@ -154,7 +169,10 @@ func (a *{{.Abbreviation}}) Find{{.StructName}}(c *gin.Context) {
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func (a *{{.Abbreviation}}) Get{{.StructName}}List(c *gin.Context) {
list, err := service{{ .StructName }}.Get{{.StructName}}InfoList()
// 创建业务用Context
ctx := c.Request.Context()
list, err := service{{ .StructName }}.Get{{.StructName}}InfoList(ctx)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败:" + err.Error(), c)
@@ -173,13 +191,16 @@ func (a *{{.Abbreviation}}) Get{{.StructName}}List(c *gin.Context) {
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func (a *{{.Abbreviation}}) Get{{.StructName}}List(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
var pageInfo request.{{.StructName}}Search
err := c.ShouldBindQuery(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := service{{ .StructName }}.Get{{.StructName}}InfoList(pageInfo)
list, total, err := service{{ .StructName }}.Get{{.StructName}}InfoList(ctx,pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败:" + err.Error(), c)
@@ -203,8 +224,11 @@ func (a *{{.Abbreviation}}) Get{{.StructName}}List(c *gin.Context) {
// @Success 200 {object} response.Response{data=object,msg=string} "查询成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}DataSource [get]
func (a *{{.Abbreviation}}) Get{{.StructName}}DataSource(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
// 此接口为获取数据源定义的数据
dataSource, err := service{{ .StructName }}.Get{{.StructName}}DataSource()
dataSource, err := service{{ .StructName }}.Get{{.StructName}}DataSource(ctx)
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败:" + err.Error(), c)
@@ -222,7 +246,10 @@ func (a *{{.Abbreviation}}) Get{{.StructName}}DataSource(c *gin.Context) {
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
func (a *{{.Abbreviation}}) Get{{.StructName}}Public(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
// 此接口不需要鉴权 示例为返回了一个固定的消息接口一般本接口用于C端服务需要自己实现业务逻辑
service{{ .StructName }}.Get{{.StructName}}Public()
service{{ .StructName }}.Get{{.StructName}}Public(ctx)
response.OkWithDetailed(gin.H{"info": "不需要鉴权的{{.Description}}接口信息"}, "获取成功", c)
}

View File

@@ -58,6 +58,7 @@ package service
import (
{{- if not .OnlyTemplate }}
"context"
"{{.Module}}/global"
"{{.Module}}/plugin/{{.Package}}/model"
{{- if not .IsTree }}
@@ -87,14 +88,14 @@ type {{.Abbreviation}} struct {}
{{- if not .OnlyTemplate }}
// Create{{.StructName}} 创建{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) Create{{.StructName}}({{.Abbreviation}} *model.{{.StructName}}) (err error) {
func (s *{{.Abbreviation}}) Create{{.StructName}}(ctx context.Context, {{.Abbreviation}} *model.{{.StructName}}) (err error) {
err = {{$db}}.Create({{.Abbreviation}}).Error
return err
}
// Delete{{.StructName}} 删除{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) Delete{{.StructName}}({{.PrimaryField.FieldJson}} string{{- if .AutoCreateResource -}},userID uint{{- end -}}) (err error) {
func (s *{{.Abbreviation}}) Delete{{.StructName}}(ctx context.Context, {{.PrimaryField.FieldJson}} string{{- if .AutoCreateResource -}},userID uint{{- end -}}) (err error) {
{{- if .IsTree }}
var count int64
@@ -125,7 +126,7 @@ func (s *{{.Abbreviation}}) Delete{{.StructName}}({{.PrimaryField.FieldJson}} st
// Delete{{.StructName}}ByIds 批量删除{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) Delete{{.StructName}}ByIds({{.PrimaryField.FieldJson}}s []string {{- if .AutoCreateResource }},deleted_by uint{{- end}}) (err error) {
func (s *{{.Abbreviation}}) Delete{{.StructName}}ByIds(ctx context.Context, {{.PrimaryField.FieldJson}}s []string {{- if .AutoCreateResource }},deleted_by uint{{- end}}) (err error) {
{{- if .AutoCreateResource }}
err = {{$db}}.Transaction(func(tx *gorm.DB) error {
if err := tx.Model(&model.{{.StructName}}{}).Where("{{.PrimaryField.ColumnName}} in ?", {{.PrimaryField.FieldJson}}s).Update("deleted_by", deleted_by).Error; err != nil {
@@ -144,14 +145,14 @@ func (s *{{.Abbreviation}}) Delete{{.StructName}}ByIds({{.PrimaryField.FieldJson
// Update{{.StructName}} 更新{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) Update{{.StructName}}({{.Abbreviation}} model.{{.StructName}}) (err error) {
func (s *{{.Abbreviation}}) Update{{.StructName}}(ctx context.Context, {{.Abbreviation}} model.{{.StructName}}) (err error) {
err = {{$db}}.Model(&model.{{.StructName}}{}).Where("{{.PrimaryField.ColumnName}} = ?",{{.Abbreviation}}.{{.PrimaryField.FieldName}}).Updates(&{{.Abbreviation}}).Error
return err
}
// Get{{.StructName}} 根据{{.PrimaryField.FieldJson}}获取{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) Get{{.StructName}}({{.PrimaryField.FieldJson}} string) ({{.Abbreviation}} model.{{.StructName}}, err error) {
func (s *{{.Abbreviation}}) Get{{.StructName}}(ctx context.Context, {{.PrimaryField.FieldJson}} string) ({{.Abbreviation}} model.{{.StructName}}, err error) {
err = {{$db}}.Where("{{.PrimaryField.ColumnName}} = ?", {{.PrimaryField.FieldJson}}).First(&{{.Abbreviation}}).Error
return
}
@@ -160,7 +161,7 @@ func (s *{{.Abbreviation}}) Get{{.StructName}}({{.PrimaryField.FieldJson}} strin
{{- if .IsTree }}
// Get{{.StructName}}InfoList 分页获取{{.Description}}记录,Tree模式下不添加分页和搜索
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList() (list []*model.{{.StructName}},err error) {
func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList(ctx context.Context) (list []*model.{{.StructName}},err error) {
// 创建db
db := {{$db}}.Model(&model.{{.StructName}}{})
var {{.Abbreviation}}s []*model.{{.StructName}}
@@ -172,7 +173,7 @@ func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList() (list []*model.{{.Struc
{{- else }}
// Get{{.StructName}}InfoList 分页获取{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList(info request.{{.StructName}}Search) (list []model.{{.StructName}}, total int64, err error) {
func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList(ctx context.Context, info request.{{.StructName}}Search) (list []model.{{.StructName}}, total int64, err error) {
limit := info.PageSize
offset := info.PageSize * (info.Page - 1)
// 创建db
@@ -234,7 +235,7 @@ func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList(info request.{{.StructNam
}
{{- end }}
{{- if .HasDataSource }}
func (s *{{.Abbreviation}})Get{{.StructName}}DataSource() (res map[string][]map[string]any, err error) {
func (s *{{.Abbreviation}})Get{{.StructName}}DataSource(ctx context.Context) (res map[string][]map[string]any, err error) {
res = make(map[string][]map[string]any)
{{range $key, $value := .DataSourceMap}}
{{$key}} := make([]map[string]any, 0)
@@ -252,7 +253,7 @@ func (s *{{.Abbreviation}})Get{{.StructName}}DataSource() (res map[string][]map[
{{- end }}
{{- end }}
func (s *{{.Abbreviation}})Get{{.StructName}}Public() {
func (s *{{.Abbreviation}})Get{{.StructName}}Public(ctx context.Context) {
}
{{- end }}

View File

@@ -131,7 +131,7 @@
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
<div class="file-list">
<el-tag v-for="file in scope.row.{{.FieldJson}}" :key="file.uid" @click="downloadFile(file.url)">{{"{{"}}file.name{{"}}"}}</el-tag>
<el-tag v-for="file in scope.row.{{.FieldJson}}" :key="file.uid" @click="onDownloadFile(file.url)">{{"{{"}}file.name{{"}}"}}</el-tag>
</div>
</template>
</el-table-column>
@@ -607,7 +607,7 @@ getDataSourceFunc()
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
<div class="file-list">
<el-tag v-for="file in scope.row.{{.FieldJson}}" :key="file.uid" @click="downloadFile(file.url)">{{"{{"}}file.name{{"}}"}}</el-tag>
<el-tag v-for="file in scope.row.{{.FieldJson}}" :key="file.uid" @click="onDownloadFile(file.url)">{{"{{"}}file.name{{"}}"}}</el-tag>
</div>
</template>
</el-table-column>
@@ -1295,11 +1295,6 @@ const enterDialog = async () => {
}
})
}
{{if .HasFile }}
const downloadFile = (url) => {
window.open(getUrl(url), '_blank')
}
{{end}}
const detailFrom = ref({})

View File

@@ -9,9 +9,11 @@ type SysExportTemplateRouter struct {
}
// InitSysExportTemplateRouter 初始化 导出模板 路由信息
func (s *SysExportTemplateRouter) InitSysExportTemplateRouter(Router *gin.RouterGroup) {
func (s *SysExportTemplateRouter) InitSysExportTemplateRouter(Router *gin.RouterGroup, pubRouter *gin.RouterGroup) {
sysExportTemplateRouter := Router.Group("sysExportTemplate").Use(middleware.OperationRecord())
sysExportTemplateRouterWithoutRecord := Router.Group("sysExportTemplate")
sysExportTemplateRouterWithoutAuth := pubRouter.Group("sysExportTemplate")
{
sysExportTemplateRouter.POST("createSysExportTemplate", exportTemplateApi.CreateSysExportTemplate) // 新建导出模板
sysExportTemplateRouter.DELETE("deleteSysExportTemplate", exportTemplateApi.DeleteSysExportTemplate) // 删除导出模板
@@ -22,7 +24,11 @@ func (s *SysExportTemplateRouter) InitSysExportTemplateRouter(Router *gin.Router
{
sysExportTemplateRouterWithoutRecord.GET("findSysExportTemplate", exportTemplateApi.FindSysExportTemplate) // 根据ID获取导出模板
sysExportTemplateRouterWithoutRecord.GET("getSysExportTemplateList", exportTemplateApi.GetSysExportTemplateList) // 获取导出模板列表
sysExportTemplateRouterWithoutRecord.GET("exportExcel", exportTemplateApi.ExportExcel) // 导出表格
sysExportTemplateRouterWithoutRecord.GET("exportExcel", exportTemplateApi.ExportExcel) // 获取导出token
sysExportTemplateRouterWithoutRecord.GET("exportTemplate", exportTemplateApi.ExportTemplate) // 导出表格模板
}
{
sysExportTemplateRouterWithoutAuth.GET("exportExcelByToken", exportTemplateApi.ExportExcelByToken) // 通过token导出表格
sysExportTemplateRouterWithoutAuth.GET("exportTemplateByToken", exportTemplateApi.ExportTemplateByToken) // 通过token导出模板
}
}

View File

@@ -40,10 +40,10 @@ func SetToken(c *gin.Context, token string, maxAge int) {
}
func GetToken(c *gin.Context) string {
token, _ := c.Cookie("x-token")
token := c.Request.Header.Get("x-token")
if token == "" {
j := NewJWT()
token = c.Request.Header.Get("x-token")
token, _ = c.Cookie("x-token")
claims, err := j.ParseToken(token)
if err != nil {
global.GVA_LOG.Error("重新写入cookie token失败,未能成功解析token,请检查请求头是否存在x-token且claims是否为规定结构")

View File

@@ -1,6 +1,6 @@
{
"name": "gin-vue-admin",
"version": "2.7.9",
"version": "2.8.0",
"private": true,
"scripts": {
"serve": "node openDocument.js && vite --host --mode development",

View File

@@ -95,3 +95,34 @@ export const getSysExportTemplateList = (params) => {
params
})
}
// ExportExcel 导出表格token
// @Tags SysExportTemplate
// @Summary 导出表格
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/exportExcel [get]
export const exportExcel = (params) => {
return service({
url: '/sysExportTemplate/exportExcel',
method: 'get',
params
})
}
// ExportTemplate 导出表格模板
// @Tags SysExportTemplate
// @Summary 导出表格模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/exportTemplate [get]
export const exportTemplate = (params) => {
return service({
url: '/sysExportTemplate/exportTemplate',
method: 'get',
params
})
}

View File

@@ -5,7 +5,8 @@
</template>
<script setup>
import {getUrl} from "@/utils/image";
import { exportExcel } from '@/api/exportTemplate'
const props = defineProps({
templateId: {
@@ -58,8 +59,17 @@
)
.join('&')
const url = `${baseUrl}/sysExportTemplate/exportExcel?templateID=${props.templateId}${params ? '&' + params : ''}`
const res = await exportExcel({
templateID: props.templateId,
params
})
if(res.code === 0){
ElMessage.success('创建导出任务成功,开始下载')
const url = `${baseUrl}${res.data}`
window.open(url, '_blank')
}
window.open(url, '_blank')
}
</script>

View File

@@ -1,10 +1,13 @@
<template>
<el-button type="primary" icon="download" @click="exportTemplate"
<el-button type="primary" icon="download" @click="exportTemplateFunc"
>下载模板</el-button
>
</template>
<script setup>
import { ElMessage } from 'element-plus'
import {exportTemplate} from "@/api/exportTemplate";
const props = defineProps({
templateId: {
type: String,
@@ -12,9 +15,8 @@
}
})
import { ElMessage } from 'element-plus'
const exportTemplate = async () => {
const exportTemplateFunc = async () => {
if (props.templateId === '') {
ElMessage.error('组件未设置模板ID')
return
@@ -23,7 +25,16 @@
if (baseUrl === "/"){
baseUrl = ""
}
const url = `${baseUrl}/sysExportTemplate/exportTemplate?templateID=${props.templateId}`
window.open(url, '_blank')
const res = await exportTemplate({
templateID: props.templateId
})
if(res.code === 0){
ElMessage.success('创建导出任务成功,开始下载')
const url = `${baseUrl}${res.data}`
window.open(url, '_blank')
}
}
</script>

View File

@@ -4,6 +4,7 @@
:show-file-list="false"
:on-success="handleSuccess"
:multiple="false"
:headers="{'x-token': token}"
>
<el-button type="primary" icon="upload" class="ml-3"> 导入 </el-button>
</el-upload>
@@ -11,6 +12,7 @@
<script setup>
import { ElMessage } from 'element-plus'
import { useUserStore } from "@/pinia";
let baseUrl = import.meta.env.VITE_BASE_API
if (baseUrl === "/"){
@@ -24,6 +26,10 @@
}
})
const userStore = useUserStore()
const token = userStore.token
const emit = defineEmits(['on-success'])
const url = `${baseUrl}/sysExportTemplate/importExcel?templateID=${props.templateId}`

View File

@@ -11,6 +11,7 @@
:limit="limit"
:accept="accept"
class="upload-btn"
:headers="{'x-token': token}"
>
<el-button type="primary"> 上传文件 </el-button>
</el-upload>
@@ -21,6 +22,7 @@
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getBaseUrl } from '@/utils/format'
import { useUserStore } from "@/pinia";
defineOptions({
name: 'UploadCommon'
@@ -37,6 +39,10 @@
}
})
const userStore = useUserStore()
const token = userStore.token
const fullscreenLoading = ref(false)
const model = defineModel({ type: Array })

View File

@@ -7,6 +7,7 @@
:on-success="uploadSuccess"
:show-file-list="false"
:data="{'classId': props.classId}"
:headers="{'x-token': token}"
multiple
class="upload-btn"
>
@@ -20,12 +21,17 @@
import { ElMessage } from 'element-plus'
import { isVideoMime, isImageMime } from '@/utils/image'
import { getBaseUrl } from '@/utils/format'
import {Upload} from "@element-plus/icons-vue";
import { Upload } from "@element-plus/icons-vue";
import { useUserStore } from "@/pinia";
defineOptions({
name: 'UploadCommon'
})
const userStore = useUserStore()
const token = userStore.token
const props = defineProps({
classId: {
type: Number,

View File

@@ -8,6 +8,7 @@
:data="{'classId': props.classId}"
:on-success="handleImageSuccess"
:on-change="handleFileChange"
:headers="{'x-token': token}"
>
<el-button type="primary" icon="crop"> 裁剪上传</el-button>
</el-upload>
@@ -87,6 +88,7 @@ import { RefreshLeft, RefreshRight, Plus, Minus } from '@element-plus/icons-vue'
import 'vue-cropper/dist/index.css'
import { VueCropper } from 'vue-cropper'
import { getBaseUrl } from '@/utils/format'
import { useUserStore } from "@/pinia";
defineOptions({
name: 'CropperImage'

View File

@@ -7,6 +7,7 @@
:before-upload="beforeImageUpload"
:multiple="false"
:data="{'classId': props.classId}"
:headers="{'x-token': token}"
>
<el-button type="primary" :icon="Upload">压缩上传</el-button>
</el-upload>
@@ -17,7 +18,8 @@
import ImageCompress from '@/utils/image'
import { ElMessage } from 'element-plus'
import { getBaseUrl } from '@/utils/format'
import {Upload} from "@element-plus/icons-vue";
import { Upload } from "@element-plus/icons-vue";
import { useUserStore } from "@/pinia";
defineOptions({
name: 'UploadImage'
@@ -43,6 +45,10 @@
}
})
const userStore = useUserStore()
const token = userStore.token
const beforeImageUpload = (file) => {
const isJPG = file.type?.toLowerCase() === 'image/jpeg'
const isPng = file.type?.toLowerCase() === 'image/png'

View File

@@ -17,7 +17,7 @@ export const viteLogo = (env) => {
`> 欢迎使用Gin-Vue-Admin开源地址https://github.com/flipped-aurora/gin-vue-admin`
)
)
console.log(greenText(`> 当前版本:v2.7.9`))
console.log(greenText(`> 当前版本:v2.8.0`))
console.log(greenText(`> 加群方式:微信shouzi_1994 QQ群470239250`))
console.log(
greenText(`> 项目地址https://github.com/flipped-aurora/gin-vue-admin`)

View File

@@ -10,7 +10,7 @@ export default {
register(app)
console.log(`
欢迎使用 Gin-Vue-Admin
当前版本:v2.7.9
当前版本:v2.8.0
加群方式:微信shouzi_1994 QQ群622360840
项目地址https://github.com/flipped-aurora/gin-vue-admin
插件市场:https://plugin.gin-vue-admin.com

View File

@@ -84,6 +84,7 @@ import 'vue-cropper/dist/index.css'
import { VueCropper } from 'vue-cropper'
import { getBaseUrl } from '@/utils/format'
import { useRouter } from 'vue-router'
import { useUserStore } from "@/pinia";
defineOptions({
name: 'scanUpload'

View File

@@ -657,7 +657,7 @@
<el-table-column
align="left"
prop="dataTypeLong"
label="数据库字段长度"
label="字段长度/枚举值"
width="160"
>
<template #default="{ row }">
@@ -741,6 +741,7 @@
class="flex items-center"
:before-upload="importJson"
:show-file-list="false"
:headers="{'x-token': token}"
accept=".json"
>
<el-button type="primary" class="mx-2" :disabled="isAdd"
@@ -828,6 +829,11 @@
import { ElMessage, ElMessageBox } from 'element-plus'
import WarningBar from '@/components/warningBar/warningBar.vue'
import Sortable from 'sortablejs'
import { useUserStore } from "@/pinia";
const userStore = useUserStore()
const token = userStore.token
const handleFocus = () => {
document.addEventListener('keydown', handleKeydown);
@@ -931,7 +937,6 @@
if (res.code === 0) {
form.value.fields = []
const json = JSON.parse(res.data)
json.fields?.forEach((item) => {
item.fieldName = toUpperCase(item.fieldName)
})

View File

@@ -6,6 +6,7 @@
:show-file-list="false"
:on-success="handleSuccess"
:on-error="handleSuccess"
:headers="{'x-token': token}"
name="plug"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
@@ -20,6 +21,11 @@
<script setup>
import { ElMessage } from 'element-plus'
import { getBaseUrl } from '@/utils/format'
import { useUserStore } from "@/pinia";
const userStore = useUserStore()
const token = userStore.token
const handleSuccess = (res) => {
if (res.code === 0) {