Merge branch 'develop' into develop

This commit is contained in:
奇淼(piexlmax
2021-02-27 10:26:00 +08:00
committed by GitHub
39 changed files with 722 additions and 387 deletions
+99
View File
@@ -0,0 +1,99 @@
package v1
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"gin-vue-admin/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// /excel/importExcel 接口,与upload接口作用类似,只是把文件存到resource/excel目录下,用于导入Excel时存放Excel文件(ExcelImport.xlsx)
// /excel/loadExcel接口,用于读取resource/excel目录下的文件((ExcelImport.xlsx)并加载为[]model.SysBaseMenu类型的示例数据
// /excel/exportExcel 接口,用于读取前端传来的tableData,生成Excel文件并返回
// /excel/downloadTemplate 接口,用于下载resource/excel目录下的 ExcelTemplate.xlsx 文件,作为导入的模板
// @Tags excel
// @Summary 导出Excel
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/octet-stream
// @Param data body model.ExcelInfo true "导出Excel文件信息"
// @Success 200
// @Router /excel/exportExcel [post]
func ExportExcel(c *gin.Context) {
var excelInfo model.ExcelInfo
_ = c.ShouldBindJSON(&excelInfo)
filePath := global.GVA_CONFIG.Excel.Dir + excelInfo.FileName
err := service.ParseInfoList2Excel(excelInfo.InfoList, filePath)
if err != nil {
global.GVA_LOG.Error("转换Excel失败!", zap.Any("err", err))
response.FailWithMessage("转换Excel失败", c)
return
}
c.Writer.Header().Add("success", "true")
c.File(filePath)
}
// @Tags excel
// @Summary 导入Excel文件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "导入Excel文件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"导入成功"}"
// @Router /excel/importExcel [post]
func ImportExcel(c *gin.Context) {
_, header, err := c.Request.FormFile("file")
if err != nil {
global.GVA_LOG.Error("接收文件失败!", zap.Any("err", err))
response.FailWithMessage("接收文件失败", c)
return
}
_ = c.SaveUploadedFile(header, global.GVA_CONFIG.Excel.Dir+"ExcelImport.xlsx")
response.OkWithMessage("导入成功", c)
}
// @Tags excel
// @Summary 加载Excel数据
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"加载数据成功"}"
// @Router /excel/loadExcel [get]
func LoadExcel(c *gin.Context) {
menus, err := service.ParseExcel2InfoList()
if err != nil {
global.GVA_LOG.Error("加载数据失败", zap.Any("err", err))
response.FailWithMessage("加载数据失败", c)
return
}
response.OkWithDetailed(response.PageResult{
List: menus,
Total: int64(len(menus)),
Page: 1,
PageSize: 999,
}, "加载数据成功", c)
}
// @Tags excel
// @Summary 下载模板
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param fileName query fileName true "模板名称"
// @Success 200
// @Router /excel/downloadTemplate [get]
func DownloadTemplate(c *gin.Context) {
fileName := c.Query("fileName")
filePath := global.GVA_CONFIG.Excel.Dir + fileName
ok, err := utils.PathExists(filePath)
if !ok || err != nil {
global.GVA_LOG.Error("文件不存在", zap.Any("err", err))
response.FailWithMessage("文件不存在", c)
return
}
c.Writer.Header().Add("success", "true")
c.File(filePath)
}
+1 -85
View File
@@ -6,7 +6,6 @@ import (
"gin-vue-admin/model/request"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"gin-vue-admin/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
@@ -76,89 +75,6 @@ func GetFileList(c *gin.Context) {
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
},"获取成功", c)
}, "获取成功", c)
}
}
// @Tags ExaFileUploadAndDownload
// @Summary 导出Excel
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/octet-stream
// @Param data body request.ExcelInfo true "导出Excel文件信息"
// @Success 200
// @Router /fileUploadAndDownload/exportExcel [post]
func ExportExcel(c *gin.Context) {
var excelInfo request.ExcelInfo
c.ShouldBindJSON(&excelInfo)
filePath := global.GVA_CONFIG.Excel.Dir+excelInfo.FileName
err := service.ParseInfoList2Excel(excelInfo.InfoList, filePath)
if err != nil {
global.GVA_LOG.Error("转换Excel失败!", zap.Any("err", err))
response.FailWithMessage("转换Excel失败", c)
return
}
c.Writer.Header().Add("success", "true")
c.File(filePath)
}
// @Tags ExaFileUploadAndDownload
// @Summary 导入Excel文件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "导入Excel文件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"导入成功"}"
// @Router /fileUploadAndDownload/importExcel [post]
func ImportExcel(c *gin.Context) {
_, header, err := c.Request.FormFile("file")
if err != nil {
global.GVA_LOG.Error("接收文件失败!", zap.Any("err", err))
response.FailWithMessage("接收文件失败", c)
return
}
c.SaveUploadedFile(header, global.GVA_CONFIG.Excel.Dir+"ExcelImport.xlsx")
response.OkWithMessage("导入成功", c)
}
// @Tags ExaFileUploadAndDownload
// @Summary 加载Excel数据
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"加载数据成功"}"
// @Router /fileUploadAndDownload/loadExcel [get]
func LoadExcel(c *gin.Context) {
menus, err := service.ParseExcel2InfoList()
if err != nil {
global.GVA_LOG.Error("加载数据失败", zap.Any("err", err))
response.FailWithMessage("加载数据失败", c)
return
}
response.OkWithDetailed(response.PageResult{
List: menus,
Total: int64(len(menus)),
Page: 1,
PageSize: 999,
},"加载数据成功", c)
}
// @Tags ExaFileUploadAndDownload
// @Summary 下载模板
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param fileName query fileName true "模板名称"
// @Success 200
// @Router /fileUploadAndDownload/downloadTemplate [get]
func DownloadTemplate(c *gin.Context) {
fileName := c.Query("fileName")
filePath := global.GVA_CONFIG.Excel.Dir+fileName
ok, err := utils.PathExists(filePath)
if !ok || err != nil {
global.GVA_LOG.Error("文件不存在", zap.Any("err", err))
response.FailWithMessage("文件不存在", c)
return
}
c.Writer.Header().Add("success", "true")
c.File(filePath)
}
+28 -3
View File
@@ -1,19 +1,44 @@
package v1
import (
"errors"
"fmt"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"gin-vue-admin/utils"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"go.uber.org/zap"
"net/url"
"os"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// @Tags AutoCode
// @Summary 预览创建后的代码
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.AutoCodeStruct true "预览创建代码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/preview [post]
func PreviewTemp(c *gin.Context) {
var a model.AutoCodeStruct
_ = c.ShouldBindJSON(&a)
if err := utils.Verify(a, utils.AutoCodeVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
autoCode, err := service.PreviewTemp(a)
if err != nil {
global.GVA_LOG.Error("预览失败!", zap.Any("err", err))
response.FailWithMessage("预览失败", c)
} else {
response.OkWithDetailed(gin.H{"autoCode": autoCode}, "预览成功", c)
}
}
// @Tags AutoCode
// @Summary 自动代码模板
// @Security ApiKeyAuth
+1 -1
View File
@@ -44,7 +44,7 @@ func (m *_mysql) Init() {
m._config.DisableForeignKeyConstraintWhenMigrating = true
m.db, m.err = gorm.Open(mysql.New(mysql.Config{
DSN: global.GVA_CONFIG.Mysql.Dsn(), // DSN data source name
DefaultStringSize: 256, // string 类型字段的默认长度
DefaultStringSize: 191, // string 类型字段的默认长度
DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
+5
View File
@@ -92,6 +92,11 @@ var apis = []model.SysApi{
{global.GVA_MODEL{ID: 77, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/getMyNeed", "获取我的待办", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 78, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/getWorkflowMoveByID", "根据id获取当前节点详情和历史", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 79, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/completeWorkflowMove", "提交工作流", "workflowProcess", "POST"},
{global.GVA_MODEL{ID: 80, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/autoCode/preview", "预览自动化代码", "autoCode", "POST"},
{global.GVA_MODEL{ID: 81, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/excel/importExcel", "预览自动化代码", "autoCode", "POST"},
{global.GVA_MODEL{ID: 82, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/excel/loadExcel", "预览自动化代码", "autoCode", "POST"},
{global.GVA_MODEL{ID: 83, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/excel/exportExcel", "预览自动化代码", "autoCode", "POST"},
{global.GVA_MODEL{ID: 84, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/excel/downloadTemplate", "预览自动化代码", "autoCode", "POST"},
}
//@author: [SliverHorn](https://github.com/SliverHorn)
+5
View File
@@ -55,6 +55,7 @@ var carbines = []gormadapter.CasbinRule{
{PType: "p", V0: "888", V1: "/customer/customer", V2: "GET"},
{PType: "p", V0: "888", V1: "/customer/customerList", V2: "GET"},
{PType: "p", V0: "888", V1: "/autoCode/createTemp", V2: "POST"},
{PType: "p", V0: "888", V1: "/autoCode/preview", V2: "POST"},
{PType: "p", V0: "888", V1: "/autoCode/getTables", V2: "GET"},
{PType: "p", V0: "888", V1: "/autoCode/getDB", V2: "GET"},
{PType: "p", V0: "888", V1: "/autoCode/getColumn", V2: "GET"},
@@ -91,6 +92,10 @@ var carbines = []gormadapter.CasbinRule{
{PType: "p", V0: "888", V1: "/workflowProcess/getMyStated", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/getMyNeed", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/getWorkflowMoveByID", V2: "GET"},
{PType: "p", V0: "888", V1: "/excel/importExcel", V2: "POST"},
{PType: "p", V0: "888", V1: "/excel/loadExcel", V2: "GET"},
{PType: "p", V0: "888", V1: "/excel/exportExcel", V2: "POST"},
{PType: "p", V0: "888", V1: "/excel/downloadTemplate", V2: "GET"},
{PType: "p", V0: "8881", V1: "/base/login", V2: "POST"},
{PType: "p", V0: "8881", V1: "/user/register", V2: "POST"},
{PType: "p", V0: "8881", V1: "/api/createApi", V2: "POST"},
+10
View File
@@ -78,6 +78,7 @@ qiniu:
secret-key: 'pgdbqEsf7ooZh7W3xokP833h3dZ_VecFXPDeG5JY'
use-cdn-domains: false
# aliyun oss configuration
aliyun-oss:
endpoint: 'yourEndpoint'
@@ -86,6 +87,15 @@ aliyun-oss:
bucket-name: 'yourBucketName'
bucket-url: 'yourBucketUrl'
# tencent cos configuration
tencent-cos:
bucket: 'xxxxx-10005608'
region: 'ap-shanghai'
secret-id: 'xxxxxxxx'
secret-key: 'xxxxxxxx'
base-url: 'https://gin.vue.admin'
path-prefix: 'gin-vue-admin'
# excel configuration
excel:
dir: './resource/excel/'
+2 -1
View File
@@ -14,5 +14,6 @@ type Server struct {
Local Local `mapstructure:"local" json:"local" yaml:"local"`
Qiniu Qiniu `mapstructure:"qiniu" json:"qiniu" yaml:"qiniu"`
AliyunOSS AliyunOSS `mapstructure:"aliyun-oss" json:"aliyunOSS" yaml:"aliyun-oss"`
Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"`
TencentCOS TencentCOS `mapstructure:"tencent-cos" json:"tencentCOS" yaml:"tencent-cos"`
Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"`
}
+10
View File
@@ -14,10 +14,20 @@ type Qiniu struct {
UseCdnDomains bool `mapstructure:"use-cdn-domains" json:"useCdnDomains" yaml:"use-cdn-domains"`
}
type AliyunOSS struct {
Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
AccessKeyId string `mapstructure:"access-key-id" json:"accessKeyId" yaml:"access-key-id"`
AccessKeySecret string `mapstructure:"access-key-secret" json:"accessKeySecret" yaml:"access-key-secret"`
BucketName string `mapstructure:"bucket-name" json:"bucketName" yaml:"bucket-name"`
BucketUrl string `mapstructure:"bucket-url" json:"bucketUrl" yaml:"bucket-url"`
type TencentCOS struct {
Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
Region string `mapstructure:"region" json:"region" yaml:"region"`
SecretID string `mapstructure:"secret-id" json:"secretID" yaml:"secret-id"`
SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"`
BaseURL string `mapstructure:"base-url" json:"baseURL" yaml:"base-url"`
PathPrefix string `mapstructure:"path-prefix" json:"pathPrefix" yaml:"path-prefix"`
}
+3 -2
View File
@@ -36,10 +36,10 @@ require (
github.com/onsi/ginkgo v1.7.0 // indirect
github.com/onsi/gomega v1.4.3 // indirect
github.com/pelletier/go-toml v1.6.0 // indirect
github.com/pkg/errors v0.9.1
github.com/pkg/errors v0.9.1 // indirect
github.com/qiniu/api.v7/v7 v7.4.1
github.com/satori/go.uuid v1.2.0
github.com/shirou/gopsutil v2.20.8+incompatible
github.com/shirou/gopsutil v3.21.1+incompatible
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.1.1
@@ -48,6 +48,7 @@ require (
github.com/swaggo/gin-swagger v1.2.0
github.com/swaggo/swag v1.6.7
github.com/tebeka/strftime v0.1.3 // indirect
github.com/tencentyun/cos-go-sdk-v5 v0.7.19
github.com/unrolled/secure v1.0.7
go.uber.org/zap v1.10.0
golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
+1
View File
@@ -47,6 +47,7 @@ func Routers() *gin.Engine {
router.InitSysDictionaryDetailRouter(PrivateGroup) // 字典详情管理
router.InitFileUploadAndDownloadRouter(PrivateGroup) // 文件上传下载功能路由
router.InitWorkflowProcessRouter(PrivateGroup) // 工作流相关接口
router.InitExcelRouter(PrivateGroup) // 表格导入导出
}
global.GVA_LOG.Info("router register success")
return Router
+6
View File
@@ -0,0 +1,6 @@
package model
type ExcelInfo struct {
FileName string `json:"fileName"`
InfoList []SysBaseMenu `json:"infoList"`
}
@@ -1,8 +0,0 @@
package request
import "gin-vue-admin/model"
type ExcelInfo struct {
FileName string `json:"fileName"`
InfoList []model.SysBaseMenu `json:"infoList"`
}
Binary file not shown.
+16
View File
@@ -0,0 +1,16 @@
package router
import (
"gin-vue-admin/api/v1"
"github.com/gin-gonic/gin"
)
func InitExcelRouter(Router *gin.RouterGroup) {
FileUploadAndDownloadGroup := Router.Group("excel")
{
FileUploadAndDownloadGroup.POST("/importExcel", v1.ImportExcel) // 导入Excel
FileUploadAndDownloadGroup.GET("/loadExcel", v1.LoadExcel) // 加载Excel数据
FileUploadAndDownloadGroup.POST("/exportExcel", v1.ExportExcel) // 导出Excel
FileUploadAndDownloadGroup.GET("/downloadTemplate", v1.DownloadTemplate) // 下载模板文件
}
}
@@ -15,9 +15,5 @@ func InitFileUploadAndDownloadRouter(Router *gin.RouterGroup) {
FileUploadAndDownloadGroup.GET("/findFile", v1.FindFile) // 查询当前文件成功的切片
FileUploadAndDownloadGroup.POST("/breakpointContinueFinish", v1.BreakpointContinueFinish) // 查询当前文件成功的切片
FileUploadAndDownloadGroup.POST("/removeChunk", v1.RemoveChunk) // 查询当前文件成功的切片
FileUploadAndDownloadGroup.POST("/importExcel", v1.ImportExcel) // 导入Excel
FileUploadAndDownloadGroup.GET("/loadExcel", v1.LoadExcel) // 加载Excel数据
FileUploadAndDownloadGroup.POST("/exportExcel", v1.ExportExcel) // 导出Excel
FileUploadAndDownloadGroup.GET("/downloadTemplate", v1.DownloadTemplate) // 下载模板文件
}
}
+1
View File
@@ -8,6 +8,7 @@ import (
func InitAutoCodeRouter(Router *gin.RouterGroup) {
AutoCodeRouter := Router.Group("autoCode")
{
AutoCodeRouter.POST("preview", v1.PreviewTemp) // 获取自动创建代码预览
AutoCodeRouter.POST("createTemp", v1.CreateTemp) // 创建自动化代码
AutoCodeRouter.GET("getTables", v1.GetTables) // 获取对应数据库的表
AutoCodeRouter.GET("getDB", v1.GetDB) // 获取数据库
+121 -44
View File
@@ -16,6 +16,11 @@ import (
"gorm.io/gorm"
)
const (
autoPath = "autoCode/"
basePath = "resource/template"
)
type tplData struct {
template *template.Template
locationPath string
@@ -23,6 +28,71 @@ type tplData struct {
autoMoveFilePath string
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: PreviewTemp
//@description: 预览创建代码
//@param: model.AutoCodeStruct
//@return: map[string]string, error
func PreviewTemp(autoCode model.AutoCodeStruct) (map[string]string, error) {
dataList, _, needMkdir, err := getNeedList(&autoCode)
if err != nil {
return nil, err
}
// 写入文件前,先创建文件夹
if err = utils.CreateDir(needMkdir...); err != nil {
return nil, err
}
// 创建map
ret := make(map[string]string)
// 生成map
for _, value := range dataList {
ext := ""
if ext = filepath.Ext(value.autoCodePath); ext == ".txt" {
continue
}
f, err := os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_WRONLY, 0755)
if err != nil {
return nil, err
}
if err = value.template.Execute(f, autoCode); err != nil {
return nil, err
}
_ = f.Close()
f, err = os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_RDONLY, 0755)
if err != nil {
return nil, err
}
builder := strings.Builder{}
builder.WriteString("```")
if ext != "" && strings.Contains(ext, ".") {
builder.WriteString(strings.Replace(ext, ".", "", -1))
}
builder.WriteString("\n\n")
data, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
builder.Write(data)
builder.WriteString("\n\n```")
pathArr := strings.Split(value.autoCodePath, string(os.PathSeparator))
ret[pathArr[1]+"-"+pathArr[3]] = builder.String()
_ = f.Close()
}
defer func() { // 移除中间文件
if err := os.RemoveAll(autoPath); err != nil {
return
}
}()
return ret, nil
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateTemp
//@description: 创建代码
@@ -30,52 +100,10 @@ type tplData struct {
//@return: error
func CreateTemp(autoCode model.AutoCodeStruct) (err error) {
basePath := "resource/template"
// 获取 basePath 文件夹下所有tpl文件
tplFileList, err := GetAllTplFile(basePath, nil)
dataList, fileList, needMkdir, err := getNeedList(&autoCode)
if err != nil {
return err
}
dataList := make([]tplData, 0, len(tplFileList))
fileList := make([]string, 0, len(tplFileList))
needMkdir := make([]string, 0, len(tplFileList)) // 当文件夹下存在多个tpl文件时,改为map更合理
// 根据文件路径生成 tplData 结构体,待填充数据
for _, value := range tplFileList {
dataList = append(dataList, tplData{locationPath: value})
}
// 生成 *Template, 填充 template 字段
for index, value := range dataList {
dataList[index].template, err = template.ParseFiles(value.locationPath)
if err != nil {
return err
}
}
// 生成文件路径,填充 autoCodePath 字段,readme.txt.tpl不符合规则,需要特殊处理
// resource/template/web/api.js.tpl -> autoCode/web/autoCode.PackageName/api/autoCode.PackageName.js
// resource/template/readme.txt.tpl -> autoCode/readme.txt
autoPath := "autoCode/"
for index, value := range dataList {
trimBase := strings.TrimPrefix(value.locationPath, basePath+"/")
if trimBase == "readme.txt.tpl" {
dataList[index].autoCodePath = autoPath + "readme.txt"
continue
}
if lastSeparator := strings.LastIndex(trimBase, "/"); lastSeparator != -1 {
origFileName := strings.TrimSuffix(trimBase[lastSeparator+1:], ".tpl")
firstDot := strings.Index(origFileName, ".")
if firstDot != -1 {
dataList[index].autoCodePath = filepath.Join(autoPath, trimBase[:lastSeparator], autoCode.PackageName,
origFileName[:firstDot], autoCode.PackageName+origFileName[firstDot:])
}
}
if lastSeparator := strings.LastIndex(dataList[index].autoCodePath, string(os.PathSeparator)); lastSeparator != -1 {
needMkdir = append(needMkdir, dataList[index].autoCodePath[:lastSeparator])
}
}
// 写入文件前,先创建文件夹
if err = utils.CreateDir(needMkdir...); err != nil {
return err
@@ -83,7 +111,6 @@ func CreateTemp(autoCode model.AutoCodeStruct) (err error) {
// 生成文件
for _, value := range dataList {
fileList = append(fileList, value.autoCodePath)
f, err := os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_WRONLY, 0755)
if err != nil {
return err
@@ -276,3 +303,53 @@ func AutoCreateApi(a *model.AutoCodeStruct) (err error) {
})
return err
}
func getNeedList(autoCode *model.AutoCodeStruct) (dataList []tplData, fileList []string, needMkdir []string, err error) {
// 获取 basePath 文件夹下所有tpl文件
tplFileList, err := GetAllTplFile(basePath, nil)
if err != nil {
return nil, nil, nil, err
}
dataList = make([]tplData, 0, len(tplFileList))
fileList = make([]string, 0, len(tplFileList))
needMkdir = make([]string, 0, len(tplFileList)) // 当文件夹下存在多个tpl文件时,改为map更合理
// 根据文件路径生成 tplData 结构体,待填充数据
for _, value := range tplFileList {
dataList = append(dataList, tplData{locationPath: value})
}
// 生成 *Template, 填充 template 字段
for index, value := range dataList {
dataList[index].template, err = template.ParseFiles(value.locationPath)
if err != nil {
return nil, nil, nil, err
}
}
// 生成文件路径,填充 autoCodePath 字段,readme.txt.tpl不符合规则,需要特殊处理
// resource/template/web/api.js.tpl -> autoCode/web/autoCode.PackageName/api/autoCode.PackageName.js
// resource/template/readme.txt.tpl -> autoCode/readme.txt
autoPath := "autoCode/"
for index, value := range dataList {
trimBase := strings.TrimPrefix(value.locationPath, basePath+"/")
if trimBase == "readme.txt.tpl" {
dataList[index].autoCodePath = autoPath + "readme.txt"
continue
}
if lastSeparator := strings.LastIndex(trimBase, "/"); lastSeparator != -1 {
origFileName := strings.TrimSuffix(trimBase[lastSeparator+1:], ".tpl")
firstDot := strings.Index(origFileName, ".")
if firstDot != -1 {
dataList[index].autoCodePath = filepath.Join(autoPath, trimBase[:lastSeparator], autoCode.PackageName,
origFileName[:firstDot], autoCode.PackageName+origFileName[firstDot:])
}
}
if lastSeparator := strings.LastIndex(dataList[index].autoCodePath, string(os.PathSeparator)); lastSeparator != -1 {
needMkdir = append(needMkdir, dataList[index].autoCodePath[:lastSeparator])
}
}
for _, value := range dataList {
fileList = append(fileList, value.autoCodePath)
}
return dataList, fileList, needMkdir, err
}
+3 -4
View File
@@ -89,12 +89,11 @@ func getBaseChildrenList(menu *model.SysBaseMenu, treeMap map[string][]model.Sys
//@param: menu model.SysBaseMenu
//@return: err error
func AddBaseMenu(menu model.SysBaseMenu) (err error) {
func AddBaseMenu(menu model.SysBaseMenu) error {
if !errors.Is(global.GVA_DB.Where("name = ?", menu.Name).First(&model.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) {
err = errors.New("存在重复name,请修改name")
return errors.New("存在重复name,请修改name")
}
err = global.GVA_DB.Create(&menu).Error
return err
return global.GVA_DB.Create(&menu).Error
}
//@author: [piexlmax](https://github.com/piexlmax)
+60
View File
@@ -0,0 +1,60 @@
package upload
import (
"context"
"errors"
"fmt"
"gin-vue-admin/global"
"mime/multipart"
"net/http"
"net/url"
"time"
"github.com/tencentyun/cos-go-sdk-v5"
"go.uber.org/zap"
)
type TencentCOS struct{}
// UploadFile upload file to COS
func (*TencentCOS) UploadFile(file *multipart.FileHeader) (string, string, error) {
c := NewClient()
f, openError := file.Open()
if openError != nil {
global.GVA_LOG.Error("function file.Open() Filed", zap.Any("err", openError.Error()))
return "", "", errors.New("function file.Open() Filed, err:" + openError.Error())
}
fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename)
_, err := c.Object.Put(context.Background(), global.GVA_CONFIG.TencentCOS.PathPrefix+"/"+fileKey, f, nil)
if err != nil {
panic(err)
}
return global.GVA_CONFIG.TencentCOS.BaseURL + "/" + global.GVA_CONFIG.TencentCOS.PathPrefix + "/" + fileKey, fileKey, nil
}
// DeleteFile delete file form COS
func (*TencentCOS) DeleteFile(key string) error {
c := NewClient()
name := global.GVA_CONFIG.TencentCOS.PathPrefix + "/" + key
_, err := c.Object.Delete(context.Background(), name)
if err != nil {
global.GVA_LOG.Error("function bucketManager.Delete() Filed", zap.Any("err", err.Error()))
return errors.New("function bucketManager.Delete() Filed, err:" + err.Error())
}
return nil
}
// NewClient init COS client
func NewClient() *cos.Client {
u, _ := url.Parse("https://" + global.GVA_CONFIG.TencentCOS.Bucket + ".cos." + global.GVA_CONFIG.TencentCOS.Region + ".myqcloud.com")
b := &cos.BaseURL{BucketURL: u}
c := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: global.GVA_CONFIG.TencentCOS.SecretID,
SecretKey: global.GVA_CONFIG.TencentCOS.SecretKey,
},
})
return c
}
+3 -1
View File
@@ -28,7 +28,9 @@ func NewOss() OSS {
return &Local{}
case "qiniu":
return &Qiniu{}
case "tencent-cos":
return &TencentCOS{}
default:
return &Local{}
}
}
}