Просмотр исходного кода

Merge pull request #532 from flipped-aurora/gva_gormv2_dev

Gva gormv2 dev
奇淼(piexlmax 3 лет назад
Родитель
Сommit
09fe9f3cff

+ 4 - 3
server/api/v1/sys_initdb.go

@@ -5,6 +5,7 @@ import (
 	"gin-vue-admin/model/request"
 	"gin-vue-admin/model/response"
 	"gin-vue-admin/service"
+
 	"go.uber.org/zap"
 
 	"github.com/gin-gonic/gin"
@@ -18,8 +19,8 @@ import (
 // @Router /init/initdb [post]
 func InitDB(c *gin.Context) {
 	if global.GVA_DB != nil {
-		global.GVA_LOG.Error("非法访问!")
-		response.FailWithMessage("非法访问", c)
+		global.GVA_LOG.Error("已存在数据库配置!")
+		response.FailWithMessage("已存在数据库配置", c)
 		return
 	}
 	var dbInfo request.InitDB
@@ -30,7 +31,7 @@ func InitDB(c *gin.Context) {
 	}
 	if err := service.InitDB(dbInfo); err != nil {
 		global.GVA_LOG.Error("自动创建数据库失败!", zap.Any("err", err))
-		response.FailWithMessage("自动创建数据库失败,请查看后台日志", c)
+		response.FailWithMessage("自动创建数据库失败,请查看后台日志,检查后在进行初始化", c)
 		return
 	}
 	response.OkWithData("自动创建数据库成功", c)

+ 12 - 12
server/api/v1/sys_user.go

@@ -23,15 +23,15 @@ import (
 // @Success 200 {string} string "{"success":true,"data":{},"msg":"登陆成功"}"
 // @Router /base/login [post]
 func Login(c *gin.Context) {
-	var L request.Login
-	_ = c.ShouldBindJSON(&L)
-	if err := utils.Verify(L, utils.LoginVerify); err != nil {
+	var l request.Login
+	_ = c.ShouldBindJSON(&l)
+	if err := utils.Verify(l, utils.LoginVerify); err != nil {
 		response.FailWithMessage(err.Error(), c)
 		return
 	}
-	if store.Verify(L.CaptchaId, L.Captcha, true) {
-		U := &model.SysUser{Username: L.Username, Password: L.Password}
-		if err, user := service.Login(U); err != nil {
+	if store.Verify(l.CaptchaId, l.Captcha, true) {
+		u := &model.SysUser{Username: l.Username, Password: l.Password}
+		if err, user := service.Login(u); err != nil {
 			global.GVA_LOG.Error("登陆失败! 用户名不存在或者密码错误!", zap.Any("err", err))
 			response.FailWithMessage("用户名不存在或者密码错误", c)
 		} else {
@@ -112,13 +112,13 @@ func tokenNext(c *gin.Context, user model.SysUser) {
 // @Success 200 {string} string "{"success":true,"data":{},"msg":"注册成功"}"
 // @Router /user/register [post]
 func Register(c *gin.Context) {
-	var R request.Register
-	_ = c.ShouldBindJSON(&R)
-	if err := utils.Verify(R, utils.RegisterVerify); err != nil {
+	var r request.Register
+	_ = c.ShouldBindJSON(&r)
+	if err := utils.Verify(r, utils.RegisterVerify); err != nil {
 		response.FailWithMessage(err.Error(), c)
 		return
 	}
-	user := &model.SysUser{Username: R.Username, NickName: R.NickName, Password: R.Password, HeaderImg: R.HeaderImg, AuthorityId: R.AuthorityId}
+	user := &model.SysUser{Username: r.Username, NickName: r.NickName, Password: r.Password, HeaderImg: r.HeaderImg, AuthorityId: r.AuthorityId}
 	err, userReturn := service.Register(*user)
 	if err != nil {
 		global.GVA_LOG.Error("注册失败!", zap.Any("err", err))
@@ -142,8 +142,8 @@ func ChangePassword(c *gin.Context) {
 		response.FailWithMessage(err.Error(), c)
 		return
 	}
-	U := &model.SysUser{Username: user.Username, Password: user.Password}
-	if err, _ := service.ChangePassword(U, user.NewPassword); err != nil {
+	u := &model.SysUser{Username: user.Username, Password: user.Password}
+	if err, _ := service.ChangePassword(u, user.NewPassword); err != nil {
 		global.GVA_LOG.Error("修改失败!", zap.Any("err", err))
 		response.FailWithMessage("修改失败,原密码与当前账户不符", c)
 	} else {

+ 1 - 0
server/config.yaml

@@ -53,6 +53,7 @@ captcha:
   img-height: 80
 
 # mysql connect configuration
+# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://www.gin-vue-admin.com/docs/first)
 mysql:
   path: ''
   config: ''

+ 1 - 0
server/model/sys_auto_code.go

@@ -7,6 +7,7 @@ type AutoCodeStruct struct {
 	StructName         string   `json:"structName"`         // Struct名称
 	TableName          string   `json:"tableName"`          // 表名
 	PackageName        string   `json:"packageName"`        // 文件名称
+	HumpPackageName    string   `json:"humpPackageName"`        // go文件名称
 	Abbreviation       string   `json:"abbreviation"`       // Struct简称
 	Description        string   `json:"description"`        // Struct中文名称
 	AutoCreateApiToSql bool     `json:"autoCreateApiToSql"` // 是否自动创建api

+ 1 - 2
server/router/sys_base.go

@@ -2,12 +2,11 @@ package router
 
 import (
 	"gin-vue-admin/api/v1"
-	"gin-vue-admin/middleware"
 	"github.com/gin-gonic/gin"
 )
 
 func InitBaseRouter(Router *gin.RouterGroup) (R gin.IRoutes) {
-	BaseRouter := Router.Group("base").Use(middleware.NeedInit())
+	BaseRouter := Router.Group("base")
 	{
 		BaseRouter.POST("login", v1.Login)
 		BaseRouter.POST("captcha", v1.Captcha)

+ 2 - 2
server/service/exa_excel_parse.go

@@ -24,8 +24,8 @@ func ParseInfoList2Excel(infoList []model.SysBaseMenu, filePath string) error {
 			menu.Component,
 		})
 	}
-	excel.SaveAs(filePath)
-	return nil
+	err := excel.SaveAs(filePath)
+	return err
 }
 
 func ParseExcel2InfoList() ([]model.SysBaseMenu, error) {

+ 2 - 1
server/service/jwt_black_list.go

@@ -26,7 +26,8 @@ func JsonInBlacklist(jwtList model.JwtBlacklist) (err error) {
 //@return: bool
 
 func IsBlacklist(jwt string) bool {
-	isNotFound := errors.Is(global.GVA_DB.Where("jwt = ?", jwt).First(&model.JwtBlacklist{}).Error, gorm.ErrRecordNotFound)
+	err := global.GVA_DB.Where("jwt = ?", jwt).First(&model.JwtBlacklist{}).Error
+	isNotFound := errors.Is(err, gorm.ErrRecordNotFound)
 	return !isNotFound
 }
 

+ 8 - 1
server/service/sys_auto_code.go

@@ -360,8 +360,15 @@ func getNeedList(autoCode *model.AutoCodeStruct) (dataList []tplData, fileList [
 			origFileName := strings.TrimSuffix(trimBase[lastSeparator+1:], ".tpl")
 			firstDot := strings.Index(origFileName, ".")
 			if firstDot != -1 {
+				var fileName string
+				if origFileName[firstDot:] !=".go"{
+					fileName = autoCode.PackageName+origFileName[firstDot:]
+				}else{
+					fileName = autoCode.HumpPackageName+origFileName[firstDot:]
+				}
+
 				dataList[index].autoCodePath = filepath.Join(autoPath, trimBase[:lastSeparator], autoCode.PackageName,
-					origFileName[:firstDot], autoCode.PackageName+origFileName[firstDot:])
+					origFileName[:firstDot], fileName)
 			}
 		}
 

+ 11 - 22
server/service/sys_initdb.go

@@ -9,10 +9,11 @@ import (
 	"gin-vue-admin/model/request"
 	"gin-vue-admin/source"
 	"gin-vue-admin/utils"
+	"path/filepath"
+
 	"github.com/spf13/viper"
 	"gorm.io/driver/mysql"
 	"gorm.io/gorm"
-	"path/filepath"
 )
 
 //@author: [songzhibin97](https://github.com/songzhibin97)
@@ -71,13 +72,6 @@ func initDB(InitDBFunctions ...model.InitDBFunc) (err error) {
 //@return: error
 
 func InitDB(conf request.InitDB) error {
-	BaseMysql := config.Mysql{
-		Path:     "",
-		Dbname:   "",
-		Username: "",
-		Password: "",
-		Config:   "charset=utf8mb4&parseTime=True&loc=Local",
-	}
 
 	if conf.Host == "" {
 		conf.Host = "127.0.0.1"
@@ -100,15 +94,11 @@ func InitDB(conf request.InitDB) error {
 		Config:   "charset=utf8mb4&parseTime=True&loc=Local",
 	}
 
-	if err := writeConfig(global.GVA_VP, MysqlConfig); err != nil {
-		return err
-	}
-	m := global.GVA_CONFIG.Mysql
-	if m.Dbname == "" {
+	if MysqlConfig.Dbname == "" {
 		return nil
 	}
 
-	linkDns := m.Username + ":" + m.Password + "@tcp(" + m.Path + ")/" + m.Dbname + "?" + m.Config
+	linkDns := MysqlConfig.Username + ":" + MysqlConfig.Password + "@tcp(" + MysqlConfig.Path + ")/" + MysqlConfig.Dbname + "?" + MysqlConfig.Config
 	mysqlConfig := mysql.Config{
 		DSN:                       linkDns, // DSN data source name
 		DefaultStringSize:         191,     // string 类型字段的默认长度
@@ -118,15 +108,11 @@ func InitDB(conf request.InitDB) error {
 		SkipInitializeWithVersion: false,   // 根据版本自动配置
 	}
 	if db, err := gorm.Open(mysql.New(mysqlConfig), &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}); err != nil {
-		//global.GVA_LOG.Error("MySQL启动异常!", zap.Any("err", err))
-		//os.Exit(0)
-		//return nil
-		_ = writeConfig(global.GVA_VP, BaseMysql)
 		return nil
 	} else {
 		sqlDB, _ := db.DB()
-		sqlDB.SetMaxIdleConns(m.MaxIdleConns)
-		sqlDB.SetMaxOpenConns(m.MaxOpenConns)
+		sqlDB.SetMaxIdleConns(MysqlConfig.MaxIdleConns)
+		sqlDB.SetMaxOpenConns(MysqlConfig.MaxOpenConns)
 		global.GVA_DB = db
 	}
 
@@ -147,7 +133,7 @@ func InitDB(conf request.InitDB) error {
 		model.SysOperationRecord{},
 	)
 	if err != nil {
-		_ = writeConfig(global.GVA_VP, BaseMysql)
+		global.GVA_DB = nil
 		return err
 	}
 	err = initDB(
@@ -163,7 +149,10 @@ func InitDB(conf request.InitDB) error {
 		source.File,
 		source.BaseMenu)
 	if err != nil {
-		_ = writeConfig(global.GVA_VP, BaseMysql)
+		global.GVA_DB = nil
+		return err
+	}
+	if err = writeConfig(global.GVA_VP, MysqlConfig); err != nil {
 		return err
 	}
 	global.GVA_CONFIG.AutoCode.Root, _ = filepath.Abs("..")

+ 1 - 1
server/utils/upload/aliyun_oss.go

@@ -25,7 +25,7 @@ func (*AliyunOSS) UploadFile(file *multipart.FileHeader) (string, string, error)
 		global.GVA_LOG.Error("function file.Open() Failed", zap.Any("err", openError.Error()))
 		return "", "", errors.New("function file.Open() Failed, err:" + openError.Error())
 	}
-
+	defer f.Close() // 创建文件 defer 关闭
 	// 上传阿里云路径 文件名格式 自己可以改 建议保证唯一性
 	yunFileTmpPath := filepath.Join("uploads", time.Now().Format("2006-01-02")) + "/" + file.Filename
 

+ 1 - 0
server/utils/upload/qiniu.go

@@ -38,6 +38,7 @@ func (*Qiniu) UploadFile(file *multipart.FileHeader) (string, string, error) {
 
 		return "", "", errors.New("function file.Open() Filed, err:" + openError.Error())
 	}
+	defer f.Close() // 创建文件 defer 关闭
 	fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename) // 文件名格式 自己可以改 建议保证唯一性
 	putErr := formUploader.Put(context.Background(), &ret, upToken, fileKey, f, file.Size, &putExtra)
 	if putErr != nil {

+ 1 - 0
server/utils/upload/tencent_cos.go

@@ -24,6 +24,7 @@ func (*TencentCOS) UploadFile(file *multipart.FileHeader) (string, string, error
 		global.GVA_LOG.Error("function file.Open() Filed", zap.Any("err", openError.Error()))
 		return "", "", errors.New("function file.Open() Filed, err:" + openError.Error())
 	}
+	defer f.Close() // 创建文件 defer 关闭
 	fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename)
 
 	_, err := client.Object.Put(context.Background(), global.GVA_CONFIG.TencentCOS.PathPrefix+"/"+fileKey, f, nil)

+ 1 - 5
web/src/App.vue

@@ -5,12 +5,8 @@
 </template>
 
 <script>
-import { checkDB } from '@/api/initdb'
 export default {
-  name: 'App',
-  async created() {
-    await checkDB()
-  }
+  name: 'App'
 }
 </script>
 

+ 8 - 15
web/src/utils/request.js

@@ -2,7 +2,7 @@ import axios from 'axios' // 引入axios
 import { Message } from 'element-ui'
 import { store } from '@/store'
 import context from '@/main'
-import router from '@/router/index'
+import { MessageBox } from 'element-ui'
 
 const service = axios.create({
   baseURL: process.env.VUE_APP_BASE_API,
@@ -64,16 +64,6 @@ service.interceptors.response.use(
     if (response.headers['new-token']) {
       store.commit('user/setToken', response.headers['new-token'])
     }
-    if (response.data.code === 0) {
-      if (response.data.data?.needInit) {
-        Message({
-          type: 'info',
-          message: '您是第一次使用,请初始化'
-        })
-        store.commit('user/NeedInit')
-        router.push({ name: 'Init' })
-      }
-    }
     if (response.data.code === 0 || response.headers.success === 'true') {
       return response.data
     } else {
@@ -90,11 +80,14 @@ service.interceptors.response.use(
   },
   error => {
     closeLoading()
-    Message({
-      showClose: true,
-      message: error,
-      type: 'error'
+    MessageBox.confirm(`检测到接口错误${error},此类错误内容常见于后台panic,如果影响您正常使用可强制登出清理缓存`, '接口报错', {
+      distinguishCancelAndClose: true,
+      confirmButtonText: '清理缓存',
+      cancelButtonText: '取消'
     })
+      .then(() => {
+        store.commit('user/LoginOut')
+      })
     return error
   }
 )

+ 19 - 3
web/src/view/init/index.vue

@@ -1,11 +1,21 @@
 <template>
   <div class="init_page">
     <div class="init_page_panle">
-      <div v-if="hello < 2" id="hello" :class="[hello < 1 ? 'slide-in-fwd-top' : 'slide-out-right']" class="hello  " @click="showNext">
+      <div v-if="hello < 2" id="hello" :class="[hello < 1 ? 'slide-in-fwd-top' : 'slide-out-right']" class="hello  ">
         <div>
           <div class="hello_title">GIN-VUE-ADMIN</div>
-          <p class="in-two a-fadeinT">您需要初始化您的数据库并且填充初始数据</p>
-          <p class="init_p">点击进入初始化</p>
+          <p class="in-two a-fadeinT">初始化须知</p>
+          <p class="init_p">1.您需有用一定的VUE和golang基础</p>
+          <p class="init_p">2.请您确认是否已经阅读过官方文档</p>
+          <p class="init_p">3.请您确认是否了解后续的配置流程</p>
+          <p class="init_btn">
+            <el-button type="primary" @click="goDoc">
+              阅读文档
+            </el-button>
+            <el-button type="primary" @click="showNext">
+              我已确认
+            </el-button>
+          </p>
         </div>
       </div>
       <div v-if="hello > 0 " :class="[(hello > 0 && !out)? 'slide-in-left' : '' , out ? 'slide-out-right' : '']" class=" form">
@@ -73,6 +83,9 @@ export default {
       this.hello = this.hello + 1
       console.log(this.hello)
     },
+    goDoc() {
+      window.open('https://www.gin-vue-admin.com')
+    },
     async onSubmit() {
       const loading = this.$loading({
         lock: true,
@@ -141,6 +154,9 @@ export default {
         margin-top: 20px;
         color: #777777;
       }
+      .init_btn{
+        margin-top: 20px;
+      }
     }
     .form{
       position: absolute;

+ 1 - 1
web/src/view/layout/bottomInfo/bottomInfo.vue

@@ -3,7 +3,7 @@
     <div>
       <span>Powered by</span>
       <span>
-        <a href="https://github.com/flipped-aurora/gin-vue-admin">{{$GIN_VUE_ADMIN.appName}}</a>
+        <a href="https://github.com/flipped-aurora/gin-vue-admin">{{ $GIN_VUE_ADMIN.appName }}</a>
       </span>
       <el-divider direction="vertical" />
       <span>Copyright</span>

+ 23 - 2
web/src/view/login/index.vue

@@ -3,7 +3,7 @@
     <div class="login_panle">
       <div class="login_panle_form">
         <div class="login_panle_form_title">
-          <img class="login_panle_form_title_logo" :src="$GIN_VUE_ADMIN.appLogo" alt=""><p class="login_panle_form_title_p">{{$GIN_VUE_ADMIN.appName}}</p>
+          <img class="login_panle_form_title_logo" :src="$GIN_VUE_ADMIN.appLogo" alt=""><p class="login_panle_form_title_p">{{ $GIN_VUE_ADMIN.appName }}</p>
         </div>
         <el-form
           ref="loginForm"
@@ -47,10 +47,16 @@
               >
             </div>
           </el-form-item>
+          <div />
           <el-form-item>
             <el-button
               type="primary"
-              style="width: 100%"
+              style="width: 46%"
+              @click="checkInit"
+            >前往初始化</el-button>
+            <el-button
+              type="primary"
+              style="width: 46%;margin-left:8%"
               @click="submitForm"
             >登 录</el-button>
           </el-form-item>
@@ -73,6 +79,7 @@
 <script>
 import { mapActions } from 'vuex'
 import { captcha } from '@/api/user'
+import { checkDB } from '@/api/initdb'
 export default {
   name: 'Login',
   data() {
@@ -113,6 +120,20 @@ export default {
   },
   methods: {
     ...mapActions('user', ['LoginIn']),
+    async checkInit() {
+      const res = await checkDB()
+      if (res.code === 0) {
+        if (res.data?.needInit) {
+          this.$store.commit('user/NeedInit')
+          this.$router.push({ name: 'Init' })
+        } else {
+          this.$message({
+            type: 'info',
+            message: '已配置数据库信息,无法初始化'
+          })
+        }
+      }
+    },
     async login() {
       return await this.LoginIn(this.loginForm)
     },

+ 0 - 157
web/src/view/login/login.vue

@@ -1,157 +0,0 @@
-<template>
-  <div id="userLayout" class="user-layout-wrapper">
-    <div class="container">
-      <div class="top">
-        <div class="desc">
-          <img class="logo_login" src="@/assets/logo_login.png" alt="">
-        </div>
-        <div class="header">
-          <a href="/"><span class="title">Gin-Vue-Admin</span></a>
-        </div>
-      </div>
-      <div class="main">
-        <el-form
-          ref="loginForm"
-          :model="loginForm"
-          :rules="rules"
-          @keyup.enter.native="submitForm"
-        >
-          <el-form-item prop="username">
-            <el-input v-model="loginForm.username" placeholder="请输入用户名">
-              <i slot="suffix" class="el-input__icon el-icon-user" />
-            </el-input>
-          </el-form-item>
-          <el-form-item prop="password">
-            <el-input
-              v-model="loginForm.password"
-              :type="lock === 'lock' ? 'password' : 'text'"
-              placeholder="请输入密码"
-            >
-              <i
-                slot="suffix"
-                :class="'el-input__icon el-icon-' + lock"
-                @click="changeLock"
-              />
-            </el-input>
-          </el-form-item>
-          <el-form-item style="position: relative">
-            <el-input
-              v-model="loginForm.captcha"
-              name="logVerify"
-              placeholder="请输入验证码"
-              style="width: 60%"
-            />
-            <div class="vPic">
-              <img
-                v-if="picPath"
-                :src="picPath"
-                width="100%"
-                height="100%"
-                alt="请输入验证码"
-                @click="loginVerify()"
-              >
-            </div>
-          </el-form-item>
-          <el-form-item>
-            <el-button
-              type="primary"
-              style="width: 100%"
-              @click="submitForm"
-            >登 录</el-button>
-          </el-form-item>
-        </el-form>
-      </div>
-
-      <div class="footer">
-        <div class="links">
-          <a href="http://doc.henrongyi.top/"><img src="@/assets/docs.png" class="link-icon"></a>
-          <a href="https://www.yuque.com/flipped-aurora/"><img src="@/assets/yuque.png" class="link-icon"></a>
-          <a href="https://github.com/flipped-aurora/gin-vue-admin"><img src="@/assets/github.png" class="link-icon"></a>
-          <a href="https://space.bilibili.com/322210472"><img src="@/assets/video.png" class="link-icon"></a>
-        </div>
-        <div class="copyright">Copyright &copy; {{ curYear }} 💖flipped-aurora</div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-import { mapActions } from 'vuex'
-import { captcha } from '@/api/user'
-export default {
-  name: 'Login',
-  data() {
-    const checkUsername = (rule, value, callback) => {
-      if (value.length < 5) {
-        return callback(new Error('请输入正确的用户名'))
-      } else {
-        callback()
-      }
-    }
-    const checkPassword = (rule, value, callback) => {
-      if (value.length < 6) {
-        return callback(new Error('请输入正确的密码'))
-      } else {
-        callback()
-      }
-    }
-    return {
-      curYear: 0,
-      lock: 'lock',
-      loginForm: {
-        username: 'admin',
-        password: '123456',
-        captcha: '',
-        captchaId: ''
-      },
-      rules: {
-        username: [{ validator: checkUsername, trigger: 'blur' }],
-        password: [{ validator: checkPassword, trigger: 'blur' }]
-      },
-      logVerify: '',
-      picPath: ''
-    }
-  },
-  created() {
-    this.loginVerify()
-    this.curYear = new Date().getFullYear()
-  },
-  methods: {
-    ...mapActions('user', ['LoginIn']),
-    async login() {
-      return await this.LoginIn(this.loginForm)
-    },
-    async submitForm() {
-      this.$refs.loginForm.validate(async(v) => {
-        if (v) {
-          const flag = await this.login()
-          if (!flag) {
-            this.loginVerify()
-          }
-        } else {
-          this.$message({
-            type: 'error',
-            message: '请正确填写登录信息',
-            showClose: true
-          })
-          this.loginVerify()
-          return false
-        }
-      })
-    },
-    changeLock() {
-      this.lock = this.lock === 'lock' ? 'unlock' : 'lock'
-    },
-    loginVerify() {
-      captcha({}).then((ele) => {
-        this.picPath = ele.data.picPath
-        this.loginForm.captchaId = ele.data.captchaId
-      })
-    }
-  }
-}
-</script>
-
-<style scoped lang="scss">
-@import "@/style/login.scss";
-</style>

+ 3 - 1
web/src/view/systemTools/autoCode/index.vue

@@ -154,7 +154,7 @@ const fieldTemplate = {
 
 import FieldDialog from '@/view/systemTools/autoCode/component/fieldDialog.vue'
 import PreviewCodeDialg from '@/view/systemTools/autoCode/component/previewCodeDialg.vue'
-import { toUpperCase, toHump } from '@/utils/stringFun'
+import { toUpperCase, toHump, toSQLLine } from '@/utils/stringFun'
 import { createTemp, getDB, getTable, getColumn, preview } from '@/api/autoCode'
 import { getDict } from '@/utils/dictionary'
 
@@ -294,6 +294,8 @@ export default {
             })
             return false
           }
+          this.form.humpPackageName = toSQLLine(this.form.packageName)
+          debugger
           if (isPreview) {
             const data = await preview(this.form)
             this.preViewCode = data.data.autoCode