sys_auto_code.go 9.1 KB
Newer Older
1 2 3
package service

import (
m0_50812349's avatar
m0_50812349 已提交
4
	"errors"
m0_50812349's avatar
m0_50812349 已提交
5
	"fmt"
Mr.奇淼('s avatar
Mr.奇淼( 已提交
6
	"gin-vue-admin/global"
7
	"gin-vue-admin/model"
Mr.奇淼('s avatar
Mr.奇淼( 已提交
8
	"gin-vue-admin/model/request"
9
	"gin-vue-admin/utils"
10
	"gorm.io/gorm"
11
	"io/ioutil"
12
	"os"
m0_50812349's avatar
m0_50812349 已提交
13
	"path/filepath"
14
	"strings"
15
	"text/template"
16 17
)

18
type tplData struct {
m0_50812349's avatar
m0_50812349 已提交
19 20 21 22
	template         *template.Template
	locationPath     string
	autoCodePath     string
	autoMoveFilePath string
23 24
}

m0_50812349's avatar
m0_50812349 已提交
25 26 27 28 29
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateTemp
//@description: 创建代码
//@param: model.AutoCodeStruct
//@return: error
Mr.奇淼('s avatar
Mr.奇淼( 已提交
30

S
songzhibin97 已提交
31
func CreateTemp(autoCode *model.AutoCodeStruct) (err error) {
32 33 34
	basePath := "resource/template"
	// 获取 basePath 文件夹下所有tpl文件
	tplFileList, err := GetAllTplFile(basePath, nil)
35 36 37
	if err != nil {
		return err
	}
38 39 40 41 42 43
	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})
44
	}
45 46 47
	// 生成 *Template, 填充 template 字段
	for index, value := range dataList {
		dataList[index].template, err = template.ParseFiles(value.locationPath)
48 49 50
		if err != nil {
			return err
		}
51 52 53
	}

	// 生成文件路径,填充 autoCodePath 字段,readme.txt.tpl不符合规则,需要特殊处理
54
	// resource/template/web/api.js.tpl -> autoCode/web/autoCode.PackageName/api/autoCode.PackageName.js
55 56 57 58 59 60 61
	// 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
62
		}
63 64 65 66 67 68 69 70

		if lastSeparator := strings.LastIndex(trimBase, "/"); lastSeparator != -1 {
			origFileName := strings.TrimSuffix(trimBase[lastSeparator+1:], ".tpl")
			firstDot := strings.Index(origFileName, ".")
			if firstDot != -1 {
				dataList[index].autoCodePath = autoPath + trimBase[:lastSeparator] + "/" + autoCode.PackageName + "/" +
					origFileName[:firstDot] + "/" + autoCode.PackageName + origFileName[firstDot:]
			}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
71
		}
72 73 74

		if lastSeparator := strings.LastIndex(dataList[index].autoCodePath, "/"); lastSeparator != -1 {
			needMkdir = append(needMkdir, dataList[index].autoCodePath[:lastSeparator])
75
		}
76 77 78 79 80 81 82 83 84 85 86
	}

	// 写入文件前,先创建文件夹
	if err = utils.CreateDir(needMkdir...); err != nil {
		return err
	}

	// 生成文件
	for _, value := range dataList {
		fileList = append(fileList, value.autoCodePath)
		f, err := os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_WRONLY, 0755)
87 88 89
		if err != nil {
			return err
		}
S
songzhibin97 已提交
90
		if err = value.template.Execute(f, *autoCode); err != nil {
91 92
			return err
		}
93
		_ = f.Close()
94
	}
95

m0_50812349's avatar
m0_50812349 已提交
96
	defer func() { // 移除中间文件
V
v_zhibsong 已提交
97 98 99 100
		if err := os.RemoveAll(autoPath); err != nil {
			return
		}
	}()
m0_50812349's avatar
m0_50812349 已提交
101 102 103 104 105
	if autoCode.AutoMoveFile { // 判断是否需要自动转移
		for index, _ := range dataList {
			addAutoMoveFile(&dataList[index])
		}
		for _, value := range dataList { // 移动文件
m0_50812349's avatar
m0_50812349 已提交
106
			if err := utils.FileMove(value.autoCodePath, value.autoMoveFilePath); err != nil {
m0_50812349's avatar
m0_50812349 已提交
107
				fmt.Println(err)
V
v_zhibsong 已提交
108 109 110
				return err
			}
		}
m0_50812349's avatar
m0_50812349 已提交
111
		return errors.New("创建代码成功并移动文件成功")
m0_50812349's avatar
m0_50812349 已提交
112
	} else { // 打包
V
v_zhibsong 已提交
113 114 115
		if err := utils.ZipFiles("./ginvueadmin.zip", fileList, ".", "."); err != nil {
			return err
		}
116 117 118
	}
	return nil
}
119

m0_50812349's avatar
m0_50812349 已提交
120 121 122 123 124 125
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetAllTplFile
//@description: 获取 pathName 文件夹下所有 tpl 文件
//@param: pathName string, fileList []string
//@return: []string, error

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
func GetAllTplFile(pathName string, fileList []string) ([]string, error) {
	files, err := ioutil.ReadDir(pathName)
	for _, fi := range files {
		if fi.IsDir() {
			fileList, err = GetAllTplFile(pathName+"/"+fi.Name(), fileList)
			if err != nil {
				return nil, err
			}
		} else {
			if strings.HasSuffix(fi.Name(), ".tpl") {
				fileList = append(fileList, pathName+"/"+fi.Name())
			}
		}
	}
	return fileList, err
}
Mr.奇淼('s avatar
Mr.奇淼( 已提交
142

m0_50812349's avatar
m0_50812349 已提交
143 144 145 146 147 148 149
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetTables
//@description: 获取数据库的所有表名
//@param: pathName string
//@param: fileList []string
//@return: []string, error

Mr.奇淼('s avatar
Mr.奇淼( 已提交
150
func GetTables(dbName string) (err error, TableNames []request.TableReq) {
151
	err = global.GVA_DB.Raw("select table_name as table_name from information_schema.tables where table_schema = ?", dbName).Scan(&TableNames).Error
Mr.奇淼('s avatar
Mr.奇淼( 已提交
152 153 154
	return err, TableNames
}

m0_50812349's avatar
m0_50812349 已提交
155 156 157 158 159 160 161
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetDB
//@description: 获取数据库的所有数据库名
//@param: pathName string
//@param: fileList []string
//@return: []string, error

Mr.奇淼('s avatar
Mr.奇淼( 已提交
162 163 164 165 166
func GetDB() (err error, DBNames []request.DBReq) {
	err = global.GVA_DB.Raw("SELECT SCHEMA_NAME AS `database` FROM INFORMATION_SCHEMA.SCHEMATA;").Scan(&DBNames).Error
	return err, DBNames
}

m0_50812349's avatar
m0_50812349 已提交
167 168 169 170 171 172 173
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetDB
//@description: 获取指定数据库和指定数据表的所有字段名,类型值等
//@param: pathName string
//@param: fileList []string
//@return: []string, error

174
func GetColumn(tableName string, dbName string) (err error, Columns []request.ColumnReq) {
175
	err = global.GVA_DB.Raw("SELECT COLUMN_NAME column_name,DATA_TYPE data_type,CASE DATA_TYPE WHEN 'longtext' THEN c.CHARACTER_MAXIMUM_LENGTH WHEN 'varchar' THEN c.CHARACTER_MAXIMUM_LENGTH WHEN 'double' THEN CONCAT_WS( ',', c.NUMERIC_PRECISION, c.NUMERIC_SCALE ) WHEN 'decimal' THEN CONCAT_WS( ',', c.NUMERIC_PRECISION, c.NUMERIC_SCALE ) WHEN 'int' THEN c.NUMERIC_PRECISION WHEN 'bigint' THEN c.NUMERIC_PRECISION ELSE '' END AS data_type_long,COLUMN_COMMENT column_comment FROM INFORMATION_SCHEMA.COLUMNS c WHERE table_name = ? AND table_schema = ?", tableName, dbName).Scan(&Columns).Error
176
	return err, Columns
Mr.奇淼('s avatar
Mr.奇淼( 已提交
177
}
m0_50812349's avatar
m0_50812349 已提交
178

m0_50812349's avatar
m0_50812349 已提交
179 180 181 182 183 184
//@author: [SliverHorn](https://github.com/SliverHorn)
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: addAutoMoveFile
//@description: 生成对应的迁移文件路径
//@param: *tplData
//@return: null
S
songzhibin97 已提交
185

m0_50812349's avatar
m0_50812349 已提交
186
func addAutoMoveFile(data *tplData) {
S
change2  
songzhibin97 已提交
187
	dir := filepath.Base(filepath.Dir(data.autoCodePath))
S
songzhibin97 已提交
188
	base := filepath.Base(data.autoCodePath)
m0_50812349's avatar
m0_50812349 已提交
189 190
	if strings.Contains(data.autoCodePath, "server") {
		if strings.Contains(data.autoCodePath, "router") {
S
songzhibin97 已提交
191
			data.autoMoveFilePath = filepath.Join(dir, base)
m0_50812349's avatar
m0_50812349 已提交
192
		} else if strings.Contains(data.autoCodePath, "api") {
S
songzhibin97 已提交
193
			data.autoMoveFilePath = filepath.Join(dir, "v1", base)
m0_50812349's avatar
m0_50812349 已提交
194
		} else if strings.Contains(data.autoCodePath, "service") {
S
songzhibin97 已提交
195
			data.autoMoveFilePath = filepath.Join(dir, base)
m0_50812349's avatar
m0_50812349 已提交
196
		} else if strings.Contains(data.autoCodePath, "model") {
S
songzhibin97 已提交
197
			data.autoMoveFilePath = filepath.Join(dir, base)
m0_50812349's avatar
m0_50812349 已提交
198
		} else if strings.Contains(data.autoCodePath, "request") {
S
songzhibin97 已提交
199
			data.autoMoveFilePath = filepath.Join("model", dir, base)
m0_50812349's avatar
m0_50812349 已提交
200 201 202
		}
	} else if strings.Contains(data.autoCodePath, "web") {
		if strings.Contains(data.autoCodePath, "js") {
S
songzhibin97 已提交
203
			data.autoMoveFilePath = filepath.Join("../", "web", "src", dir, base)
m0_50812349's avatar
m0_50812349 已提交
204
		} else if strings.Contains(data.autoCodePath, "form") {
m0_50812349's avatar
m0_50812349 已提交
205
			data.autoMoveFilePath = filepath.Join("../", "web", "src", "view", filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), strings.TrimSuffix(base, filepath.Ext(base))+"Form.vue")
m0_50812349's avatar
m0_50812349 已提交
206
		} else if strings.Contains(data.autoCodePath, "table") {
S
re  
songzhibin97 已提交
207
			data.autoMoveFilePath = filepath.Join("../", "web", "src", "view", filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), base)
m0_50812349's avatar
m0_50812349 已提交
208 209 210
		}
	}
}
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

//@author: [piexlmax](https://github.com/piexlmax)
//@author: [SliverHorn](https://github.com/SliverHorn)
//@function: CreateApi
//@description: 自动创建api数据,
//@param: a *model.AutoCodeStruct
//@return: error

func AutoCreateApi(a *model.AutoCodeStruct) (err error) {
	var apiList = []model.SysApi{
		{
			Path:        "/" + a.Abbreviation + "/" + "create" + a.StructName,
			Description: "新增" + a.Description,
			ApiGroup:    a.Abbreviation,
			Method:      "POST",
		},
		{
			Path:        "/" + a.Abbreviation + "/" + "delete" + a.StructName,
			Description: "删除" + a.Description,
			ApiGroup:    a.Abbreviation,
			Method:      "DELETE",
		},
		{
			Path:        "/" + a.Abbreviation + "/" + "delete" + a.StructName + "ByIds",
			Description: "批量删除" + a.Description,
			ApiGroup:    a.Abbreviation,
			Method:      "DELETE",
		},
		{
			Path:        "/" + a.Abbreviation + "/" + "update" + a.StructName,
			Description: "更新" + a.Description,
			ApiGroup:    a.Abbreviation,
			Method:      "PUT",
		},
		{
			Path:        "/" + a.Abbreviation + "/" + "find" + a.StructName,
			Description: "根据ID获取" + a.Description,
			ApiGroup:    a.Abbreviation,
			Method:      "GET",
		},
		{
			Path:        "/" + a.Abbreviation + "/" + "get" + a.StructName + "List",
			Description: "获取" + a.Description + "列表",
			ApiGroup:    a.Abbreviation,
			Method:      "GET",
		},
	}
	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
		for _, v := range apiList {
			var api model.SysApi
			if err := tx.Where("path = ? AND method = ?", v.Path, v.Method).First(&api).Error; err != nil {
				return err
			}
			if err := tx.Create(&v).Error; err != nil { // 遇到错误时回滚事务
				return err
			}
		}
		return nil
	})
	return err
S
songzhibin97 已提交
271
}